@intentius/chant-lexicon-k8s 0.49.0 → 0.50.0
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/composites/index.d.ts +2 -0
- package/dist/composites/index.d.ts.map +1 -1
- package/dist/composites/operator-stack.d.ts +183 -0
- package/dist/composites/operator-stack.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +35 -35
- package/dist/lint/post-synth/argo-helpers.d.ts.map +1 -1
- package/dist/lint/post-synth/crd-schema-helpers.d.ts.map +1 -1
- package/dist/lint/post-synth/k8s-helpers.d.ts +28 -5
- package/dist/lint/post-synth/k8s-helpers.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8005.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8006.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8041.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8042.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8101.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8102.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8103.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8104.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8105.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8201.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8202.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8203.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8204.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8205.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8207.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8208.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8209.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8301.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8302.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8303.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8304.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8305.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8306.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8401.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8402.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8403.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8404.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8405.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8406.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8407.d.ts.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/op/builders.d.ts +69 -0
- package/dist/op/builders.d.ts.map +1 -0
- package/dist/rules/argo-helpers.ts +2 -6
- package/dist/rules/crd-schema-helpers.ts +4 -6
- package/dist/rules/k8s-helpers.ts +32 -23
- package/dist/rules/wk8005.ts +27 -32
- package/dist/rules/wk8006.ts +33 -38
- package/dist/rules/wk8041.ts +19 -24
- package/dist/rules/wk8042.ts +17 -22
- package/dist/rules/wk8101.ts +29 -34
- package/dist/rules/wk8102.ts +13 -18
- package/dist/rules/wk8103.ts +17 -22
- package/dist/rules/wk8104.ts +30 -35
- package/dist/rules/wk8105.ts +16 -21
- package/dist/rules/wk8201.ts +26 -31
- package/dist/rules/wk8202.ts +17 -22
- package/dist/rules/wk8203.ts +17 -22
- package/dist/rules/wk8204.ts +46 -51
- package/dist/rules/wk8205.ts +27 -32
- package/dist/rules/wk8207.ts +14 -19
- package/dist/rules/wk8208.ts +14 -19
- package/dist/rules/wk8209.ts +14 -19
- package/dist/rules/wk8301.ts +25 -30
- package/dist/rules/wk8302.ts +19 -24
- package/dist/rules/wk8303.ts +23 -26
- package/dist/rules/wk8304.ts +35 -40
- package/dist/rules/wk8305.ts +39 -42
- package/dist/rules/wk8306.ts +20 -25
- package/dist/rules/wk8401.ts +59 -64
- package/dist/rules/wk8402.ts +13 -18
- package/dist/rules/wk8403.ts +32 -37
- package/dist/rules/wk8404.ts +15 -21
- package/dist/rules/wk8405.ts +15 -18
- package/dist/rules/wk8406.ts +29 -34
- package/dist/rules/wk8407.ts +17 -22
- package/dist/serializer.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/composites/composites.test.ts +283 -0
- package/src/composites/index.ts +4 -0
- package/src/composites/operator-stack.ts +385 -0
- package/src/index.ts +11 -0
- package/src/lint/post-synth/argo-helpers.ts +2 -6
- package/src/lint/post-synth/crd-schema-helpers.ts +4 -6
- package/src/lint/post-synth/k8s-helpers.test.ts +26 -9
- package/src/lint/post-synth/k8s-helpers.ts +32 -23
- package/src/lint/post-synth/wk8005.ts +27 -32
- package/src/lint/post-synth/wk8006.ts +33 -38
- package/src/lint/post-synth/wk8041.ts +19 -24
- package/src/lint/post-synth/wk8042.ts +17 -22
- package/src/lint/post-synth/wk8101.ts +29 -34
- package/src/lint/post-synth/wk8102.ts +13 -18
- package/src/lint/post-synth/wk8103.ts +17 -22
- package/src/lint/post-synth/wk8104.ts +30 -35
- package/src/lint/post-synth/wk8105.ts +16 -21
- package/src/lint/post-synth/wk8201.ts +26 -31
- package/src/lint/post-synth/wk8202.ts +17 -22
- package/src/lint/post-synth/wk8203.ts +17 -22
- package/src/lint/post-synth/wk8204.ts +46 -51
- package/src/lint/post-synth/wk8205.ts +27 -32
- package/src/lint/post-synth/wk8207.ts +14 -19
- package/src/lint/post-synth/wk8208.ts +14 -19
- package/src/lint/post-synth/wk8209.ts +14 -19
- package/src/lint/post-synth/wk8301.ts +25 -30
- package/src/lint/post-synth/wk8302.ts +19 -24
- package/src/lint/post-synth/wk8303.ts +23 -26
- package/src/lint/post-synth/wk8304.ts +35 -40
- package/src/lint/post-synth/wk8305.ts +39 -42
- package/src/lint/post-synth/wk8306.ts +20 -25
- package/src/lint/post-synth/wk8401.ts +59 -64
- package/src/lint/post-synth/wk8402.ts +13 -18
- package/src/lint/post-synth/wk8403.ts +32 -37
- package/src/lint/post-synth/wk8404.ts +15 -21
- package/src/lint/post-synth/wk8405.ts +15 -18
- package/src/lint/post-synth/wk8406.ts +29 -34
- package/src/lint/post-synth/wk8407.ts +17 -22
- package/src/op/builders.test.ts +82 -0
- package/src/op/builders.ts +95 -0
- package/src/serializer.ts +9 -1
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
10
|
-
import {
|
|
10
|
+
import { docsToManifests, extractContainers, WORKLOAD_KINDS } from "./k8s-helpers";
|
|
11
11
|
|
|
12
12
|
const SENSITIVE_NAME_PATTERN = /password|token|key|secret/i;
|
|
13
13
|
|
|
@@ -18,37 +18,32 @@ export const wk8005: PostSynthCheck = {
|
|
|
18
18
|
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
19
19
|
const diagnostics: PostSynthDiagnostic[] = [];
|
|
20
20
|
|
|
21
|
-
for (const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" has hardcoded value for sensitive env var "${envVar.name}" — use secretKeyRef instead`,
|
|
48
|
-
entity: resourceName,
|
|
49
|
-
lexicon: "k8s",
|
|
50
|
-
});
|
|
51
|
-
}
|
|
21
|
+
for (const manifest of docsToManifests(ctx)) {
|
|
22
|
+
if (!manifest.kind || !WORKLOAD_KINDS.has(manifest.kind)) continue;
|
|
23
|
+
|
|
24
|
+
const containers = extractContainers(manifest);
|
|
25
|
+
const resourceName = manifest.metadata?.name ?? manifest.kind;
|
|
26
|
+
|
|
27
|
+
for (const container of containers) {
|
|
28
|
+
if (!Array.isArray(container.env)) continue;
|
|
29
|
+
|
|
30
|
+
for (const envVar of container.env) {
|
|
31
|
+
if (
|
|
32
|
+
typeof envVar.name === "string" &&
|
|
33
|
+
SENSITIVE_NAME_PATTERN.test(envVar.name) &&
|
|
34
|
+
envVar.value !== undefined &&
|
|
35
|
+
envVar.value !== null &&
|
|
36
|
+
typeof envVar.value === "string" &&
|
|
37
|
+
envVar.value !== "" &&
|
|
38
|
+
!envVar.valueFrom
|
|
39
|
+
) {
|
|
40
|
+
diagnostics.push({
|
|
41
|
+
checkId: "WK8005",
|
|
42
|
+
severity: "error",
|
|
43
|
+
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" has hardcoded value for sensitive env var "${envVar.name}" — use secretKeyRef instead`,
|
|
44
|
+
entity: resourceName,
|
|
45
|
+
lexicon: "k8s",
|
|
46
|
+
});
|
|
52
47
|
}
|
|
53
48
|
}
|
|
54
49
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
9
|
-
import {
|
|
9
|
+
import { docsToManifests, extractContainers, WORKLOAD_KINDS } from "./k8s-helpers";
|
|
10
10
|
|
|
11
11
|
export const wk8006: PostSynthCheck = {
|
|
12
12
|
id: "WK8006",
|
|
@@ -15,49 +15,44 @@ export const wk8006: PostSynthCheck = {
|
|
|
15
15
|
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
16
16
|
const diagnostics: PostSynthDiagnostic[] = [];
|
|
17
17
|
|
|
18
|
-
for (const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
18
|
+
for (const manifest of docsToManifests(ctx)) {
|
|
19
|
+
if (!manifest.kind || !WORKLOAD_KINDS.has(manifest.kind)) continue;
|
|
20
|
+
|
|
21
|
+
const containers = extractContainers(manifest);
|
|
22
|
+
const resourceName = manifest.metadata?.name ?? manifest.kind;
|
|
23
|
+
|
|
24
|
+
for (const container of containers) {
|
|
25
|
+
const image = container.image;
|
|
26
|
+
if (typeof image !== "string" || image === "") continue;
|
|
27
|
+
|
|
28
|
+
// Split off digest (@sha256:...) — those are pinned and fine
|
|
29
|
+
if (image.includes("@")) continue;
|
|
30
|
+
|
|
31
|
+
// Extract the tag portion (after the last colon that isn't part of a port)
|
|
32
|
+
// Images can be: name, name:tag, registry:port/name, registry:port/name:tag
|
|
33
|
+
const slashIndex = image.lastIndexOf("/");
|
|
34
|
+
const afterSlash = slashIndex >= 0 ? image.slice(slashIndex + 1) : image;
|
|
35
|
+
const colonIndex = afterSlash.lastIndexOf(":");
|
|
36
|
+
|
|
37
|
+
if (colonIndex === -1) {
|
|
38
|
+
// No tag at all
|
|
39
|
+
diagnostics.push({
|
|
40
|
+
checkId: "WK8006",
|
|
41
|
+
severity: "warning",
|
|
42
|
+
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" uses untagged image "${image}" — specify an explicit version tag`,
|
|
43
|
+
entity: resourceName,
|
|
44
|
+
lexicon: "k8s",
|
|
45
|
+
});
|
|
46
|
+
} else {
|
|
47
|
+
const tag = afterSlash.slice(colonIndex + 1);
|
|
48
|
+
if (tag === "latest") {
|
|
43
49
|
diagnostics.push({
|
|
44
50
|
checkId: "WK8006",
|
|
45
51
|
severity: "warning",
|
|
46
|
-
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" uses
|
|
52
|
+
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" uses :latest tag on image "${image}" — use a specific version tag`,
|
|
47
53
|
entity: resourceName,
|
|
48
54
|
lexicon: "k8s",
|
|
49
55
|
});
|
|
50
|
-
} else {
|
|
51
|
-
const tag = afterSlash.slice(colonIndex + 1);
|
|
52
|
-
if (tag === "latest") {
|
|
53
|
-
diagnostics.push({
|
|
54
|
-
checkId: "WK8006",
|
|
55
|
-
severity: "warning",
|
|
56
|
-
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" uses :latest tag on image "${image}" — use a specific version tag`,
|
|
57
|
-
entity: resourceName,
|
|
58
|
-
lexicon: "k8s",
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
56
|
}
|
|
62
57
|
}
|
|
63
58
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
10
|
-
import {
|
|
10
|
+
import { docsToManifests, extractContainers, WORKLOAD_KINDS } from "./k8s-helpers";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Known API key patterns and their descriptions.
|
|
@@ -35,33 +35,28 @@ export const wk8041: PostSynthCheck = {
|
|
|
35
35
|
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
36
36
|
const diagnostics: PostSynthDiagnostic[] = [];
|
|
37
37
|
|
|
38
|
-
for (const
|
|
39
|
-
|
|
40
|
-
const manifests = parseK8sManifests(yaml);
|
|
38
|
+
for (const manifest of docsToManifests(ctx)) {
|
|
39
|
+
if (!manifest.kind || !WORKLOAD_KINDS.has(manifest.kind)) continue;
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
const containers = extractContainers(manifest);
|
|
42
|
+
const resourceName = manifest.metadata?.name ?? manifest.kind;
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
for (const container of containers) {
|
|
45
|
+
if (!Array.isArray(container.env)) continue;
|
|
47
46
|
|
|
48
|
-
for (const
|
|
49
|
-
if (
|
|
47
|
+
for (const envVar of container.env) {
|
|
48
|
+
if (typeof envVar.value !== "string" || envVar.value === "") continue;
|
|
50
49
|
|
|
51
|
-
for (const
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
lexicon: "k8s",
|
|
62
|
-
});
|
|
63
|
-
break; // One match per env var is sufficient
|
|
64
|
-
}
|
|
50
|
+
for (const { pattern, label } of API_KEY_PATTERNS) {
|
|
51
|
+
if (pattern.test(envVar.value)) {
|
|
52
|
+
diagnostics.push({
|
|
53
|
+
checkId: "WK8041",
|
|
54
|
+
severity: "error",
|
|
55
|
+
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" has a ${label} hardcoded in env var "${envVar.name ?? "(unnamed)"}" — use a Secret reference instead`,
|
|
56
|
+
entity: resourceName,
|
|
57
|
+
lexicon: "k8s",
|
|
58
|
+
});
|
|
59
|
+
break; // One match per env var is sufficient
|
|
65
60
|
}
|
|
66
61
|
}
|
|
67
62
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
10
|
-
import {
|
|
10
|
+
import { docsToManifests } from "./k8s-helpers";
|
|
11
11
|
|
|
12
12
|
const PRIVATE_KEY_PATTERN = /-----BEGIN\s+[\w\s]*PRIVATE KEY-----/;
|
|
13
13
|
|
|
@@ -18,27 +18,22 @@ export const wk8042: PostSynthCheck = {
|
|
|
18
18
|
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
19
19
|
const diagnostics: PostSynthDiagnostic[] = [];
|
|
20
20
|
|
|
21
|
-
for (const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
message: `ConfigMap "${resourceName}" contains a private key in data field "${key}" — use a Secret resource instead`,
|
|
38
|
-
entity: resourceName,
|
|
39
|
-
lexicon: "k8s",
|
|
40
|
-
});
|
|
41
|
-
}
|
|
21
|
+
for (const manifest of docsToManifests(ctx)) {
|
|
22
|
+
if (manifest.kind !== "ConfigMap") continue;
|
|
23
|
+
|
|
24
|
+
const resourceName = manifest.metadata?.name ?? "ConfigMap";
|
|
25
|
+
const data = manifest.data;
|
|
26
|
+
if (typeof data !== "object" || data === null) continue;
|
|
27
|
+
|
|
28
|
+
for (const [key, value] of Object.entries(data)) {
|
|
29
|
+
if (typeof value === "string" && PRIVATE_KEY_PATTERN.test(value)) {
|
|
30
|
+
diagnostics.push({
|
|
31
|
+
checkId: "WK8042",
|
|
32
|
+
severity: "error",
|
|
33
|
+
message: `ConfigMap "${resourceName}" contains a private key in data field "${key}" — use a Secret resource instead`,
|
|
34
|
+
entity: resourceName,
|
|
35
|
+
lexicon: "k8s",
|
|
36
|
+
});
|
|
42
37
|
}
|
|
43
38
|
}
|
|
44
39
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
10
|
-
import {
|
|
10
|
+
import { docsToManifests } from "./k8s-helpers";
|
|
11
11
|
|
|
12
12
|
export const wk8101: PostSynthCheck = {
|
|
13
13
|
id: "WK8101",
|
|
@@ -16,46 +16,41 @@ export const wk8101: PostSynthCheck = {
|
|
|
16
16
|
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
17
17
|
const diagnostics: PostSynthDiagnostic[] = [];
|
|
18
18
|
|
|
19
|
-
for (const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
19
|
+
for (const manifest of docsToManifests(ctx)) {
|
|
20
|
+
if (manifest.kind !== "Deployment") continue;
|
|
21
|
+
|
|
22
|
+
const resourceName = manifest.metadata?.name ?? "Deployment";
|
|
23
|
+
const spec = manifest.spec;
|
|
24
|
+
if (!spec) continue;
|
|
25
|
+
|
|
26
|
+
const selector = spec.selector as Record<string, unknown> | undefined;
|
|
27
|
+
const matchLabels = selector?.matchLabels as Record<string, string> | undefined;
|
|
28
|
+
if (!matchLabels || typeof matchLabels !== "object") continue;
|
|
29
|
+
|
|
30
|
+
const template = spec.template as Record<string, unknown> | undefined;
|
|
31
|
+
const templateMetadata = template?.metadata as Record<string, unknown> | undefined;
|
|
32
|
+
const templateLabels = templateMetadata?.labels as Record<string, string> | undefined;
|
|
33
|
+
|
|
34
|
+
if (!templateLabels || typeof templateLabels !== "object") {
|
|
35
|
+
diagnostics.push({
|
|
36
|
+
checkId: "WK8101",
|
|
37
|
+
severity: "error",
|
|
38
|
+
message: `Deployment "${resourceName}" has spec.selector.matchLabels but no spec.template.metadata.labels`,
|
|
39
|
+
entity: resourceName,
|
|
40
|
+
lexicon: "k8s",
|
|
41
|
+
});
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
for (const [key, value] of Object.entries(matchLabels)) {
|
|
46
|
+
if (templateLabels[key] !== value) {
|
|
39
47
|
diagnostics.push({
|
|
40
48
|
checkId: "WK8101",
|
|
41
49
|
severity: "error",
|
|
42
|
-
message: `Deployment "${resourceName}"
|
|
50
|
+
message: `Deployment "${resourceName}" selector label "${key}=${value}" does not match template label "${key}=${templateLabels[key] ?? '(missing)'}"`,
|
|
43
51
|
entity: resourceName,
|
|
44
52
|
lexicon: "k8s",
|
|
45
53
|
});
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
for (const [key, value] of Object.entries(matchLabels)) {
|
|
50
|
-
if (templateLabels[key] !== value) {
|
|
51
|
-
diagnostics.push({
|
|
52
|
-
checkId: "WK8101",
|
|
53
|
-
severity: "error",
|
|
54
|
-
message: `Deployment "${resourceName}" selector label "${key}=${value}" does not match template label "${key}=${templateLabels[key] ?? '(missing)'}"`,
|
|
55
|
-
entity: resourceName,
|
|
56
|
-
lexicon: "k8s",
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
54
|
}
|
|
60
55
|
}
|
|
61
56
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
9
|
-
import {
|
|
9
|
+
import { docsToManifests } from "./k8s-helpers";
|
|
10
10
|
|
|
11
11
|
export const wk8102: PostSynthCheck = {
|
|
12
12
|
id: "WK8102",
|
|
@@ -15,25 +15,20 @@ export const wk8102: PostSynthCheck = {
|
|
|
15
15
|
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
16
16
|
const diagnostics: PostSynthDiagnostic[] = [];
|
|
17
17
|
|
|
18
|
-
for (const
|
|
19
|
-
|
|
20
|
-
const manifests = parseK8sManifests(yaml);
|
|
18
|
+
for (const manifest of docsToManifests(ctx)) {
|
|
19
|
+
if (!manifest.kind || !manifest.metadata) continue;
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const resourceName = manifest.metadata.name ?? manifest.kind;
|
|
22
|
+
const labels = manifest.metadata.labels;
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
entity: resourceName,
|
|
34
|
-
lexicon: "k8s",
|
|
35
|
-
});
|
|
36
|
-
}
|
|
24
|
+
if (!labels || typeof labels !== "object" || Object.keys(labels).length === 0) {
|
|
25
|
+
diagnostics.push({
|
|
26
|
+
checkId: "WK8102",
|
|
27
|
+
severity: "warning",
|
|
28
|
+
message: `${manifest.kind} "${resourceName}" has no metadata.labels — add labels for organizational purposes`,
|
|
29
|
+
entity: resourceName,
|
|
30
|
+
lexicon: "k8s",
|
|
31
|
+
});
|
|
37
32
|
}
|
|
38
33
|
}
|
|
39
34
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
9
|
-
import {
|
|
9
|
+
import { docsToManifests, extractContainers, WORKLOAD_KINDS } from "./k8s-helpers";
|
|
10
10
|
|
|
11
11
|
export const wk8103: PostSynthCheck = {
|
|
12
12
|
id: "WK8103",
|
|
@@ -15,27 +15,22 @@ export const wk8103: PostSynthCheck = {
|
|
|
15
15
|
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
16
16
|
const diagnostics: PostSynthDiagnostic[] = [];
|
|
17
17
|
|
|
18
|
-
for (const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
message: `${manifest.kind} "${resourceName}" has a container at index ${i} without a name — the name field is required`,
|
|
35
|
-
entity: resourceName,
|
|
36
|
-
lexicon: "k8s",
|
|
37
|
-
});
|
|
38
|
-
}
|
|
18
|
+
for (const manifest of docsToManifests(ctx)) {
|
|
19
|
+
if (!manifest.kind || !WORKLOAD_KINDS.has(manifest.kind)) continue;
|
|
20
|
+
|
|
21
|
+
const containers = extractContainers(manifest);
|
|
22
|
+
const resourceName = manifest.metadata?.name ?? manifest.kind;
|
|
23
|
+
|
|
24
|
+
for (let i = 0; i < containers.length; i++) {
|
|
25
|
+
const container = containers[i];
|
|
26
|
+
if (!container.name || typeof container.name !== "string" || container.name.trim() === "") {
|
|
27
|
+
diagnostics.push({
|
|
28
|
+
checkId: "WK8103",
|
|
29
|
+
severity: "error",
|
|
30
|
+
message: `${manifest.kind} "${resourceName}" has a container at index ${i} without a name — the name field is required`,
|
|
31
|
+
entity: resourceName,
|
|
32
|
+
lexicon: "k8s",
|
|
33
|
+
});
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
36
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
10
|
-
import {
|
|
10
|
+
import { docsToManifests, extractContainers, WORKLOAD_KINDS } from "./k8s-helpers";
|
|
11
11
|
|
|
12
12
|
export const wk8104: PostSynthCheck = {
|
|
13
13
|
id: "WK8104",
|
|
@@ -16,45 +16,20 @@ export const wk8104: PostSynthCheck = {
|
|
|
16
16
|
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
17
17
|
const diagnostics: PostSynthDiagnostic[] = [];
|
|
18
18
|
|
|
19
|
-
for (const
|
|
20
|
-
const
|
|
21
|
-
const manifests = parseK8sManifests(yaml);
|
|
19
|
+
for (const manifest of docsToManifests(ctx)) {
|
|
20
|
+
const resourceName = manifest.metadata?.name ?? manifest.kind ?? "(unknown)";
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
for (const container of containers) {
|
|
30
|
-
if (!Array.isArray(container.ports)) continue;
|
|
31
|
-
for (const port of container.ports) {
|
|
32
|
-
if (typeof port === "object" && port !== null && !port.name) {
|
|
33
|
-
diagnostics.push({
|
|
34
|
-
checkId: "WK8104",
|
|
35
|
-
severity: "warning",
|
|
36
|
-
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" has an unnamed port (containerPort: ${port.containerPort ?? "?"}) — add a name for clarity`,
|
|
37
|
-
entity: resourceName,
|
|
38
|
-
lexicon: "k8s",
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Check Service ports
|
|
46
|
-
if (manifest.kind === "Service") {
|
|
47
|
-
const spec = manifest.spec;
|
|
48
|
-
if (!spec) continue;
|
|
49
|
-
const ports = spec.ports as Array<Record<string, unknown>> | undefined;
|
|
50
|
-
if (!Array.isArray(ports)) continue;
|
|
51
|
-
|
|
52
|
-
for (const port of ports) {
|
|
22
|
+
// Check container ports in workloads
|
|
23
|
+
if (manifest.kind && WORKLOAD_KINDS.has(manifest.kind)) {
|
|
24
|
+
const containers = extractContainers(manifest);
|
|
25
|
+
for (const container of containers) {
|
|
26
|
+
if (!Array.isArray(container.ports)) continue;
|
|
27
|
+
for (const port of container.ports) {
|
|
53
28
|
if (typeof port === "object" && port !== null && !port.name) {
|
|
54
29
|
diagnostics.push({
|
|
55
30
|
checkId: "WK8104",
|
|
56
31
|
severity: "warning",
|
|
57
|
-
message: `
|
|
32
|
+
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" has an unnamed port (containerPort: ${port.containerPort ?? "?"}) — add a name for clarity`,
|
|
58
33
|
entity: resourceName,
|
|
59
34
|
lexicon: "k8s",
|
|
60
35
|
});
|
|
@@ -62,6 +37,26 @@ export const wk8104: PostSynthCheck = {
|
|
|
62
37
|
}
|
|
63
38
|
}
|
|
64
39
|
}
|
|
40
|
+
|
|
41
|
+
// Check Service ports
|
|
42
|
+
if (manifest.kind === "Service") {
|
|
43
|
+
const spec = manifest.spec;
|
|
44
|
+
if (!spec) continue;
|
|
45
|
+
const ports = spec.ports as Array<Record<string, unknown>> | undefined;
|
|
46
|
+
if (!Array.isArray(ports)) continue;
|
|
47
|
+
|
|
48
|
+
for (const port of ports) {
|
|
49
|
+
if (typeof port === "object" && port !== null && !port.name) {
|
|
50
|
+
diagnostics.push({
|
|
51
|
+
checkId: "WK8104",
|
|
52
|
+
severity: "warning",
|
|
53
|
+
message: `Service "${resourceName}" has an unnamed port (port: ${port.port ?? "?"}) — add a name for clarity`,
|
|
54
|
+
entity: resourceName,
|
|
55
|
+
lexicon: "k8s",
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
65
60
|
}
|
|
66
61
|
|
|
67
62
|
return diagnostics;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
10
|
-
import {
|
|
10
|
+
import { docsToManifests, extractContainers, WORKLOAD_KINDS } from "./k8s-helpers";
|
|
11
11
|
|
|
12
12
|
export const wk8105: PostSynthCheck = {
|
|
13
13
|
id: "WK8105",
|
|
@@ -16,26 +16,21 @@ export const wk8105: PostSynthCheck = {
|
|
|
16
16
|
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
17
17
|
const diagnostics: PostSynthDiagnostic[] = [];
|
|
18
18
|
|
|
19
|
-
for (const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" has no explicit imagePullPolicy — set it to "Always", "IfNotPresent", or "Never"`,
|
|
35
|
-
entity: resourceName,
|
|
36
|
-
lexicon: "k8s",
|
|
37
|
-
});
|
|
38
|
-
}
|
|
19
|
+
for (const manifest of docsToManifests(ctx)) {
|
|
20
|
+
if (!manifest.kind || !WORKLOAD_KINDS.has(manifest.kind)) continue;
|
|
21
|
+
|
|
22
|
+
const containers = extractContainers(manifest);
|
|
23
|
+
const resourceName = manifest.metadata?.name ?? manifest.kind;
|
|
24
|
+
|
|
25
|
+
for (const container of containers) {
|
|
26
|
+
if (!container.imagePullPolicy) {
|
|
27
|
+
diagnostics.push({
|
|
28
|
+
checkId: "WK8105",
|
|
29
|
+
severity: "warning",
|
|
30
|
+
message: `Container "${container.name ?? "(unnamed)"}" in ${manifest.kind} "${resourceName}" has no explicit imagePullPolicy — set it to "Always", "IfNotPresent", or "Never"`,
|
|
31
|
+
entity: resourceName,
|
|
32
|
+
lexicon: "k8s",
|
|
33
|
+
});
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
36
|
}
|