@intentius/chant-lexicon-helm 0.124.31 → 0.124.33
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/archive-render.js +76 -0
- package/dist/codegen/docs-cli.js +3 -0
- package/dist/codegen/docs.js +113 -0
- package/dist/codegen/generate-cli.js +19 -0
- package/dist/codegen/generate.js +210 -0
- package/dist/codegen/naming.js +29 -0
- package/dist/codegen/package.js +44 -0
- package/dist/codegen/values-type.js +87 -0
- package/dist/commands.js +413 -0
- package/dist/components/builders.js +9 -0
- package/dist/components/capability-plugin.js +17 -0
- package/dist/components/helm-upgrade.js +109 -0
- package/dist/components/index.js +11 -0
- package/dist/composites/catalog.js +1119 -0
- package/dist/composites/helm-batch-job.js +148 -0
- package/dist/composites/helm-crd-lifecycle.js +145 -0
- package/dist/composites/helm-cron-job.js +130 -0
- package/dist/composites/helm-daemon-set.js +125 -0
- package/dist/composites/helm-external-secret.js +63 -0
- package/dist/composites/helm-library.js +24 -0
- package/dist/composites/helm-microservice.js +260 -0
- package/dist/composites/helm-monitored-service.js +188 -0
- package/dist/composites/helm-namespace-env.js +116 -0
- package/dist/composites/helm-secure-ingress.js +86 -0
- package/dist/composites/helm-stateful-service.js +160 -0
- package/dist/composites/helm-web-app.js +201 -0
- package/dist/composites/helm-worker.js +164 -0
- package/dist/composites/index.js +13 -0
- package/dist/config.js +161 -0
- package/dist/coverage.js +37 -0
- package/dist/deep-observe-hooks.js +19 -0
- package/dist/deep-observe.js +55 -0
- package/dist/describe-resources.js +119 -0
- package/dist/describe-stack-status.js +66 -0
- package/dist/detect.js +11 -0
- package/dist/generated/index.js +11 -0
- package/dist/helpers.js +84 -0
- package/dist/import/generator.js +292 -0
- package/dist/import/parser.js +141 -0
- package/dist/import/template-stripper.js +86 -0
- package/dist/index.js +55 -0
- package/dist/integrity.json +2 -2
- package/dist/intrinsics.js +482 -0
- package/dist/lint/audit-catalog.js +33 -0
- package/dist/lint/audit-lineage.js +53 -0
- package/dist/lint/post-synth/helm-helpers.js +60 -0
- package/dist/lint/post-synth/index.js +48 -0
- package/dist/lint/post-synth/whm005-no-empty-wrapper.js +47 -0
- package/dist/lint/post-synth/whm101.js +38 -0
- package/dist/lint/post-synth/whm102.js +26 -0
- package/dist/lint/post-synth/whm103.js +51 -0
- package/dist/lint/post-synth/whm104.js +29 -0
- package/dist/lint/post-synth/whm105.js +23 -0
- package/dist/lint/post-synth/whm201.js +29 -0
- package/dist/lint/post-synth/whm202.js +42 -0
- package/dist/lint/post-synth/whm203.js +32 -0
- package/dist/lint/post-synth/whm204.js +51 -0
- package/dist/lint/post-synth/whm301.js +31 -0
- package/dist/lint/post-synth/whm302.js +33 -0
- package/dist/lint/post-synth/whm401.js +52 -0
- package/dist/lint/post-synth/whm402.js +38 -0
- package/dist/lint/post-synth/whm403.js +38 -0
- package/dist/lint/post-synth/whm404.js +30 -0
- package/dist/lint/post-synth/whm405.js +47 -0
- package/dist/lint/post-synth/whm406.js +27 -0
- package/dist/lint/post-synth/whm407.js +72 -0
- package/dist/lint/post-synth/whm501.js +89 -0
- package/dist/lint/post-synth/whm502.js +85 -0
- package/dist/lint/post-synth/whm503.js +82 -0
- package/dist/lint/post-synth/whm504.js +47 -0
- package/dist/lint/rules/chart-metadata.js +53 -0
- package/dist/lint/rules/no-hardcoded-image.js +50 -0
- package/dist/lint/rules/values-no-helm-tpl.js +78 -0
- package/dist/lint/rules/values-no-secrets.js +65 -0
- package/dist/list-artifacts.js +134 -0
- package/dist/lsp/completions.d.ts.map +1 -1
- package/dist/lsp/completions.js +18 -0
- package/dist/lsp/hover.d.ts.map +1 -1
- package/dist/lsp/hover.js +40 -0
- package/dist/manifest.json +1 -1
- package/dist/op/activities/cluster-probe.js +116 -0
- package/dist/op/activities/helm.js +449 -0
- package/dist/op/activities/index.js +10 -0
- package/dist/op/builders.js +45 -0
- package/dist/package-cli.js +21 -0
- package/dist/pinnability/actions.js +207 -0
- package/dist/pinnability/classify.js +416 -0
- package/dist/pinnability/conditions.js +0 -0
- package/dist/pinnability/index.js +16 -0
- package/dist/pinnability/localize.js +518 -0
- package/dist/pinnability/render-stream.js +53 -0
- package/dist/pinnability/values.js +151 -0
- package/dist/plugin.js +458 -0
- package/dist/project-codegen.js +215 -0
- package/dist/release-observe.js +287 -0
- package/dist/render-diff.js +279 -0
- package/dist/render-digest.js +0 -0
- package/dist/render-records.js +29 -0
- package/dist/render-store.js +401 -0
- package/dist/render-wrapper.js +164 -0
- package/dist/render.js +394 -0
- package/dist/resources.js +109 -0
- package/dist/serializer.js +903 -0
- package/dist/validate-cli.js +17 -0
- package/dist/validate.js +30 -0
- package/dist/values-probe.js +504 -0
- package/dist/wrapper-chart.js +95 -0
- package/package.json +11 -11
- package/src/codegen/package.ts +2 -2
- package/src/lsp/completions.ts +2 -1
- package/src/lsp/hover.ts +2 -1
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render diffing (#1249 offline, #1250 live — epic #1228 Phase 6), the two
|
|
3
|
+
* halves of `chant helm diff` (./commands.ts).
|
|
4
|
+
*
|
|
5
|
+
* `diffRenders` (#1249) is the offline half: given two content digests
|
|
6
|
+
* already in the render store (render-store.ts), report what changed
|
|
7
|
+
* between them — no cluster, no credentials, no live read. This is the
|
|
8
|
+
* pre-flight question a pin, a chart bump, or a values change all raise:
|
|
9
|
+
* "what will this touch?"
|
|
10
|
+
*
|
|
11
|
+
* Pairing is document-level, keyed on `(kind, namespace, name)` — the same
|
|
12
|
+
* identity `RenderManifest.documents` already indexes (render-store.ts).
|
|
13
|
+
* That index exists precisely so two renders can be matched without
|
|
14
|
+
* reparsing a whole stream: a document present on both sides with the same
|
|
15
|
+
* per-document digest is unchanged and costs nothing further; one whose
|
|
16
|
+
* digest differs is parsed on both sides and diffed field by field.
|
|
17
|
+
*
|
|
18
|
+
* Field-level diffing reuses core's `flattenDeepProperties` /
|
|
19
|
+
* `deepValueEqual` (packages/core/src/deep-observation.ts) — the same
|
|
20
|
+
* path-flattening core's own live-drift diff (lifecycle/deep-diff.ts) is
|
|
21
|
+
* built on. This module does not reuse `diffDeep` itself for the offline
|
|
22
|
+
* path: that function's shape is declared/live/baseline/fieldOwners,
|
|
23
|
+
* tailored to a source tree vs a cluster read. A stored render has neither
|
|
24
|
+
* a baseline nor a field owner, and both sides here are equally "declared"
|
|
25
|
+
* — reusing the flatten/compare primitives without the three-way apparatus
|
|
26
|
+
* is the right cut for render-to-render.
|
|
27
|
+
*
|
|
28
|
+
* Duplicate documents (an aliased dependency emitting the same CRD twice,
|
|
29
|
+
* render-digest.ts's canonicalization note) are matched positionally within
|
|
30
|
+
* their `(kind, namespace, name)` group: first occurrence to first, second
|
|
31
|
+
* to second. A group with more entries on one side reports the surplus as
|
|
32
|
+
* added or removed rather than guessing which duplicate corresponds to
|
|
33
|
+
* which.
|
|
34
|
+
*
|
|
35
|
+
* A document neither side's manifest could index (unparseable, or missing
|
|
36
|
+
* `kind`/`metadata.name` — render-store.ts's `indexRenderDocuments`) cannot
|
|
37
|
+
* be paired by identity. It is never silently dropped: `unindexed` counts
|
|
38
|
+
* it on whichever side(s) it appears, so a diff over two renders that both
|
|
39
|
+
* carry unindexable documents does not quietly under-report.
|
|
40
|
+
*
|
|
41
|
+
* `diffRenderLive` (#1250) is the online complement: given a single
|
|
42
|
+
* `contentDigest` resolved from the render store, read the live property
|
|
43
|
+
* tree for every document the render recorded — by identity
|
|
44
|
+
* (kind/namespace/name), not by helm release — and diff each one against
|
|
45
|
+
* the render's own stored bytes with `lifecycle/deep-diff.ts`. This *does*
|
|
46
|
+
* reuse `diffDeep`'s three-way apparatus (via `diffDeepObservation`): the
|
|
47
|
+
* declared side is the render's stored documents, the live side is a
|
|
48
|
+
* cluster read, which is exactly that function's shape.
|
|
49
|
+
*
|
|
50
|
+
* The declared side for the live path is the render's stored documents,
|
|
51
|
+
* never a fresh `helm template` run and never a chant TS build. A digest
|
|
52
|
+
* not in the store — an unpinned render was never persisted
|
|
53
|
+
* (`render-store.ts`'s `persistHelmRender` refuses that) — has nothing to
|
|
54
|
+
* diff against and comes back `found: false`, never a false "no drift" over
|
|
55
|
+
* documents nobody has (epic AC: unpinned releases handled without false
|
|
56
|
+
* drift).
|
|
57
|
+
*
|
|
58
|
+
* The live side reuses the exact seam `observeResourcesDeepHelm` (#1247)
|
|
59
|
+
* uses — the k8s lexicon's typed client and normalization hooks — so a
|
|
60
|
+
* document this reads and one a release's `describeResources` reads compare
|
|
61
|
+
* under the same rules (secret masking, managed-fields ownership, pruning).
|
|
62
|
+
* Hook resources need no special handling here the way the release-scoped
|
|
63
|
+
* read needs a second `helm get hooks` channel: `helm template` (what
|
|
64
|
+
* produced the stored render) already includes hook manifests as ordinary
|
|
65
|
+
* documents, so they are simply rows in `manifest.documents` like any other.
|
|
66
|
+
*/
|
|
67
|
+
import yaml from "js-yaml";
|
|
68
|
+
import { deepValueEqual, flattenDeepProperties, normalizeDeepObservation } from "@intentius/chant/deep-observation";
|
|
69
|
+
import { diffDeepObservation } from "@intentius/chant/lifecycle/deep-observe";
|
|
70
|
+
import { observeResourcesDeepK8s } from "@intentius/chant-lexicon-k8s/deep-observe";
|
|
71
|
+
import { gvkToTypeName } from "@intentius/chant-lexicon-k8s/spec/parse";
|
|
72
|
+
import { helmDeepNormalizationHooks } from "./deep-observe-hooks.js";
|
|
73
|
+
import { CLUSTER_SCOPED_KINDS } from "./release-observe.js";
|
|
74
|
+
import { loadRenderManifest, readRenderDocument } from "./render-store.js";
|
|
75
|
+
function docKey(doc) {
|
|
76
|
+
return `${doc.kind}\0${doc.namespace ?? ""}\0${doc.name}`;
|
|
77
|
+
}
|
|
78
|
+
function docRef(doc) {
|
|
79
|
+
return { kind: doc.kind, namespace: doc.namespace, name: doc.name, source: doc.source };
|
|
80
|
+
}
|
|
81
|
+
/** Group a manifest's document entries by identity, preserving occurrence order for duplicate matching. */
|
|
82
|
+
function groupByIdentity(documents) {
|
|
83
|
+
const groups = new Map();
|
|
84
|
+
for (const doc of documents) {
|
|
85
|
+
const key = docKey(doc);
|
|
86
|
+
const group = groups.get(key);
|
|
87
|
+
if (group)
|
|
88
|
+
group.push(doc);
|
|
89
|
+
else
|
|
90
|
+
groups.set(key, [doc]);
|
|
91
|
+
}
|
|
92
|
+
return groups;
|
|
93
|
+
}
|
|
94
|
+
function compareRefs(a, b) {
|
|
95
|
+
return (a.kind.localeCompare(b.kind) ||
|
|
96
|
+
(a.namespace ?? "").localeCompare(b.namespace ?? "") ||
|
|
97
|
+
a.name.localeCompare(b.name));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Field-level diff between a document's two parsed trees. Both sides are
|
|
101
|
+
* flattened with `flattenDeepProperties` (no ordering hooks — a stored
|
|
102
|
+
* render carries no lexicon to supply one, so arrays are compared
|
|
103
|
+
* positionally, exactly as the canonicalized bytes ordered them) and walked
|
|
104
|
+
* path by path.
|
|
105
|
+
*/
|
|
106
|
+
function diffDocumentFields(beforeText, afterText, entityType) {
|
|
107
|
+
const beforeTree = (yaml.load(beforeText) ?? {});
|
|
108
|
+
const afterTree = (yaml.load(afterText) ?? {});
|
|
109
|
+
const beforeFlat = flattenDeepProperties(beforeTree, { entityType, side: "declared" });
|
|
110
|
+
const afterFlat = flattenDeepProperties(afterTree, { entityType, side: "live" });
|
|
111
|
+
const paths = [...new Set([...beforeFlat.keys(), ...afterFlat.keys()])].sort();
|
|
112
|
+
const changes = [];
|
|
113
|
+
for (const path of paths) {
|
|
114
|
+
const hasBefore = beforeFlat.has(path);
|
|
115
|
+
const hasAfter = afterFlat.has(path);
|
|
116
|
+
const beforeValue = beforeFlat.get(path);
|
|
117
|
+
const afterValue = afterFlat.get(path);
|
|
118
|
+
if (hasBefore && hasAfter && deepValueEqual(beforeValue, afterValue))
|
|
119
|
+
continue;
|
|
120
|
+
const kind = !hasBefore ? "added" : !hasAfter ? "removed" : "changed";
|
|
121
|
+
changes.push({
|
|
122
|
+
path,
|
|
123
|
+
kind,
|
|
124
|
+
...(hasBefore ? { before: beforeValue } : {}),
|
|
125
|
+
...(hasAfter ? { after: afterValue } : {}),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return changes;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Diff two renders already in the store, by content digest. Offline: every
|
|
132
|
+
* byte compared comes from the archive (render-store.ts), never a cluster.
|
|
133
|
+
*
|
|
134
|
+
* Throws when either digest has no manifest — a diff over a render nobody
|
|
135
|
+
* persisted is a usage error, not an empty report.
|
|
136
|
+
*/
|
|
137
|
+
export function diffRenders(from, to, options) {
|
|
138
|
+
const opts = { root: options?.root };
|
|
139
|
+
const fromManifest = requireManifest(from, opts.root);
|
|
140
|
+
const toManifest = requireManifest(to, opts.root);
|
|
141
|
+
const fromGroups = groupByIdentity(fromManifest.documents);
|
|
142
|
+
const toGroups = groupByIdentity(toManifest.documents);
|
|
143
|
+
const added = [];
|
|
144
|
+
const removed = [];
|
|
145
|
+
const changed = [];
|
|
146
|
+
const unchanged = [];
|
|
147
|
+
const keys = new Set([...fromGroups.keys(), ...toGroups.keys()]);
|
|
148
|
+
for (const key of keys) {
|
|
149
|
+
const fromEntries = fromGroups.get(key) ?? [];
|
|
150
|
+
const toEntries = toGroups.get(key) ?? [];
|
|
151
|
+
const pairCount = Math.min(fromEntries.length, toEntries.length);
|
|
152
|
+
for (let i = 0; i < pairCount; i++) {
|
|
153
|
+
const fromDoc = fromEntries[i];
|
|
154
|
+
const toDoc = toEntries[i];
|
|
155
|
+
if (fromDoc.digest === toDoc.digest) {
|
|
156
|
+
unchanged.push(docRef(fromDoc));
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const fromRead = readRenderDocument(from, fromDoc, opts);
|
|
160
|
+
const toRead = readRenderDocument(to, toDoc, opts);
|
|
161
|
+
/* c8 ignore next 5 -- indexed entries always resolve; defensive only */
|
|
162
|
+
if (!fromRead || !toRead) {
|
|
163
|
+
throw new Error(`render diff: indexed document ${fromDoc.kind}/${fromDoc.name} failed to resolve from its own store entry`);
|
|
164
|
+
}
|
|
165
|
+
changed.push({
|
|
166
|
+
...docRef(fromDoc),
|
|
167
|
+
beforeDigest: fromDoc.digest,
|
|
168
|
+
afterDigest: toDoc.digest,
|
|
169
|
+
changes: diffDocumentFields(fromRead.text, toRead.text, fromDoc.kind),
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
for (let i = pairCount; i < fromEntries.length; i++) {
|
|
173
|
+
removed.push({ ...docRef(fromEntries[i]), digest: fromEntries[i].digest });
|
|
174
|
+
}
|
|
175
|
+
for (let i = pairCount; i < toEntries.length; i++) {
|
|
176
|
+
added.push({ ...docRef(toEntries[i]), digest: toEntries[i].digest });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
from: { contentDigest: fromManifest.contentDigest, chart: fromManifest.chart, releaseName: fromManifest.releaseName },
|
|
181
|
+
to: { contentDigest: toManifest.contentDigest, chart: toManifest.chart, releaseName: toManifest.releaseName },
|
|
182
|
+
added: added.sort(compareRefs),
|
|
183
|
+
removed: removed.sort(compareRefs),
|
|
184
|
+
changed: changed.sort(compareRefs),
|
|
185
|
+
unchanged: unchanged.sort(compareRefs),
|
|
186
|
+
unindexed: {
|
|
187
|
+
from: fromManifest.docCount - fromManifest.documents.length,
|
|
188
|
+
to: toManifest.docCount - toManifest.documents.length,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function requireManifest(contentDigest, root) {
|
|
193
|
+
const manifest = loadRenderManifest(contentDigest, { root });
|
|
194
|
+
if (!manifest) {
|
|
195
|
+
throw new Error(`no stored render for ${contentDigest} — resolve it first (chant helm renders), or check ` +
|
|
196
|
+
`CHANT_HELM_RENDER_ROOT if the store root was overridden.`);
|
|
197
|
+
}
|
|
198
|
+
return manifest;
|
|
199
|
+
}
|
|
200
|
+
/** True when the diff found no added, removed, or changed documents. */
|
|
201
|
+
export function renderDiffIsEmpty(result) {
|
|
202
|
+
return result.added.length === 0 && result.removed.length === 0 && result.changed.length === 0;
|
|
203
|
+
}
|
|
204
|
+
function splitApiVersion(apiVersion) {
|
|
205
|
+
const slash = apiVersion.indexOf("/");
|
|
206
|
+
return slash > 0
|
|
207
|
+
? { group: apiVersion.slice(0, slash), version: apiVersion.slice(slash + 1) }
|
|
208
|
+
: { group: "", version: apiVersion };
|
|
209
|
+
}
|
|
210
|
+
/** Row key convention shared with the release-scoped reads (#1246/#1247): `<Kind>/<namespace>/<name>`, `cluster:<Kind>/<name>`. */
|
|
211
|
+
export function documentKey(kind, namespace, name) {
|
|
212
|
+
return namespace ? `${kind}/${namespace}/${name}` : `cluster:${kind}/${name}`;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* A namespace-silent document defaults to the render's target namespace —
|
|
216
|
+
* the same rule a deployed release applies to its manifest (`helm apply
|
|
217
|
+
* -n <ns>` targets whatever a namespace-silent object's `.Release.Namespace`
|
|
218
|
+
* would have filled in) — unless the kind is cluster-scoped, in which case a
|
|
219
|
+
* missing namespace is never defaulted.
|
|
220
|
+
*/
|
|
221
|
+
export function resolveDocumentNamespace(kind, declared, renderNamespace) {
|
|
222
|
+
if (declared)
|
|
223
|
+
return declared;
|
|
224
|
+
if (CLUSTER_SCOPED_KINDS.has(kind))
|
|
225
|
+
return undefined;
|
|
226
|
+
return renderNamespace ?? undefined;
|
|
227
|
+
}
|
|
228
|
+
/** The document minus the envelope the row's `type` already carries — mirrors `deep-observe.ts`'s `declaredTreeOf`. */
|
|
229
|
+
function declaredTreeOf(doc, namespace) {
|
|
230
|
+
const { apiVersion: _apiVersion, kind: _kind, ...rest } = doc;
|
|
231
|
+
const metadata = (rest.metadata ?? {});
|
|
232
|
+
return {
|
|
233
|
+
...rest,
|
|
234
|
+
...(namespace ? { metadata: { ...metadata, ...(metadata.namespace === undefined ? { namespace } : {}) } } : {}),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Diff one stored render's documents against the live cluster.
|
|
239
|
+
*
|
|
240
|
+
* `found: false` when `contentDigest` is not in the store — never fabricates
|
|
241
|
+
* a document, and never reports "no drift" over a render this has no bytes
|
|
242
|
+
* for. On a found render, every document indexed in its manifest becomes a
|
|
243
|
+
* synthetic declared entity (keyed like a release's rows), read live through
|
|
244
|
+
* the k8s lexicon's deep observer, and diffed property-by-property.
|
|
245
|
+
*/
|
|
246
|
+
export async function diffRenderLive(options, deps = {}) {
|
|
247
|
+
const manifest = loadRenderManifest(options.contentDigest, { root: options.root });
|
|
248
|
+
if (!manifest)
|
|
249
|
+
return { found: false, contentDigest: options.contentDigest };
|
|
250
|
+
const entities = new Map();
|
|
251
|
+
for (const docEntry of manifest.documents) {
|
|
252
|
+
const resolved = readRenderDocument(options.contentDigest, { kind: docEntry.kind, name: docEntry.name, namespace: docEntry.namespace }, { root: options.root });
|
|
253
|
+
if (!resolved)
|
|
254
|
+
continue; // integrity gap between the index and the content — skip, never fabricate
|
|
255
|
+
const parsed = yaml.load(resolved.text);
|
|
256
|
+
if (parsed === null || typeof parsed !== "object")
|
|
257
|
+
continue;
|
|
258
|
+
const namespace = resolveDocumentNamespace(docEntry.kind, docEntry.namespace, manifest.namespace);
|
|
259
|
+
const key = documentKey(docEntry.kind, namespace, docEntry.name);
|
|
260
|
+
const { group, version } = splitApiVersion(docEntry.apiVersion);
|
|
261
|
+
entities.set(key, {
|
|
262
|
+
entityType: gvkToTypeName({ group, version, kind: docEntry.kind }),
|
|
263
|
+
props: declaredTreeOf(parsed, namespace),
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
const k8sOptions = {
|
|
267
|
+
environment: options.environment,
|
|
268
|
+
buildOutput: "",
|
|
269
|
+
entityNames: [...entities.keys()],
|
|
270
|
+
entities,
|
|
271
|
+
...(options.owned !== undefined ? { owned: options.owned } : {}),
|
|
272
|
+
};
|
|
273
|
+
const raw = deps.connect
|
|
274
|
+
? await observeResourcesDeepK8s(k8sOptions, deps.connect)
|
|
275
|
+
: await observeResourcesDeepK8s(k8sOptions);
|
|
276
|
+
const live = normalizeDeepObservation(raw);
|
|
277
|
+
const diff = diffDeepObservation(entities, live, helmDeepNormalizationHooks);
|
|
278
|
+
return { found: true, manifest, diff };
|
|
279
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The in-process ledger of `HelmRender` invocations — split out of
|
|
3
|
+
* `./render.ts` so a post-synth check can read it without importing the
|
|
4
|
+
* render machinery (#1979 follow-up, found by the hosted audit's bump).
|
|
5
|
+
*
|
|
6
|
+
* WHM503 (`./lint/post-synth/whm503.ts`) scans these records, and post-synth
|
|
7
|
+
* barrels are edge-imported by the hosted audit service: everything they
|
|
8
|
+
* reach through static imports must be safe to initialize on workerd.
|
|
9
|
+
* `render.ts` is not — it imports the full `@intentius/chant` barrel, whose
|
|
10
|
+
* static graph reaches the TypeScript compiler (fold-import), and
|
|
11
|
+
* TypeScript's own module init touches `__filename`, which crashes the
|
|
12
|
+
* worker at startup. This module carries only the record shape and the
|
|
13
|
+
* ledger, imports nothing but a type, and keeps the barrel edge-clean;
|
|
14
|
+
* `render.ts` re-exports it all, so the lexicon's public surface is
|
|
15
|
+
* unchanged.
|
|
16
|
+
*/
|
|
17
|
+
const renderRecords = [];
|
|
18
|
+
/** Append one invocation's record (called by `HelmRender`, ./render.ts). */
|
|
19
|
+
export function recordHelmRender(record) {
|
|
20
|
+
renderRecords.push(record);
|
|
21
|
+
}
|
|
22
|
+
/** Every render recorded in this process, in invocation order. */
|
|
23
|
+
export function getHelmRenderRecords() {
|
|
24
|
+
return renderRecords;
|
|
25
|
+
}
|
|
26
|
+
/** Reset the record list (test isolation). */
|
|
27
|
+
export function clearHelmRenderRecords() {
|
|
28
|
+
renderRecords.length = 0;
|
|
29
|
+
}
|