@intentius/chant-lexicon-helm 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/integrity.json +36 -0
- package/dist/manifest.json +37 -0
- package/dist/meta.json +208 -0
- package/dist/rules/chart-metadata.ts +64 -0
- package/dist/rules/helm-helpers.ts +64 -0
- package/dist/rules/no-hardcoded-image.ts +62 -0
- package/dist/rules/values-no-secrets.ts +82 -0
- package/dist/rules/whm101.ts +46 -0
- package/dist/rules/whm102.ts +33 -0
- package/dist/rules/whm103.ts +59 -0
- package/dist/rules/whm104.ts +35 -0
- package/dist/rules/whm105.ts +30 -0
- package/dist/rules/whm201.ts +36 -0
- package/dist/rules/whm202.ts +50 -0
- package/dist/rules/whm203.ts +39 -0
- package/dist/rules/whm204.ts +60 -0
- package/dist/rules/whm301.ts +41 -0
- package/dist/rules/whm302.ts +40 -0
- package/dist/rules/whm401.ts +57 -0
- package/dist/rules/whm402.ts +45 -0
- package/dist/rules/whm403.ts +45 -0
- package/dist/rules/whm404.ts +36 -0
- package/dist/rules/whm405.ts +53 -0
- package/dist/rules/whm406.ts +34 -0
- package/dist/rules/whm407.ts +83 -0
- package/dist/rules/whm501.ts +103 -0
- package/dist/rules/whm502.ts +94 -0
- package/dist/skills/chant-helm-chart-patterns.md +229 -0
- package/dist/skills/chant-helm-chart-security-patterns.md +192 -0
- package/dist/skills/chant-helm-create-chart.md +211 -0
- package/dist/types/index.d.ts +132 -0
- package/package.json +34 -0
- package/src/codegen/docs-cli.ts +4 -0
- package/src/codegen/docs.ts +483 -0
- package/src/codegen/generate-cli.ts +28 -0
- package/src/codegen/generate.ts +249 -0
- package/src/codegen/naming.ts +38 -0
- package/src/codegen/package.ts +64 -0
- package/src/composites/composites.test.ts +1050 -0
- package/src/composites/helm-batch-job.ts +209 -0
- package/src/composites/helm-crd-lifecycle.ts +184 -0
- package/src/composites/helm-cron-job.ts +177 -0
- package/src/composites/helm-daemon-set.ts +169 -0
- package/src/composites/helm-external-secret.ts +93 -0
- package/src/composites/helm-library.ts +51 -0
- package/src/composites/helm-microservice.ts +331 -0
- package/src/composites/helm-monitored-service.ts +252 -0
- package/src/composites/helm-namespace-env.ts +154 -0
- package/src/composites/helm-secure-ingress.ts +114 -0
- package/src/composites/helm-stateful-service.ts +213 -0
- package/src/composites/helm-web-app.ts +264 -0
- package/src/composites/helm-worker.ts +207 -0
- package/src/composites/index.ts +38 -0
- package/src/coverage.test.ts +21 -0
- package/src/coverage.ts +50 -0
- package/src/generated/index.d.ts +132 -0
- package/src/generated/index.ts +13 -0
- package/src/generated/lexicon-helm.json +208 -0
- package/src/helpers.test.ts +51 -0
- package/src/helpers.ts +100 -0
- package/src/import/generator.ts +285 -0
- package/src/import/import.test.ts +224 -0
- package/src/import/parser.ts +160 -0
- package/src/import/template-stripper.ts +123 -0
- package/src/index.ts +108 -0
- package/src/intrinsics.test.ts +380 -0
- package/src/intrinsics.ts +484 -0
- package/src/lint/post-synth/helm-helpers.ts +64 -0
- package/src/lint/post-synth/post-synth.test.ts +504 -0
- package/src/lint/post-synth/whm101.ts +46 -0
- package/src/lint/post-synth/whm102.ts +33 -0
- package/src/lint/post-synth/whm103.ts +59 -0
- package/src/lint/post-synth/whm104.ts +35 -0
- package/src/lint/post-synth/whm105.ts +30 -0
- package/src/lint/post-synth/whm201.ts +36 -0
- package/src/lint/post-synth/whm202.ts +50 -0
- package/src/lint/post-synth/whm203.ts +39 -0
- package/src/lint/post-synth/whm204.ts +60 -0
- package/src/lint/post-synth/whm301.ts +41 -0
- package/src/lint/post-synth/whm302.ts +40 -0
- package/src/lint/post-synth/whm401.ts +57 -0
- package/src/lint/post-synth/whm402.ts +45 -0
- package/src/lint/post-synth/whm403.ts +45 -0
- package/src/lint/post-synth/whm404.ts +36 -0
- package/src/lint/post-synth/whm405.ts +53 -0
- package/src/lint/post-synth/whm406.ts +34 -0
- package/src/lint/post-synth/whm407.ts +83 -0
- package/src/lint/post-synth/whm501.ts +103 -0
- package/src/lint/post-synth/whm502.ts +94 -0
- package/src/lint/rules/chart-metadata.ts +64 -0
- package/src/lint/rules/lint-rules.test.ts +97 -0
- package/src/lint/rules/no-hardcoded-image.ts +62 -0
- package/src/lint/rules/values-no-secrets.ts +82 -0
- package/src/lsp/completions.test.ts +72 -0
- package/src/lsp/completions.ts +20 -0
- package/src/lsp/hover.test.ts +46 -0
- package/src/lsp/hover.ts +46 -0
- package/src/package-cli.ts +28 -0
- package/src/plugin.test.ts +71 -0
- package/src/plugin.ts +206 -0
- package/src/resources.ts +77 -0
- package/src/serializer.test.ts +930 -0
- package/src/serializer.ts +835 -0
- package/src/skills/chart-patterns.md +229 -0
- package/src/skills/chart-security-patterns.md +192 -0
- package/src/skills/create-chart.md +211 -0
- package/src/validate-cli.ts +21 -0
- package/src/validate.test.ts +37 -0
- package/src/validate.ts +36 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation generation for the Helm lexicon.
|
|
3
|
+
*
|
|
4
|
+
* Generates Starlight MDX pages for Helm entities using the core docs pipeline.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { dirname, join } from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
import { docsPipeline, writeDocsSite, type DocsConfig } from "@intentius/chant/codegen/docs";
|
|
10
|
+
|
|
11
|
+
function serviceFromType(resourceType: string): string {
|
|
12
|
+
const parts = resourceType.split("::");
|
|
13
|
+
return parts.length >= 2 ? parts[1] : "Helm";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const overview = `The **Helm** lexicon generates production-quality, parameterized Helm charts from typed TypeScript.
|
|
17
|
+
|
|
18
|
+
Unlike static manifest generators, the Helm lexicon produces real \`{{ .Values.x }}\` directives, \`values.yaml\`, \`values.schema.json\`, conditional resources, Helm hooks, and standard \`_helpers.tpl\`.
|
|
19
|
+
|
|
20
|
+
Install it with:
|
|
21
|
+
|
|
22
|
+
\`\`\`bash
|
|
23
|
+
npm install --save-dev @intentius/chant-lexicon-helm @intentius/chant-lexicon-k8s
|
|
24
|
+
\`\`\`
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
\`\`\`typescript
|
|
29
|
+
import { Chart, Values } from "@intentius/chant-lexicon-helm";
|
|
30
|
+
import { values, include, printf, toYaml } from "@intentius/chant-lexicon-helm";
|
|
31
|
+
import { Deployment, Service } from "@intentius/chant-lexicon-k8s";
|
|
32
|
+
|
|
33
|
+
export const chart = new Chart({
|
|
34
|
+
apiVersion: "v2",
|
|
35
|
+
name: "my-app",
|
|
36
|
+
version: "0.1.0",
|
|
37
|
+
type: "application",
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const valuesSchema = new Values({
|
|
41
|
+
replicaCount: 1,
|
|
42
|
+
image: { repository: "nginx", tag: "", pullPolicy: "IfNotPresent" },
|
|
43
|
+
service: { type: "ClusterIP", port: 80 },
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export const deployment = new Deployment({
|
|
47
|
+
metadata: {
|
|
48
|
+
name: include("my-app.fullname"),
|
|
49
|
+
labels: include("my-app.labels"),
|
|
50
|
+
},
|
|
51
|
+
spec: {
|
|
52
|
+
replicas: values.replicaCount,
|
|
53
|
+
template: {
|
|
54
|
+
spec: {
|
|
55
|
+
containers: [{
|
|
56
|
+
name: "my-app",
|
|
57
|
+
image: printf("%s:%s", values.image.repository, values.image.tag),
|
|
58
|
+
ports: [{ containerPort: values.service.port, name: "http" }],
|
|
59
|
+
resources: toYaml(values.resources),
|
|
60
|
+
}],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
\`\`\`
|
|
66
|
+
|
|
67
|
+
Build the chart:
|
|
68
|
+
|
|
69
|
+
\`\`\`bash
|
|
70
|
+
chant build
|
|
71
|
+
helm lint dist/
|
|
72
|
+
helm template test dist/
|
|
73
|
+
\`\`\`
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
const outputFormat = `## Output structure
|
|
77
|
+
|
|
78
|
+
The Helm serializer produces a complete chart directory:
|
|
79
|
+
|
|
80
|
+
\`\`\`
|
|
81
|
+
dist/
|
|
82
|
+
Chart.yaml ← from Chart entity
|
|
83
|
+
values.yaml ← from Values entity (defaults)
|
|
84
|
+
values.schema.json ← auto-generated JSON Schema from Values types
|
|
85
|
+
.helmignore
|
|
86
|
+
templates/
|
|
87
|
+
_helpers.tpl ← auto-generated standard helpers
|
|
88
|
+
deployment.yaml ← K8s resources with {{ .Values.x }} directives
|
|
89
|
+
service.yaml
|
|
90
|
+
NOTES.txt ← from HelmNotes entity
|
|
91
|
+
tests/
|
|
92
|
+
test-connection.yaml ← from HelmTest entities
|
|
93
|
+
\`\`\`
|
|
94
|
+
`;
|
|
95
|
+
|
|
96
|
+
export async function generateDocs(opts?: { verbose?: boolean }): Promise<void> {
|
|
97
|
+
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
98
|
+
|
|
99
|
+
const config: DocsConfig = {
|
|
100
|
+
name: "helm",
|
|
101
|
+
displayName: "Helm",
|
|
102
|
+
description: "Typed constructors for parameterized Helm charts",
|
|
103
|
+
distDir: join(pkgDir, "dist"),
|
|
104
|
+
outDir: join(pkgDir, "docs"),
|
|
105
|
+
overview,
|
|
106
|
+
outputFormat,
|
|
107
|
+
serviceFromType,
|
|
108
|
+
suppressPages: ["pseudo-parameters"],
|
|
109
|
+
extraPages: [
|
|
110
|
+
{
|
|
111
|
+
slug: "getting-started",
|
|
112
|
+
title: "Getting Started",
|
|
113
|
+
description: "Create your first typed Helm chart in 5 minutes",
|
|
114
|
+
content: `## What is the Helm lexicon?
|
|
115
|
+
|
|
116
|
+
The Helm lexicon extends chant to produce **real, parameterized Helm charts** from typed TypeScript. Unlike static manifest generators (like cdk8s's Helm output), the Helm lexicon generates:
|
|
117
|
+
|
|
118
|
+
- \`{{ .Values.x }}\` template directives
|
|
119
|
+
- \`values.yaml\` with typed defaults
|
|
120
|
+
- \`values.schema.json\` for validation
|
|
121
|
+
- Conditional resources via \`{{- if }}\`
|
|
122
|
+
- Standard \`_helpers.tpl\`
|
|
123
|
+
- Helm hooks and tests
|
|
124
|
+
|
|
125
|
+
## Install
|
|
126
|
+
|
|
127
|
+
\`\`\`bash
|
|
128
|
+
npm install --save-dev @intentius/chant @intentius/chant-lexicon-helm @intentius/chant-lexicon-k8s
|
|
129
|
+
\`\`\`
|
|
130
|
+
|
|
131
|
+
## Your first chart
|
|
132
|
+
|
|
133
|
+
\`\`\`bash
|
|
134
|
+
chant init --lexicon helm
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
This creates a scaffold with a Chart, Values, Deployment, and Service. Run \`chant build\` to produce a complete Helm chart directory.
|
|
138
|
+
|
|
139
|
+
## Key imports
|
|
140
|
+
|
|
141
|
+
\`\`\`typescript
|
|
142
|
+
// Resources
|
|
143
|
+
import { Chart, Values, HelmNotes } from "@intentius/chant-lexicon-helm";
|
|
144
|
+
|
|
145
|
+
// Intrinsics (produce Go template expressions)
|
|
146
|
+
import { values, Release, include, printf, toYaml, If } from "@intentius/chant-lexicon-helm";
|
|
147
|
+
|
|
148
|
+
// K8s resources
|
|
149
|
+
import { Deployment, Service, Ingress } from "@intentius/chant-lexicon-k8s";
|
|
150
|
+
\`\`\`
|
|
151
|
+
`,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
slug: "intrinsics",
|
|
155
|
+
title: "Intrinsics Reference",
|
|
156
|
+
description: "All Helm template intrinsics and how they map to Go template expressions",
|
|
157
|
+
content: `## Values proxy
|
|
158
|
+
|
|
159
|
+
\`\`\`typescript
|
|
160
|
+
import { values } from "@intentius/chant-lexicon-helm";
|
|
161
|
+
|
|
162
|
+
values.replicaCount // {{ .Values.replicaCount }}
|
|
163
|
+
values.image.repository // {{ .Values.image.repository }}
|
|
164
|
+
values.x.pipe("upper") // {{ .Values.x | upper }}
|
|
165
|
+
\`\`\`
|
|
166
|
+
|
|
167
|
+
## Built-in objects
|
|
168
|
+
|
|
169
|
+
\`\`\`typescript
|
|
170
|
+
import { Release, ChartRef } from "@intentius/chant-lexicon-helm";
|
|
171
|
+
|
|
172
|
+
Release.Name // {{ .Release.Name }}
|
|
173
|
+
Release.Namespace // {{ .Release.Namespace }}
|
|
174
|
+
Release.IsUpgrade // {{ .Release.IsUpgrade }}
|
|
175
|
+
ChartRef.Name // {{ .Chart.Name }}
|
|
176
|
+
ChartRef.Version // {{ .Chart.Version }}
|
|
177
|
+
\`\`\`
|
|
178
|
+
|
|
179
|
+
## Template functions
|
|
180
|
+
|
|
181
|
+
| Function | Output |
|
|
182
|
+
|----------|--------|
|
|
183
|
+
| \`include("name")\` | \`{{ include "name" . }}\` |
|
|
184
|
+
| \`required("msg", values.x)\` | \`{{ required "msg" .Values.x }}\` |
|
|
185
|
+
| \`helmDefault("val", values.x)\` | \`{{ default "val" .Values.x }}\` |
|
|
186
|
+
| \`toYaml(values.x)\` | \`{{ toYaml .Values.x }}\` |
|
|
187
|
+
| \`toYaml(values.x, 12)\` | \`{{ toYaml .Values.x \\| nindent 12 }}\` |
|
|
188
|
+
| \`quote(values.x)\` | \`{{ .Values.x \\| quote }}\` |
|
|
189
|
+
| \`printf("%s:%s", a, b)\` | \`{{ printf "%s:%s" a b }}\` |
|
|
190
|
+
| \`tpl(values.x)\` | \`{{ tpl .Values.x . }}\` |
|
|
191
|
+
| \`lookup("v1", "Secret", "ns", "name")\` | \`{{ lookup "v1" "Secret" "ns" "name" }}\` |
|
|
192
|
+
|
|
193
|
+
## Control flow
|
|
194
|
+
|
|
195
|
+
\`\`\`typescript
|
|
196
|
+
import { If, Range, With, values } from "@intentius/chant-lexicon-helm";
|
|
197
|
+
|
|
198
|
+
// Conditional resource
|
|
199
|
+
export const ingress = If(values.ingress.enabled, new Ingress({ ... }));
|
|
200
|
+
|
|
201
|
+
// Conditional value
|
|
202
|
+
const image = If(values.image.tag, printf("%s:%s", values.image.repo, values.image.tag));
|
|
203
|
+
\`\`\`
|
|
204
|
+
|
|
205
|
+
## Resource ordering
|
|
206
|
+
|
|
207
|
+
| Function | Output |
|
|
208
|
+
|----------|--------|
|
|
209
|
+
| \`withOrder(5)\` | \`helm.sh/hook: pre-install,pre-upgrade\` + \`helm.sh/hook-weight: "5"\` |
|
|
210
|
+
| \`argoWave(2)\` | \`argocd.argoproj.io/sync-wave: "2"\` |
|
|
211
|
+
|
|
212
|
+
\`\`\`typescript
|
|
213
|
+
import { withOrder, argoWave } from "@intentius/chant-lexicon-helm";
|
|
214
|
+
|
|
215
|
+
const job = new Job({
|
|
216
|
+
metadata: { annotations: { ...withOrder(-5) } },
|
|
217
|
+
// ...
|
|
218
|
+
});
|
|
219
|
+
\`\`\`
|
|
220
|
+
`,
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
slug: "composites",
|
|
224
|
+
title: "Composites",
|
|
225
|
+
description: "Pre-built Helm chart patterns",
|
|
226
|
+
content: `## Available composites
|
|
227
|
+
|
|
228
|
+
| Composite | Description | Resources |
|
|
229
|
+
|-----------|-------------|-----------|
|
|
230
|
+
| \`HelmWebApp\` | Web application | Deployment, Service, Ingress?, HPA?, ServiceAccount? |
|
|
231
|
+
| \`HelmStatefulService\` | Stateful workload | StatefulSet, headless Service, PVC |
|
|
232
|
+
| \`HelmCronJob\` | Scheduled job | CronJob |
|
|
233
|
+
| \`HelmMicroservice\` | Full microservice | Deployment, Service, Ingress?, HPA?, PDB?, ServiceAccount, ConfigMap? |
|
|
234
|
+
| \`HelmLibrary\` | Library chart | Chart.yaml (type: library), _helpers.tpl |
|
|
235
|
+
| \`HelmCRDLifecycle\` | Managed CRD lifecycle | Job (hook), ConfigMap, ServiceAccount, ClusterRole, ClusterRoleBinding |
|
|
236
|
+
| \`HelmDaemonSet\` | Node-level workload | DaemonSet, ServiceAccount? |
|
|
237
|
+
| \`HelmWorker\` | Background processor | Deployment (no Service), ServiceAccount, HPA?, PDB? |
|
|
238
|
+
| \`HelmExternalSecret\` | Secret management | ExternalSecret CR (external-secrets.io) |
|
|
239
|
+
| \`HelmBatchJob\` | One-shot batch job | Job, ServiceAccount?, Role?, RoleBinding? |
|
|
240
|
+
| \`HelmMonitoredService\` | Service with monitoring | Deployment, Service, ServiceAccount?, ServiceMonitor, PrometheusRule? |
|
|
241
|
+
| \`HelmSecureIngress\` | TLS ingress + cert-manager | Ingress, Certificate? |
|
|
242
|
+
| \`HelmNamespaceEnv\` | Namespace environment | Namespace, ResourceQuota?, LimitRange?, NetworkPolicy? |
|
|
243
|
+
|
|
244
|
+
## Example
|
|
245
|
+
|
|
246
|
+
\`\`\`typescript
|
|
247
|
+
import { HelmWebApp } from "@intentius/chant-lexicon-helm";
|
|
248
|
+
|
|
249
|
+
const result = HelmWebApp({
|
|
250
|
+
name: "my-app",
|
|
251
|
+
imageRepository: "myregistry/app",
|
|
252
|
+
port: 3000,
|
|
253
|
+
replicas: 3,
|
|
254
|
+
ingress: true,
|
|
255
|
+
autoscaling: true,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// result.chart, result.values, result.deployment, result.service, result.ingress, result.hpa
|
|
259
|
+
\`\`\`
|
|
260
|
+
`,
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
slug: "rules",
|
|
264
|
+
title: "Lint Rules",
|
|
265
|
+
description: "Pre-synth and post-synth lint rules for Helm charts",
|
|
266
|
+
content: `## Pre-synth rules (AST-level)
|
|
267
|
+
|
|
268
|
+
| Rule | Severity | Description |
|
|
269
|
+
|------|----------|-------------|
|
|
270
|
+
| WHM001 | error | Chart must have name, version, and apiVersion |
|
|
271
|
+
| WHM002 | warning | Values should not contain bare secrets (password, token, key) |
|
|
272
|
+
| WHM003 | warning | Container images should use values references, not hardcoded tags |
|
|
273
|
+
|
|
274
|
+
## Post-synth checks (output validation)
|
|
275
|
+
|
|
276
|
+
| Check | Severity | Description |
|
|
277
|
+
|-------|----------|-------------|
|
|
278
|
+
| WHM101 | error | Chart.yaml has required fields and apiVersion v2 |
|
|
279
|
+
| WHM102 | warning | values.schema.json present when Values type used |
|
|
280
|
+
| WHM103 | error | Go template syntax valid (balanced braces) |
|
|
281
|
+
| WHM104 | info | NOTES.txt exists for application charts |
|
|
282
|
+
| WHM105 | warning | _helpers.tpl exists |
|
|
283
|
+
| WHM201 | info | Resources have standard Helm labels |
|
|
284
|
+
| WHM202 | info | Hook weights defined for multi-hook charts |
|
|
285
|
+
| WHM203 | info | Values entries documented |
|
|
286
|
+
| WHM204 | warning | Dependencies use semver ranges |
|
|
287
|
+
| WHM301 | info | At least one test for application charts |
|
|
288
|
+
| WHM302 | info | Resource limits set (via values or defaults) |
|
|
289
|
+
| WHM401 | warning | Image uses :latest tag or no tag |
|
|
290
|
+
| WHM402 | warning | runAsNonRoot not set in security context |
|
|
291
|
+
| WHM403 | info | readOnlyRootFilesystem not set |
|
|
292
|
+
| WHM404 | error | privileged: true detected |
|
|
293
|
+
| WHM405 | warning | Resource spec missing cpu/memory detail |
|
|
294
|
+
| WHM406 | info | CRDs in crds/ — Helm never upgrades/deletes them |
|
|
295
|
+
| WHM407 | warning | Secret with inline data, no ExternalSecret/SealedSecret |
|
|
296
|
+
| WHM501 | info | Values keys defined but never referenced in templates |
|
|
297
|
+
| WHM502 | warning | Deprecated or invalid K8s API versions |
|
|
298
|
+
`,
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
slug: "security",
|
|
302
|
+
title: "Security",
|
|
303
|
+
description: "Security best practices and checks for Helm charts",
|
|
304
|
+
content: `## Secret management
|
|
305
|
+
|
|
306
|
+
Avoid inline secrets in Kubernetes Secret manifests. Use ExternalSecret or SealedSecret instead:
|
|
307
|
+
|
|
308
|
+
\`\`\`typescript
|
|
309
|
+
import { HelmExternalSecret } from "@intentius/chant-lexicon-helm";
|
|
310
|
+
|
|
311
|
+
const { externalSecret, values } = HelmExternalSecret({
|
|
312
|
+
name: "app-secrets",
|
|
313
|
+
secretStoreName: "vault",
|
|
314
|
+
data: {
|
|
315
|
+
DB_PASSWORD: "secret/data/db-password",
|
|
316
|
+
API_KEY: "secret/data/api-key",
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
\`\`\`
|
|
320
|
+
|
|
321
|
+
WHM407 warns when a \`kind: Secret\` template contains inline data values without an ExternalSecret or SealedSecret in the chart.
|
|
322
|
+
|
|
323
|
+
## Security context best practices
|
|
324
|
+
|
|
325
|
+
Always set security context on pods and containers:
|
|
326
|
+
|
|
327
|
+
\`\`\`typescript
|
|
328
|
+
spec: {
|
|
329
|
+
securityContext: {
|
|
330
|
+
runAsNonRoot: true,
|
|
331
|
+
runAsUser: 1000,
|
|
332
|
+
},
|
|
333
|
+
containers: [{
|
|
334
|
+
securityContext: {
|
|
335
|
+
readOnlyRootFilesystem: true,
|
|
336
|
+
allowPrivilegeEscalation: false,
|
|
337
|
+
},
|
|
338
|
+
}],
|
|
339
|
+
}
|
|
340
|
+
\`\`\`
|
|
341
|
+
|
|
342
|
+
### Related checks
|
|
343
|
+
|
|
344
|
+
| Check | Severity | Description |
|
|
345
|
+
|-------|----------|-------------|
|
|
346
|
+
| WHM401 | warning | Image uses :latest tag or no tag |
|
|
347
|
+
| WHM402 | warning | runAsNonRoot not set |
|
|
348
|
+
| WHM403 | info | readOnlyRootFilesystem not set |
|
|
349
|
+
| WHM404 | error | privileged: true detected |
|
|
350
|
+
| WHM405 | warning | Resource spec missing cpu/memory |
|
|
351
|
+
| WHM406 | info | CRD lifecycle limitation |
|
|
352
|
+
| WHM407 | warning | Secret with inline data |
|
|
353
|
+
|
|
354
|
+
## Image pinning
|
|
355
|
+
|
|
356
|
+
Always pin container images to specific tags or digests:
|
|
357
|
+
|
|
358
|
+
\`\`\`typescript
|
|
359
|
+
// Bad — triggers WHM401
|
|
360
|
+
image: "nginx:latest"
|
|
361
|
+
image: "nginx"
|
|
362
|
+
|
|
363
|
+
// Good
|
|
364
|
+
image: printf("%s:%s", values.image.repository, values.image.tag)
|
|
365
|
+
\`\`\`
|
|
366
|
+
|
|
367
|
+
Set a specific default tag in your values:
|
|
368
|
+
|
|
369
|
+
\`\`\`typescript
|
|
370
|
+
const valuesSchema = new Values({
|
|
371
|
+
image: {
|
|
372
|
+
repository: "nginx",
|
|
373
|
+
tag: "1.25.0", // Pinned version
|
|
374
|
+
pullPolicy: "IfNotPresent",
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
\`\`\`
|
|
378
|
+
`,
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
slug: "best-practices",
|
|
382
|
+
title: "Best Practices",
|
|
383
|
+
description: "Common patterns and recommendations for Helm charts with chant",
|
|
384
|
+
content: `## CRD lifecycle
|
|
385
|
+
|
|
386
|
+
Helm installs CRDs from the \`crds/\` directory but **never upgrades or deletes them**. For managed CRD lifecycle, use the \`HelmCRDLifecycle\` composite:
|
|
387
|
+
|
|
388
|
+
\`\`\`typescript
|
|
389
|
+
import { HelmCRDLifecycle } from "@intentius/chant-lexicon-helm";
|
|
390
|
+
|
|
391
|
+
const lifecycle = HelmCRDLifecycle({
|
|
392
|
+
name: "my-operator",
|
|
393
|
+
crdContent: crdYaml,
|
|
394
|
+
kubectlImage: "bitnami/kubectl",
|
|
395
|
+
kubectlTag: "1.28",
|
|
396
|
+
});
|
|
397
|
+
\`\`\`
|
|
398
|
+
|
|
399
|
+
This creates a Job-based hook that runs \`kubectl apply\` for CRDs during pre-install/pre-upgrade, with proper RBAC.
|
|
400
|
+
|
|
401
|
+
## Resource ordering
|
|
402
|
+
|
|
403
|
+
Use \`withOrder()\` for Helm hook ordering and \`argoWave()\` for Argo CD sync waves:
|
|
404
|
+
|
|
405
|
+
\`\`\`typescript
|
|
406
|
+
import { withOrder, argoWave } from "@intentius/chant-lexicon-helm";
|
|
407
|
+
|
|
408
|
+
// Helm hook ordering (lower weight = runs first)
|
|
409
|
+
metadata: { annotations: { ...withOrder(-5) } }
|
|
410
|
+
|
|
411
|
+
// Argo CD sync waves
|
|
412
|
+
metadata: { annotations: { ...argoWave(1) } }
|
|
413
|
+
\`\`\`
|
|
414
|
+
|
|
415
|
+
## Multi-environment values
|
|
416
|
+
|
|
417
|
+
Structure your chant project with base values and environment overlays:
|
|
418
|
+
|
|
419
|
+
\`\`\`
|
|
420
|
+
src/
|
|
421
|
+
chart.ts ← Base chart with shared values
|
|
422
|
+
values-dev.yaml ← Override for dev
|
|
423
|
+
values-staging.yaml ← Override for staging
|
|
424
|
+
values-prod.yaml ← Override for production
|
|
425
|
+
\`\`\`
|
|
426
|
+
|
|
427
|
+
Use \`helm install -f values-prod.yaml\` to merge environment-specific values.
|
|
428
|
+
|
|
429
|
+
## List merge workaround
|
|
430
|
+
|
|
431
|
+
Helm's strategic merge patch does not merge lists — it replaces them. Use map-of-maps instead:
|
|
432
|
+
|
|
433
|
+
\`\`\`typescript
|
|
434
|
+
// Instead of a list (hard to override per-environment)
|
|
435
|
+
hosts: [{ host: "app.example.com" }]
|
|
436
|
+
|
|
437
|
+
// Use a map-of-maps pattern
|
|
438
|
+
hosts:
|
|
439
|
+
primary:
|
|
440
|
+
host: "app.example.com"
|
|
441
|
+
paths: [{ path: "/", pathType: "Prefix" }]
|
|
442
|
+
\`\`\`
|
|
443
|
+
|
|
444
|
+
## Unused values
|
|
445
|
+
|
|
446
|
+
WHM501 detects values keys that are defined but never referenced in templates. This helps keep \`values.yaml\` clean and avoids confusion.
|
|
447
|
+
|
|
448
|
+
## Deprecated API versions
|
|
449
|
+
|
|
450
|
+
WHM502 detects deprecated Kubernetes API versions (like \`extensions/v1beta1\` for Ingress) and suggests current replacements.
|
|
451
|
+
`,
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
slug: "skills",
|
|
455
|
+
title: "AI Skills",
|
|
456
|
+
description: "AI agent skills bundled with the Helm lexicon",
|
|
457
|
+
content: `## What are skills?
|
|
458
|
+
|
|
459
|
+
Skills are structured markdown documents bundled with a lexicon. When an AI agent works in a chant project, it discovers and loads relevant skills automatically — giving it operational knowledge about the Helm chart workflow.
|
|
460
|
+
|
|
461
|
+
## Bundled skill: chant-helm
|
|
462
|
+
|
|
463
|
+
The \`chant-helm\` skill teaches AI agents how to:
|
|
464
|
+
|
|
465
|
+
- Scaffold new Helm chart projects with \`chant init --lexicon helm\`
|
|
466
|
+
- Use Helm intrinsics (values proxy, include, printf, toYaml, If/Range/With)
|
|
467
|
+
- Build and validate charts with chant + helm CLI
|
|
468
|
+
- Debug common issues (unbalanced braces, hardcoded images, missing metadata)
|
|
469
|
+
- Use composites for common patterns (WebApp, Microservice, StatefulService)
|
|
470
|
+
|
|
471
|
+
When you scaffold a new project with \`chant init --lexicon helm\`, the skill is installed to \`skills/chant-helm/SKILL.md\` for automatic discovery by Claude Code.
|
|
472
|
+
`,
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
const result = await docsPipeline(config);
|
|
478
|
+
writeDocsSite(result, config.outDir);
|
|
479
|
+
|
|
480
|
+
if (opts?.verbose) {
|
|
481
|
+
console.error(`Generated ${result.pages.length} documentation pages`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* CLI entry point for Helm lexicon generation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { dirname } from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { generate, writeGeneratedFiles } from "./generate";
|
|
9
|
+
|
|
10
|
+
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
11
|
+
|
|
12
|
+
async function main() {
|
|
13
|
+
const verbose = process.argv.includes("--verbose") || process.argv.includes("-v");
|
|
14
|
+
|
|
15
|
+
console.error("Generating Helm lexicon (static types)...");
|
|
16
|
+
|
|
17
|
+
const result = await generate({ verbose });
|
|
18
|
+
writeGeneratedFiles(result, pkgDir);
|
|
19
|
+
|
|
20
|
+
console.error(
|
|
21
|
+
`Generated ${result.resources} resources, ${result.properties} property types`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
main().catch((err) => {
|
|
26
|
+
console.error("Generation failed:", err);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
});
|