@intentius/chant-lexicon-helm 0.0.16 → 0.0.22
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/dist/integrity.json +3 -3
- package/dist/manifest.json +1 -1
- package/dist/skills/chant-helm-create-chart.md +1 -1
- package/package.json +21 -3
- package/src/codegen/docs.test.ts +14 -0
- package/src/codegen/generate.test.ts +71 -0
- package/src/codegen/package.test.ts +36 -0
- package/src/import/roundtrip.test.ts +144 -0
- package/src/lint/post-synth/whm101.test.ts +69 -0
- package/src/lint/post-synth/whm102.test.ts +57 -0
- package/src/lint/post-synth/whm103.test.ts +58 -0
- package/src/lint/post-synth/whm104.test.ts +57 -0
- package/src/lint/post-synth/whm105.test.ts +41 -0
- package/src/lint/post-synth/whm201.test.ts +59 -0
- package/src/lint/post-synth/whm202.test.ts +62 -0
- package/src/lint/post-synth/whm203.test.ts +58 -0
- package/src/lint/post-synth/whm204.test.ts +56 -0
- package/src/lint/post-synth/whm301.test.ts +49 -0
- package/src/lint/post-synth/whm302.test.ts +58 -0
- package/src/lint/post-synth/whm401.test.ts +59 -0
- package/src/lint/post-synth/whm402.test.ts +58 -0
- package/src/lint/post-synth/whm403.test.ts +50 -0
- package/src/lint/post-synth/whm404.test.ts +50 -0
- package/src/lint/post-synth/whm405.test.ts +60 -0
- package/src/lint/post-synth/whm406.test.ts +43 -0
- package/src/lint/post-synth/whm407.test.ts +60 -0
- package/src/lint/post-synth/whm501.test.ts +70 -0
- package/src/lint/post-synth/whm502.test.ts +72 -0
- package/src/lint/rules/chart-metadata.test.ts +45 -0
- package/src/lint/rules/no-hardcoded-image.test.ts +41 -0
- package/src/lint/rules/values-no-secrets.test.ts +48 -0
- package/src/plugin.ts +205 -0
- package/src/skills/create-chart.md +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm201 } from "./whm201";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM201: standard labels", () => {
|
|
24
|
+
test("info when template lacks labels", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"templates/deploy.yaml": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: test\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm201.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM201");
|
|
32
|
+
expect(diags[0].severity).toBe("info");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("passes when template includes labels helper", () => {
|
|
36
|
+
const ctx = makeCtx({
|
|
37
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
38
|
+
"templates/deploy.yaml": 'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n labels: {{ include "test.labels" . }}\n',
|
|
39
|
+
});
|
|
40
|
+
expect(whm201.check(ctx)).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("passes when template has helm.sh/chart annotation", () => {
|
|
44
|
+
const ctx = makeCtx({
|
|
45
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
46
|
+
"templates/deploy.yaml": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n labels:\n helm.sh/chart: test\n",
|
|
47
|
+
});
|
|
48
|
+
expect(whm201.check(ctx)).toHaveLength(0);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("skips _helpers.tpl and NOTES.txt", () => {
|
|
52
|
+
const ctx = makeCtx({
|
|
53
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
54
|
+
"templates/_helpers.tpl": "kind: something\n",
|
|
55
|
+
"templates/NOTES.txt": "kind: something\n",
|
|
56
|
+
});
|
|
57
|
+
expect(whm201.check(ctx)).toHaveLength(0);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm202 } from "./whm202";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM202: hook weights", () => {
|
|
24
|
+
test("warns when multiple hooks exist and some lack weights", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"templates/pre-install.yaml": "helm.sh/hook: pre-install\nhelm.sh/hook-weight: \"-5\"\n",
|
|
28
|
+
"templates/post-install.yaml": "helm.sh/hook: post-install\n",
|
|
29
|
+
});
|
|
30
|
+
const diags = whm202.check(ctx);
|
|
31
|
+
expect(diags).toHaveLength(1);
|
|
32
|
+
expect(diags[0].checkId).toBe("WHM202");
|
|
33
|
+
expect(diags[0].severity).toBe("warning");
|
|
34
|
+
expect(diags[0].message).toContain("hook-weight");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("passes when all hooks have weights", () => {
|
|
38
|
+
const ctx = makeCtx({
|
|
39
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
40
|
+
"templates/pre-install.yaml": "helm.sh/hook: pre-install\nhelm.sh/hook-weight: \"-5\"\n",
|
|
41
|
+
"templates/post-install.yaml": "helm.sh/hook: post-install\nhelm.sh/hook-weight: \"5\"\n",
|
|
42
|
+
});
|
|
43
|
+
expect(whm202.check(ctx)).toHaveLength(0);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("passes with a single hook without weight", () => {
|
|
47
|
+
const ctx = makeCtx({
|
|
48
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
49
|
+
"templates/pre-install.yaml": "helm.sh/hook: pre-install\n",
|
|
50
|
+
});
|
|
51
|
+
expect(whm202.check(ctx)).toHaveLength(0);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("ignores test hooks", () => {
|
|
55
|
+
const ctx = makeCtx({
|
|
56
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
57
|
+
"templates/test.yaml": "helm.sh/hook: test\n",
|
|
58
|
+
"templates/pre-install.yaml": "helm.sh/hook: pre-install\n",
|
|
59
|
+
});
|
|
60
|
+
expect(whm202.check(ctx)).toHaveLength(0);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm203 } from "./whm203";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM203: values documentation", () => {
|
|
24
|
+
test("info when values exist but no schema", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"values.yaml": "replicaCount: 1\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm203.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM203");
|
|
32
|
+
expect(diags[0].severity).toBe("info");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("passes when schema exists", () => {
|
|
36
|
+
const ctx = makeCtx({
|
|
37
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
38
|
+
"values.yaml": "replicaCount: 1\n",
|
|
39
|
+
"values.schema.json": '{"type":"object"}',
|
|
40
|
+
});
|
|
41
|
+
expect(whm203.check(ctx)).toHaveLength(0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("passes when values.yaml is empty object", () => {
|
|
45
|
+
const ctx = makeCtx({
|
|
46
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
47
|
+
"values.yaml": "{}",
|
|
48
|
+
});
|
|
49
|
+
expect(whm203.check(ctx)).toHaveLength(0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("passes when no values.yaml exists", () => {
|
|
53
|
+
const ctx = makeCtx({
|
|
54
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
55
|
+
});
|
|
56
|
+
expect(whm203.check(ctx)).toHaveLength(0);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm204 } from "./whm204";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM204: dependency semver ranges", () => {
|
|
24
|
+
test("info when dependency uses pinned version", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\ndependencies:\n - name: redis\n version: 1.2.3\n repository: https://charts.bitnami.com\n",
|
|
27
|
+
});
|
|
28
|
+
const diags = whm204.check(ctx);
|
|
29
|
+
expect(diags).toHaveLength(1);
|
|
30
|
+
expect(diags[0].checkId).toBe("WHM204");
|
|
31
|
+
expect(diags[0].severity).toBe("info");
|
|
32
|
+
expect(diags[0].message).toContain("redis");
|
|
33
|
+
expect(diags[0].message).toContain("1.2.3");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("passes when dependency uses tilde range", () => {
|
|
37
|
+
const ctx = makeCtx({
|
|
38
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\ndependencies:\n - name: redis\n version: ~1.2.3\n repository: https://charts.bitnami.com\n",
|
|
39
|
+
});
|
|
40
|
+
expect(whm204.check(ctx)).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("passes when dependency uses caret range", () => {
|
|
44
|
+
const ctx = makeCtx({
|
|
45
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\ndependencies:\n - name: redis\n version: ^1.2.3\n repository: https://charts.bitnami.com\n",
|
|
46
|
+
});
|
|
47
|
+
expect(whm204.check(ctx)).toHaveLength(0);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("passes when no dependencies section", () => {
|
|
51
|
+
const ctx = makeCtx({
|
|
52
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
53
|
+
});
|
|
54
|
+
expect(whm204.check(ctx)).toHaveLength(0);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm301 } from "./whm301";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM301: Helm tests", () => {
|
|
24
|
+
test("info when no tests defined for application chart", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\ntype: application\n",
|
|
27
|
+
"templates/deploy.yaml": "kind: Deployment\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm301.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM301");
|
|
32
|
+
expect(diags[0].severity).toBe("info");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("passes when test exists", () => {
|
|
36
|
+
const ctx = makeCtx({
|
|
37
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\ntype: application\n",
|
|
38
|
+
"templates/tests/test-connection.yaml": "helm.sh/hook: test\n",
|
|
39
|
+
});
|
|
40
|
+
expect(whm301.check(ctx)).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("skips library charts", () => {
|
|
44
|
+
const ctx = makeCtx({
|
|
45
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\ntype: library\n",
|
|
46
|
+
});
|
|
47
|
+
expect(whm301.check(ctx)).toHaveLength(0);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm302 } from "./whm302";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM302: resource limits", () => {
|
|
24
|
+
test("info when containers lack resources", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm302.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM302");
|
|
32
|
+
expect(diags[0].severity).toBe("info");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("passes when resources are set", () => {
|
|
36
|
+
const ctx = makeCtx({
|
|
37
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
38
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n resources:\n limits:\n cpu: 100m\n",
|
|
39
|
+
});
|
|
40
|
+
expect(whm302.check(ctx)).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("passes when resources use values reference", () => {
|
|
44
|
+
const ctx = makeCtx({
|
|
45
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
46
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n resources: {{ toYaml .Values.resources }}\n",
|
|
47
|
+
});
|
|
48
|
+
expect(whm302.check(ctx)).toHaveLength(0);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("skips test templates", () => {
|
|
52
|
+
const ctx = makeCtx({
|
|
53
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
54
|
+
"templates/tests/test.yaml": "containers:\n - name: test\n",
|
|
55
|
+
});
|
|
56
|
+
expect(whm302.check(ctx)).toHaveLength(0);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm401 } from "./whm401";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM401: image tag", () => {
|
|
24
|
+
test("warns on :latest tag", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n image: nginx:latest\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm401.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM401");
|
|
32
|
+
expect(diags[0].severity).toBe("warning");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("warns on untagged image", () => {
|
|
36
|
+
const ctx = makeCtx({
|
|
37
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
38
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n image: nginx\n",
|
|
39
|
+
});
|
|
40
|
+
const diags = whm401.check(ctx);
|
|
41
|
+
expect(diags).toHaveLength(1);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("passes with pinned tag", () => {
|
|
45
|
+
const ctx = makeCtx({
|
|
46
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
47
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n image: nginx:1.25.0\n",
|
|
48
|
+
});
|
|
49
|
+
expect(whm401.check(ctx)).toHaveLength(0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("passes with .Values reference", () => {
|
|
53
|
+
const ctx = makeCtx({
|
|
54
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
55
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n image: {{ .Values.image.repository }}:{{ .Values.image.tag }}\n",
|
|
56
|
+
});
|
|
57
|
+
expect(whm401.check(ctx)).toHaveLength(0);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm402 } from "./whm402";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM402: runAsNonRoot", () => {
|
|
24
|
+
test("warns when containers lack runAsNonRoot", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm402.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM402");
|
|
32
|
+
expect(diags[0].severity).toBe("warning");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("passes with runAsNonRoot: true", () => {
|
|
36
|
+
const ctx = makeCtx({
|
|
37
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
38
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n securityContext:\n runAsNonRoot: true\n",
|
|
39
|
+
});
|
|
40
|
+
expect(whm402.check(ctx)).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("passes with .Values.securityContext ref", () => {
|
|
44
|
+
const ctx = makeCtx({
|
|
45
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
46
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n securityContext: {{ toYaml .Values.securityContext }}\n",
|
|
47
|
+
});
|
|
48
|
+
expect(whm402.check(ctx)).toHaveLength(0);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("passes with .Values.podSecurityContext ref", () => {
|
|
52
|
+
const ctx = makeCtx({
|
|
53
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
54
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n securityContext: {{ toYaml .Values.podSecurityContext }}\n",
|
|
55
|
+
});
|
|
56
|
+
expect(whm402.check(ctx)).toHaveLength(0);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm403 } from "./whm403";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM403: readOnlyRootFilesystem", () => {
|
|
24
|
+
test("info when containers lack readOnlyRootFilesystem", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm403.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM403");
|
|
32
|
+
expect(diags[0].severity).toBe("info");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("passes with readOnlyRootFilesystem: true", () => {
|
|
36
|
+
const ctx = makeCtx({
|
|
37
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
38
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n securityContext:\n readOnlyRootFilesystem: true\n",
|
|
39
|
+
});
|
|
40
|
+
expect(whm403.check(ctx)).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("passes with .Values.securityContext ref", () => {
|
|
44
|
+
const ctx = makeCtx({
|
|
45
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
46
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n securityContext: {{ toYaml .Values.securityContext }}\n",
|
|
47
|
+
});
|
|
48
|
+
expect(whm403.check(ctx)).toHaveLength(0);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm404 } from "./whm404";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM404: privileged mode", () => {
|
|
24
|
+
test("error on privileged: true", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n securityContext:\n privileged: true\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm404.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM404");
|
|
32
|
+
expect(diags[0].severity).toBe("error");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("passes without privileged mode", () => {
|
|
36
|
+
const ctx = makeCtx({
|
|
37
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
38
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n",
|
|
39
|
+
});
|
|
40
|
+
expect(whm404.check(ctx)).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("passes with privileged: false", () => {
|
|
44
|
+
const ctx = makeCtx({
|
|
45
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
46
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n securityContext:\n privileged: false\n",
|
|
47
|
+
});
|
|
48
|
+
expect(whm404.check(ctx)).toHaveLength(0);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm405 } from "./whm405";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM405: resource spec detail", () => {
|
|
24
|
+
test("warns when resources lack cpu", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n resources:\n limits:\n memory: 256Mi\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm405.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM405");
|
|
32
|
+
expect(diags[0].message).toContain("cpu");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("passes with both cpu and memory", () => {
|
|
36
|
+
const ctx = makeCtx({
|
|
37
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
38
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n resources:\n limits:\n cpu: 100m\n memory: 256Mi\n",
|
|
39
|
+
});
|
|
40
|
+
expect(whm405.check(ctx)).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("passes when resources use .Values", () => {
|
|
44
|
+
const ctx = makeCtx({
|
|
45
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
46
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n resources: {{ toYaml .Values.resources }}\n",
|
|
47
|
+
});
|
|
48
|
+
expect(whm405.check(ctx)).toHaveLength(0);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("warns when resources lack memory", () => {
|
|
52
|
+
const ctx = makeCtx({
|
|
53
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
54
|
+
"templates/deploy.yaml": "kind: Deployment\nspec:\n containers:\n - name: app\n resources:\n limits:\n cpu: 100m\n",
|
|
55
|
+
});
|
|
56
|
+
const diags = whm405.check(ctx);
|
|
57
|
+
expect(diags).toHaveLength(1);
|
|
58
|
+
expect(diags[0].message).toContain("memory");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
4
|
+
import { whm406 } from "./whm406";
|
|
5
|
+
|
|
6
|
+
function makeCtx(files: Record<string, string>): PostSynthContext {
|
|
7
|
+
const result: SerializerResult = { primary: files["Chart.yaml"] ?? "", files };
|
|
8
|
+
const outputs = new Map<string, string | SerializerResult>();
|
|
9
|
+
outputs.set("helm", result);
|
|
10
|
+
return {
|
|
11
|
+
outputs,
|
|
12
|
+
entities: new Map(),
|
|
13
|
+
buildResult: {
|
|
14
|
+
outputs,
|
|
15
|
+
entities: new Map(),
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
sourceFileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("WHM406: CRD lifecycle", () => {
|
|
24
|
+
test("info when crds/ directory exists", () => {
|
|
25
|
+
const ctx = makeCtx({
|
|
26
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
27
|
+
"crds/my-crd.yaml": "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\n",
|
|
28
|
+
});
|
|
29
|
+
const diags = whm406.check(ctx);
|
|
30
|
+
expect(diags).toHaveLength(1);
|
|
31
|
+
expect(diags[0].checkId).toBe("WHM406");
|
|
32
|
+
expect(diags[0].severity).toBe("info");
|
|
33
|
+
expect(diags[0].message).toContain("CRD");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("passes without crds/ directory", () => {
|
|
37
|
+
const ctx = makeCtx({
|
|
38
|
+
"Chart.yaml": "apiVersion: v2\nname: test\nversion: 0.1.0\n",
|
|
39
|
+
"templates/deploy.yaml": "kind: Deployment\n",
|
|
40
|
+
});
|
|
41
|
+
expect(whm406.check(ctx)).toHaveLength(0);
|
|
42
|
+
});
|
|
43
|
+
});
|