@intentius/chant-lexicon-k8s 0.44.13 → 0.45.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/codegen/docs.d.ts.map +1 -1
- package/dist/codegen/generate-lexicon.d.ts +15 -1
- package/dist/codegen/generate-lexicon.d.ts.map +1 -1
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/crd/parser.d.ts +28 -1
- package/dist/crd/parser.d.ts.map +1 -1
- package/dist/deep-observe-hooks.d.ts +60 -4
- package/dist/deep-observe-hooks.d.ts.map +1 -1
- package/dist/deep-observe.d.ts +36 -61
- package/dist/deep-observe.d.ts.map +1 -1
- package/dist/integrity.json +6 -3
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/post-synth/crd-schema-helpers.d.ts +49 -0
- package/dist/lint/post-synth/crd-schema-helpers.d.ts.map +1 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/wk8501.d.ts +14 -0
- package/dist/lint/post-synth/wk8501.d.ts.map +1 -0
- package/dist/lint/post-synth/wk8502.d.ts +13 -0
- package/dist/lint/post-synth/wk8502.d.ts.map +1 -0
- package/dist/manifest.json +1 -1
- package/dist/meta.json +126 -63
- package/dist/okf/index.md +2 -0
- package/dist/okf/rules/WK8501.md +11 -0
- package/dist/okf/rules/WK8502.md +11 -0
- package/dist/rules/crd-schema-helpers.ts +228 -0
- package/dist/rules/wk8501.ts +40 -0
- package/dist/rules/wk8502.ts +39 -0
- package/dist/spec/parse.d.ts +32 -0
- package/dist/spec/parse.d.ts.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/codegen/docs.ts +0 -1044
- package/src/codegen/generate-lexicon.ts +38 -2
- package/src/codegen/snapshot.test.ts +20 -0
- package/src/components/capability-plugin.test.ts +20 -0
- package/src/components/capability-plugin.ts +5 -2
- package/src/crd/cnpg.test.ts +1 -1
- package/src/crd/infisical.test.ts +1 -1
- package/src/crd/parser.test.ts +117 -1
- package/src/crd/parser.ts +71 -5
- package/src/crd/traefik.test.ts +1 -1
- package/src/deep-observe-hooks.ts +78 -16
- package/src/deep-observe.test.ts +145 -29
- package/src/deep-observe.ts +43 -85
- package/src/generated/lexicon-k8s.json +126 -63
- package/src/lint/audit-catalog.ts +2 -0
- package/src/lint/post-synth/crd-schema-helpers.ts +228 -0
- package/src/lint/post-synth/index.ts +4 -0
- package/src/lint/post-synth/post-synth.test.ts +156 -0
- package/src/lint/post-synth/wk8501.ts +40 -0
- package/src/lint/post-synth/wk8502.ts +39 -0
- package/src/list-map-key-table.test.ts +83 -0
- package/src/op/activities/kubectl.ts +2 -2
- package/src/serializer.test.ts +4 -4
- package/src/spec/parse.ts +33 -0
- package/src/validate.ts +7 -4
package/dist/okf/index.md
CHANGED
|
@@ -254,3 +254,5 @@ okf_version: '0.2'
|
|
|
254
254
|
* [WK8401](/rules/WK8401.md) - shmSize must not exceed the container memory limit — pod will not schedule if it does
|
|
255
255
|
* [WK8402](/rules/WK8402.md) - RayCluster should set spec.rayVersion so KubeRay selects the correct autoscaler image
|
|
256
256
|
* [WK8403](/rules/WK8403.md) - spec.rayVersion should match the Ray version in the head container image tag
|
|
257
|
+
* [WK8501](/rules/WK8501.md) - Custom resource spec contains a field its CRD schema does not declare
|
|
258
|
+
* [WK8502](/rules/WK8502.md) - Custom resource spec field has the wrong type or a value outside its enum
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: post-synth-check
|
|
3
|
+
title: WK8501
|
|
4
|
+
description: Custom resource spec contains a field its CRD schema does not declare
|
|
5
|
+
id: WK8501
|
|
6
|
+
severity: error
|
|
7
|
+
category: post-synth
|
|
8
|
+
lexicon: k8s
|
|
9
|
+
docs: https://intentius.io/chant/lexicons/k8s/rules/
|
|
10
|
+
---
|
|
11
|
+
Custom resource spec contains a field its CRD schema does not declare
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: post-synth-check
|
|
3
|
+
title: WK8502
|
|
4
|
+
description: Custom resource spec field has the wrong type or a value outside its enum
|
|
5
|
+
id: WK8502
|
|
6
|
+
severity: error
|
|
7
|
+
category: post-synth
|
|
8
|
+
lexicon: k8s
|
|
9
|
+
docs: https://intentius.io/chant/lexicons/k8s/rules/
|
|
10
|
+
---
|
|
11
|
+
Custom resource spec field has the wrong type or a value outside its enum
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the custom-resource spec checks (WK8501, WK8502) — chant #1372.
|
|
3
|
+
*
|
|
4
|
+
* A CRD's constructor takes `spec: Record<string, unknown>`, so a misspelled
|
|
5
|
+
* or wrong-typed field type-checks, serializes, and is accepted by the API
|
|
6
|
+
* server (which prunes what the structural schema does not know) — the
|
|
7
|
+
* controller then runs with a default nobody chose. The generated lexicon JSON
|
|
8
|
+
* carries each CRD's `spec` field schema (`specSchema`); these helpers walk a
|
|
9
|
+
* synthesized manifest against it and report what the schema would reject.
|
|
10
|
+
*
|
|
11
|
+
* Excluded from check auto-discovery by the "helper" filename filter.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { createRequire } from "module";
|
|
15
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
16
|
+
import type { CrdFieldSchema } from "../../spec/parse";
|
|
17
|
+
import { getPrimaryOutput, parseK8sManifests, type K8sManifest } from "./k8s-helpers";
|
|
18
|
+
|
|
19
|
+
export type { CrdFieldSchema };
|
|
20
|
+
|
|
21
|
+
interface LexiconEntry {
|
|
22
|
+
kind: "resource" | "property";
|
|
23
|
+
apiVersion?: string;
|
|
24
|
+
gvkKind?: string;
|
|
25
|
+
specSchema?: CrdFieldSchema;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let cachedRegistry: Map<string, CrdFieldSchema> | null = null;
|
|
29
|
+
|
|
30
|
+
/** Registry key: `<apiVersion>/<kind>`, the pair a manifest carries verbatim. */
|
|
31
|
+
function registryKey(apiVersion: string, kind: string): string {
|
|
32
|
+
return `${apiVersion}/${kind}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Spec schemas of every CRD the lexicon ships, keyed by `apiVersion/kind`.
|
|
37
|
+
* Built-in kinds carry no `specSchema` and are never in the map.
|
|
38
|
+
*/
|
|
39
|
+
export function getCrdSchemaRegistry(): Map<string, CrdFieldSchema> {
|
|
40
|
+
if (cachedRegistry) return cachedRegistry;
|
|
41
|
+
cachedRegistry = new Map();
|
|
42
|
+
try {
|
|
43
|
+
// Built lazily so importing this module stays edge-safe: `createRequire`
|
|
44
|
+
// throws where import.meta.url is undefined (bundled Workers), and there
|
|
45
|
+
// the registry is simply empty.
|
|
46
|
+
const require = createRequire(import.meta.url);
|
|
47
|
+
const lexicon = require("../../generated/lexicon-k8s.json") as Record<string, LexiconEntry>;
|
|
48
|
+
for (const entry of Object.values(lexicon)) {
|
|
49
|
+
if (entry.kind === "resource" && entry.apiVersion && entry.gvkKind && entry.specSchema) {
|
|
50
|
+
cachedRegistry.set(registryKey(entry.apiVersion, entry.gvkKind), entry.specSchema);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
// Lexicon JSON not yet generated — empty registry, checks pass.
|
|
55
|
+
}
|
|
56
|
+
return cachedRegistry;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Test seam: replace the registry (pass `null` to reload from the lexicon JSON). */
|
|
60
|
+
export function setCrdSchemaRegistry(registry: Map<string, CrdFieldSchema> | null): void {
|
|
61
|
+
cachedRegistry = registry;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The schema for a manifest's `apiVersion`/`kind`, if the lexicon ships one. */
|
|
65
|
+
export function specSchemaFor(manifest: K8sManifest): CrdFieldSchema | undefined {
|
|
66
|
+
if (typeof manifest.apiVersion !== "string" || typeof manifest.kind !== "string") return undefined;
|
|
67
|
+
return getCrdSchemaRegistry().get(registryKey(manifest.apiVersion, manifest.kind));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Every manifest in the build that has a shipped spec schema, with that schema. */
|
|
71
|
+
export function customResources(ctx: PostSynthContext): Array<{ manifest: K8sManifest; schema: CrdFieldSchema }> {
|
|
72
|
+
const out: Array<{ manifest: K8sManifest; schema: CrdFieldSchema }> = [];
|
|
73
|
+
for (const [, output] of ctx.outputs) {
|
|
74
|
+
for (const manifest of parseK8sManifests(getPrimaryOutput(output))) {
|
|
75
|
+
const schema = specSchemaFor(manifest);
|
|
76
|
+
if (schema) out.push({ manifest, schema });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface SpecFinding {
|
|
83
|
+
kind: "unknown-field" | "type-mismatch";
|
|
84
|
+
/** Dotted path under `spec`, e.g. `spec.source.s3bucket`. Array elements use `[i]`. */
|
|
85
|
+
path: string;
|
|
86
|
+
message: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Walk `value` against `schema` and report every field the schema does not
|
|
91
|
+
* list (unless the enclosing object is `open`) and every scalar whose type or
|
|
92
|
+
* enum membership the schema rejects. Untyped nodes pass anything.
|
|
93
|
+
*/
|
|
94
|
+
export function validateSpec(value: unknown, schema: CrdFieldSchema, path = "spec"): SpecFinding[] {
|
|
95
|
+
const findings: SpecFinding[] = [];
|
|
96
|
+
walk(value, schema, path, findings);
|
|
97
|
+
return findings;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function walk(value: unknown, schema: CrdFieldSchema, path: string, out: SpecFinding[]): void {
|
|
101
|
+
if (value === null || value === undefined) return;
|
|
102
|
+
|
|
103
|
+
// int-or-string and other deliberately untyped nodes accept anything.
|
|
104
|
+
if (!schema.type) return;
|
|
105
|
+
|
|
106
|
+
switch (schema.type) {
|
|
107
|
+
case "object": {
|
|
108
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
109
|
+
out.push(mismatch(path, "an object", value));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const obj = value as Record<string, unknown>;
|
|
113
|
+
for (const [name, child] of Object.entries(obj)) {
|
|
114
|
+
const childSchema = schema.fields?.[name];
|
|
115
|
+
if (childSchema) {
|
|
116
|
+
walk(child, childSchema, `${path}.${name}`, out);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (schema.open) continue;
|
|
120
|
+
const known = Object.keys(schema.fields ?? {});
|
|
121
|
+
const suggestion = suggestField(name, known);
|
|
122
|
+
const hint = suggestion ? ` (did you mean "${suggestion}"?)` : "";
|
|
123
|
+
out.push({
|
|
124
|
+
kind: "unknown-field",
|
|
125
|
+
path: `${path}.${name}`,
|
|
126
|
+
message: `unknown field "${path}.${name}"${hint}`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
case "array": {
|
|
132
|
+
if (!Array.isArray(value)) {
|
|
133
|
+
out.push(mismatch(path, "an array", value));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (schema.items) {
|
|
137
|
+
value.forEach((item, i) => walk(item, schema.items!, `${path}[${i}]`, out));
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
case "string": {
|
|
142
|
+
if (typeof value !== "string") {
|
|
143
|
+
// `x-kubernetes-int-or-string` never reaches here (untyped); a plain
|
|
144
|
+
// string field given a number is a real mismatch the server coerces
|
|
145
|
+
// or rejects depending on version, so say so.
|
|
146
|
+
out.push(mismatch(path, "a string", value));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
checkEnum(value, schema, path, out);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
case "integer":
|
|
153
|
+
case "number": {
|
|
154
|
+
if (typeof value !== "number" || (schema.type === "integer" && !Number.isInteger(value))) {
|
|
155
|
+
out.push(mismatch(path, schema.type === "integer" ? "an integer" : "a number", value));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
checkEnum(value, schema, path, out);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
case "boolean": {
|
|
162
|
+
if (typeof value !== "boolean") out.push(mismatch(path, "a boolean", value));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function checkEnum(value: string | number, schema: CrdFieldSchema, path: string, out: SpecFinding[]): void {
|
|
169
|
+
if (!schema.enum || schema.enum.length === 0) return;
|
|
170
|
+
if (schema.enum.includes(String(value))) return;
|
|
171
|
+
out.push({
|
|
172
|
+
kind: "type-mismatch",
|
|
173
|
+
path,
|
|
174
|
+
message: `"${path}" must be one of ${schema.enum.map((v) => `"${v}"`).join(", ")}, got ${describe(value)}`,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function mismatch(path: string, expected: string, value: unknown): SpecFinding {
|
|
179
|
+
return {
|
|
180
|
+
kind: "type-mismatch",
|
|
181
|
+
path,
|
|
182
|
+
message: `"${path}" expects ${expected}, got ${describe(value)}`,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function describe(value: unknown): string {
|
|
187
|
+
if (typeof value === "string") return `string "${value}"`;
|
|
188
|
+
if (typeof value === "number" || typeof value === "boolean") return `${typeof value} ${String(value)}`;
|
|
189
|
+
if (Array.isArray(value)) return "an array";
|
|
190
|
+
if (value !== null && typeof value === "object") return "an object";
|
|
191
|
+
return String(value);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Levenshtein distance between two strings. */
|
|
195
|
+
export function levenshtein(a: string, b: string): number {
|
|
196
|
+
const m = a.length;
|
|
197
|
+
const n = b.length;
|
|
198
|
+
const dp: number[][] = Array.from({ length: m + 1 }, () => Array<number>(n + 1).fill(0));
|
|
199
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
200
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
201
|
+
for (let i = 1; i <= m; i++) {
|
|
202
|
+
for (let j = 1; j <= n; j++) {
|
|
203
|
+
dp[i][j] = a[i - 1] === b[j - 1]
|
|
204
|
+
? dp[i - 1][j - 1]
|
|
205
|
+
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return dp[m][n];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Closest known field within Levenshtein distance 3 (case-insensitive), if any. */
|
|
212
|
+
export function suggestField(unknown: string, known: string[]): string | undefined {
|
|
213
|
+
let best: string | undefined;
|
|
214
|
+
let bestDist = 4;
|
|
215
|
+
for (const field of known) {
|
|
216
|
+
const dist = levenshtein(unknown.toLowerCase(), field.toLowerCase());
|
|
217
|
+
if (dist < bestDist) {
|
|
218
|
+
bestDist = dist;
|
|
219
|
+
best = field;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return best;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** `metadata.name` or the kind, for diagnostics. */
|
|
226
|
+
export function resourceLabel(manifest: K8sManifest): string {
|
|
227
|
+
return manifest.metadata?.name ?? manifest.kind ?? "resource";
|
|
228
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WK8501: Custom resource spec has a field its CRD schema does not declare
|
|
3
|
+
*
|
|
4
|
+
* A generated CRD class takes `spec: Record<string, unknown>`, so a misspelled
|
|
5
|
+
* field (`classname` for `className`) type-checks and serializes. The API
|
|
6
|
+
* server accepts the object and prunes the unknown field, the controller
|
|
7
|
+
* never sees it, and the resource runs with a default nobody chose. The
|
|
8
|
+
* lexicon ships each CRD's `spec` schema (chant #1372); this check flags any
|
|
9
|
+
* field that schema does not list, unless the enclosing object declares
|
|
10
|
+
* `x-kubernetes-preserve-unknown-fields` or `additionalProperties`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
14
|
+
import { customResources, resourceLabel, validateSpec } from "./crd-schema-helpers";
|
|
15
|
+
|
|
16
|
+
export const wk8501: PostSynthCheck = {
|
|
17
|
+
id: "WK8501",
|
|
18
|
+
description: "Custom resource spec contains a field its CRD schema does not declare",
|
|
19
|
+
|
|
20
|
+
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
21
|
+
const diagnostics: PostSynthDiagnostic[] = [];
|
|
22
|
+
|
|
23
|
+
for (const { manifest, schema } of customResources(ctx)) {
|
|
24
|
+
if (manifest.spec === undefined) continue;
|
|
25
|
+
const name = resourceLabel(manifest);
|
|
26
|
+
for (const finding of validateSpec(manifest.spec, schema)) {
|
|
27
|
+
if (finding.kind !== "unknown-field") continue;
|
|
28
|
+
diagnostics.push({
|
|
29
|
+
checkId: "WK8501",
|
|
30
|
+
severity: "error",
|
|
31
|
+
message: `${manifest.kind} "${name}": ${finding.message}. The API server prunes it and the controller never sees it.`,
|
|
32
|
+
entity: name,
|
|
33
|
+
lexicon: "k8s",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return diagnostics;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WK8502: Custom resource spec field has the wrong type or an invalid enum value
|
|
3
|
+
*
|
|
4
|
+
* With `spec: Record<string, unknown>` on every generated CRD class, nothing
|
|
5
|
+
* at compile time stops `replicas: "2"` or `desiredState: "Runing"`. The API
|
|
6
|
+
* server rejects the first at apply and the controller ignores the second.
|
|
7
|
+
* The lexicon ships each CRD's `spec` schema (chant #1372); this check
|
|
8
|
+
* compares every scalar against its declared type and enum before apply.
|
|
9
|
+
* `x-kubernetes-int-or-string` and untyped nodes accept anything.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
13
|
+
import { customResources, resourceLabel, validateSpec } from "./crd-schema-helpers";
|
|
14
|
+
|
|
15
|
+
export const wk8502: PostSynthCheck = {
|
|
16
|
+
id: "WK8502",
|
|
17
|
+
description: "Custom resource spec field has the wrong type or a value outside its enum",
|
|
18
|
+
|
|
19
|
+
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
20
|
+
const diagnostics: PostSynthDiagnostic[] = [];
|
|
21
|
+
|
|
22
|
+
for (const { manifest, schema } of customResources(ctx)) {
|
|
23
|
+
if (manifest.spec === undefined) continue;
|
|
24
|
+
const name = resourceLabel(manifest);
|
|
25
|
+
for (const finding of validateSpec(manifest.spec, schema)) {
|
|
26
|
+
if (finding.kind !== "type-mismatch") continue;
|
|
27
|
+
diagnostics.push({
|
|
28
|
+
checkId: "WK8502",
|
|
29
|
+
severity: "error",
|
|
30
|
+
message: `${manifest.kind} "${name}": ${finding.message}`,
|
|
31
|
+
entity: name,
|
|
32
|
+
lexicon: "k8s",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return diagnostics;
|
|
38
|
+
},
|
|
39
|
+
};
|
package/dist/spec/parse.d.ts
CHANGED
|
@@ -64,6 +64,32 @@ export interface ParsedOperation {
|
|
|
64
64
|
/** Verbs the schema documents for the named resource, e.g. `get`, `patch`. */
|
|
65
65
|
verbs: string[];
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Compact, recursive field schema for a custom resource's `spec` — chant #1372.
|
|
69
|
+
*
|
|
70
|
+
* Built-in kinds get their field typing from the generated `.d.ts`. A CRD's
|
|
71
|
+
* constructor takes `spec: Record<string, unknown>`, so its field names, enums
|
|
72
|
+
* and scalar types have to travel through the lexicon JSON instead. This is
|
|
73
|
+
* the shape that ships there: no descriptions, no numeric bounds, only what a
|
|
74
|
+
* validator needs to reject a misspelled field or a wrong-typed value.
|
|
75
|
+
*/
|
|
76
|
+
export interface CrdFieldSchema {
|
|
77
|
+
/** OpenAPI type; `integer` is kept distinct from `number`. Absent when the schema says nothing. */
|
|
78
|
+
type?: "string" | "integer" | "number" | "boolean" | "object" | "array";
|
|
79
|
+
enum?: string[];
|
|
80
|
+
/** Object members, keyed by field name. */
|
|
81
|
+
fields?: Record<string, CrdFieldSchema>;
|
|
82
|
+
/** Required member names of an object. */
|
|
83
|
+
required?: string[];
|
|
84
|
+
/** Element schema of an array. */
|
|
85
|
+
items?: CrdFieldSchema;
|
|
86
|
+
/**
|
|
87
|
+
* True when the object accepts members its `fields` do not list —
|
|
88
|
+
* `x-kubernetes-preserve-unknown-fields` or `additionalProperties`.
|
|
89
|
+
* `x-kubernetes-int-or-string` also sets it on a scalar, meaning either type passes.
|
|
90
|
+
*/
|
|
91
|
+
open?: true;
|
|
92
|
+
}
|
|
67
93
|
export interface K8sParseResult {
|
|
68
94
|
resource: ParsedResource;
|
|
69
95
|
propertyTypes: ParsedPropertyType[];
|
|
@@ -73,6 +99,12 @@ export interface K8sParseResult {
|
|
|
73
99
|
isProperty?: boolean;
|
|
74
100
|
/** How the API addresses this resource. Absent for property types. */
|
|
75
101
|
operation?: ParsedOperation;
|
|
102
|
+
/**
|
|
103
|
+
* The `spec` field schema of a custom resource (chant #1372). Present only
|
|
104
|
+
* for CRD-derived kinds whose `openAPIV3Schema` declares a `spec`; built-in
|
|
105
|
+
* kinds carry their typing in the `.d.ts` instead.
|
|
106
|
+
*/
|
|
107
|
+
specSchema?: CrdFieldSchema;
|
|
76
108
|
}
|
|
77
109
|
interface SwaggerOperation {
|
|
78
110
|
"x-kubernetes-group-version-kind"?: GroupVersionKind;
|
package/dist/spec/parse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/spec/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAUhF,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,mBAAmB,CAAC;IACjC,4GAA4G;IAC5G,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6HAA6H;IAC7H,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,YAAY,GAAG,SAAS,CAAC;IAChC,8EAA8E;IAC9E,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,aAAa,EAAE,kBAAkB,EAAE,CAAC;IACpC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,GAAG,EAAE,gBAAgB,CAAC;IACtB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sEAAsE;IACtE,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AA4CD,UAAU,gBAAgB;IACxB,iCAAiC,CAAC,EAAE,gBAAgB,CAAC;IACrD,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,CAAC;AA+DlE;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,cAAc,EAAE,CAoCvE;AAED,uFAAuF;AACvF;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAapF;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAEpD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAqChH;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAG3D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAK7D;AA4PD;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGvD"}
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/spec/parse.ts"],"names":[],"mappings":"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"}
|
package/dist/validate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAElG,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAuBvF;;GAEG;AACH,wBAAsB,QAAQ,CAAC,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAElG,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAuBvF;;GAEG;AACH,wBAAsB,QAAQ,CAAC,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAepF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-k8s",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"description": "Kubernetes lexicon for chant — declarative IaC in TypeScript",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@types/js-yaml": "^4.0.9"
|
|
77
77
|
},
|
|
78
78
|
"optionalDependencies": {
|
|
79
|
-
"@intentius/chant-k8s-client": "^0.
|
|
79
|
+
"@intentius/chant-k8s-client": "^0.45.0"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@intentius/chant": "*",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|
|
86
86
|
"zod": "^4.3.6",
|
|
87
|
-
"@intentius/chant": "^0.
|
|
87
|
+
"@intentius/chant": "^0.45.0",
|
|
88
88
|
"typescript": "^5.9.3"
|
|
89
89
|
}
|
|
90
90
|
}
|