@intentius/chant-lexicon-helm 0.46.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/archive-render.d.ts +94 -0
- package/dist/archive-render.d.ts.map +1 -0
- package/dist/commands.d.ts +54 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/config.d.ts +135 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/deep-observe-hooks.d.ts +2 -0
- package/dist/deep-observe-hooks.d.ts.map +1 -0
- package/dist/deep-observe.d.ts +54 -0
- package/dist/deep-observe.d.ts.map +1 -0
- package/dist/describe-resources.d.ts +17 -0
- package/dist/describe-resources.d.ts.map +1 -0
- package/dist/index.d.ts +19 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +5 -3
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/whm503.d.ts +34 -0
- package/dist/lint/post-synth/whm503.d.ts.map +1 -0
- package/dist/lint/post-synth/whm504.d.ts +20 -0
- package/dist/lint/post-synth/whm504.d.ts.map +1 -0
- package/dist/manifest.json +25 -13
- package/dist/okf/index.md +2 -0
- package/dist/okf/rules/WHM503.md +15 -0
- package/dist/okf/rules/WHM504.md +11 -0
- package/dist/okf/types/Values.md +1 -0
- package/dist/op/activities/cluster-probe.d.ts +44 -0
- package/dist/op/activities/cluster-probe.d.ts.map +1 -0
- package/dist/op/activities/helm.d.ts +179 -5
- package/dist/op/activities/helm.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +4 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/builders.d.ts +47 -0
- package/dist/op/builders.d.ts.map +1 -0
- package/dist/pinnability/actions.d.ts +76 -0
- package/dist/pinnability/actions.d.ts.map +1 -0
- package/dist/pinnability/classify.d.ts +129 -0
- package/dist/pinnability/classify.d.ts.map +1 -0
- package/dist/pinnability/conditions.d.ts +109 -0
- package/dist/pinnability/conditions.d.ts.map +1 -0
- package/dist/pinnability/index.d.ts +17 -0
- package/dist/pinnability/index.d.ts.map +1 -0
- package/dist/pinnability/localize.d.ts +124 -0
- package/dist/pinnability/localize.d.ts.map +1 -0
- package/dist/pinnability/render-stream.d.ts +27 -0
- package/dist/pinnability/render-stream.d.ts.map +1 -0
- package/dist/pinnability/values.d.ts +69 -0
- package/dist/pinnability/values.d.ts.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/release-observe.d.ts +109 -0
- package/dist/release-observe.d.ts.map +1 -0
- package/dist/render-diff.d.ts +192 -0
- package/dist/render-diff.d.ts.map +1 -0
- package/dist/render-digest.d.ts +135 -0
- package/dist/render-digest.d.ts.map +1 -0
- package/dist/render-store.d.ts +310 -0
- package/dist/render-store.d.ts.map +1 -0
- package/dist/render-wrapper.d.ts +140 -0
- package/dist/render-wrapper.d.ts.map +1 -0
- package/dist/render.d.ts +81 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/rules/whm503.ts +101 -0
- package/dist/rules/whm504.ts +52 -0
- package/dist/skills/chant-helm.md +7 -0
- package/dist/values-probe.d.ts +177 -0
- package/dist/values-probe.d.ts.map +1 -0
- package/dist/wrapper-chart.d.ts +61 -0
- package/dist/wrapper-chart.d.ts.map +1 -0
- package/package.json +10 -4
- package/src/archive-render.test.ts +201 -0
- package/src/archive-render.ts +119 -0
- package/src/commands.test.ts +487 -0
- package/src/commands.ts +445 -0
- package/src/config.test.ts +130 -0
- package/src/config.ts +220 -0
- package/src/deep-observe-hooks.ts +20 -0
- package/src/deep-observe.test.ts +165 -0
- package/src/deep-observe.ts +121 -0
- package/src/describe-resources.test.ts +255 -0
- package/src/describe-resources.ts +198 -0
- package/src/index.ts +106 -2
- package/src/lifecycle-integration.test.ts +289 -0
- package/src/lint/audit-catalog.ts +2 -0
- package/src/lint/post-synth/index.ts +4 -0
- package/src/lint/post-synth/whm503.test.ts +134 -0
- package/src/lint/post-synth/whm503.ts +101 -0
- package/src/lint/post-synth/whm504.test.ts +105 -0
- package/src/lint/post-synth/whm504.ts +52 -0
- package/src/op/activities/cluster-probe.test.ts +66 -0
- package/src/op/activities/cluster-probe.ts +148 -0
- package/src/op/activities/helm.test.ts +824 -0
- package/src/op/activities/helm.ts +628 -5
- package/src/op/activities/index.ts +17 -2
- package/src/op/builders.test.ts +70 -0
- package/src/op/builders.ts +66 -0
- package/src/pinnability/actions.ts +263 -0
- package/src/pinnability/classify.ts +579 -0
- package/src/pinnability/conditions.ts +0 -0
- package/src/pinnability/index.ts +77 -0
- package/src/pinnability/localize.test.ts +234 -0
- package/src/pinnability/localize.ts +644 -0
- package/src/pinnability/pinnability.test.ts +560 -0
- package/src/pinnability/render-stream.ts +59 -0
- package/src/pinnability/values.ts +205 -0
- package/src/plugin.test.ts +3 -1
- package/src/plugin.ts +97 -12
- package/src/release-observe.ts +392 -0
- package/src/render-diff.test.ts +366 -0
- package/src/render-diff.ts +407 -0
- package/src/render-digest.test.ts +186 -0
- package/src/render-digest.ts +207 -0
- package/src/render-store.test.ts +412 -0
- package/src/render-store.ts +621 -0
- package/src/render-wrapper.test.ts +259 -0
- package/src/render-wrapper.ts +274 -0
- package/src/render.test.ts +383 -4
- package/src/render.ts +319 -8
- package/src/skills/chant-helm.md +7 -0
- package/src/values-probe.test.ts +400 -0
- package/src/values-probe.ts +627 -0
- package/src/wrapper-chart.test.ts +110 -0
- package/src/wrapper-chart.ts +124 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structure-preserving render wrapper (#1239, epic #1228 Phase 3).
|
|
3
|
+
*
|
|
4
|
+
* Turns a pinned render's document stream into chant-shaped routing groups
|
|
5
|
+
* WITHOUT restructuring the documents. Structure-preserving means the bytes
|
|
6
|
+
* that deploy are the bytes the render store recorded — this module only
|
|
7
|
+
* routes and labels; it never re-serializes, reorders lines, or edits a
|
|
8
|
+
* document. Each `RoutedDocument.text` is the exact document text from the
|
|
9
|
+
* input stream.
|
|
10
|
+
*
|
|
11
|
+
* Routing is by origin, not by kind. `helm template` stamps every document
|
|
12
|
+
* with `# Source: <chart>/<path>`, and the discriminator is whether that
|
|
13
|
+
* path contains a `crds/` **segment** (`(^|/)crds/` — `isCrdSource` from
|
|
14
|
+
* the #1234 classifier seeds):
|
|
15
|
+
*
|
|
16
|
+
* - A `crds/`-segment origin routes to the CRD group — the wrapper's
|
|
17
|
+
* `crds/`. Segment matching is load-bearing: a subchart's CRDs arrive as
|
|
18
|
+
* `charts/<child>/crds/<file>`, so a prefix rule catches none of them and
|
|
19
|
+
* would route every subchart CRD into `templates/`, making it deletable
|
|
20
|
+
* on uninstall (epic findings 4, 10 — the A/B test showed a flat wrap
|
|
21
|
+
* converts `helm uninstall` from safe to data-destroying).
|
|
22
|
+
* - A hook-annotated template document (`helm.sh/hook` in
|
|
23
|
+
* `metadata.annotations`) routes to its own group, annotations intact.
|
|
24
|
+
* Hooks survive pinning (epic finding 5); they are surfaced separately so
|
|
25
|
+
* the install path can account for them, never silently dropped.
|
|
26
|
+
* - Everything else routes to the main group — the wrapper's `templates/`.
|
|
27
|
+
* A template-rendered `CustomResourceDefinition` stays here, because the
|
|
28
|
+
* `crds/`-segment is the discriminator, not the kind: a chart that
|
|
29
|
+
* templates its CRDs opted into template lifecycle semantics (upgrades
|
|
30
|
+
* and deletes apply to them), and moving them to `crds/` would change
|
|
31
|
+
* that. The routing notes it with a warning so the choice is visible.
|
|
32
|
+
*
|
|
33
|
+
* Aliased dependencies emit duplicate CRDs (epic finding 11): the same
|
|
34
|
+
* dependency included twice under an alias renders its `crds/` once per
|
|
35
|
+
* instance — two documents, one distinct CRD. The stored artifact keeps
|
|
36
|
+
* both (canonicalization is order- and duplicate-preserving), but a wrapper
|
|
37
|
+
* chart's `crds/` holds each CRD once, so the routed CRD group deduplicates
|
|
38
|
+
* by `(group, kind)`: the first occurrence wins and a warning names both
|
|
39
|
+
* sources. A CRD document that cannot be identified (unparseable, or
|
|
40
|
+
* missing `spec.group` / `spec.names.kind`) is never deduplicated — the
|
|
41
|
+
* routing must not silently drop what it cannot identify.
|
|
42
|
+
*
|
|
43
|
+
* The wrapper inherits the source chart's name and version (epic
|
|
44
|
+
* Decisions), keeping `helm history` continuous across the pinned
|
|
45
|
+
* migration; `RoutedRender.chart` / `chartVersion` carry them.
|
|
46
|
+
*
|
|
47
|
+
* This is the seam the pinned-install path (#1242) consumes:
|
|
48
|
+
* `routeStoredRender(contentDigest)` loads a stored render's canonical
|
|
49
|
+
* bytes and manifest and routes them.
|
|
50
|
+
*/
|
|
51
|
+
/** One routed document: exact bytes plus the labels routing derived from them. */
|
|
52
|
+
export interface RoutedDocument {
|
|
53
|
+
/**
|
|
54
|
+
* The document's exact text from the input stream (from just past the
|
|
55
|
+
* `---` separator, trimmed of surrounding blank lines — the same split
|
|
56
|
+
* `splitDocuments` performs). Never re-serialized: what deploys is what
|
|
57
|
+
* was recorded.
|
|
58
|
+
*/
|
|
59
|
+
text: string;
|
|
60
|
+
/**
|
|
61
|
+
* Chart-relative `# Source:` origin path (e.g. `crds/a.yaml`,
|
|
62
|
+
* `charts/kid/crds/kidcrd.yaml`), or `null` when the document carries no
|
|
63
|
+
* source header.
|
|
64
|
+
*/
|
|
65
|
+
source: string | null;
|
|
66
|
+
/** Kubernetes kind, or `null` when the document does not parse to a kinded object. */
|
|
67
|
+
kind: string | null;
|
|
68
|
+
/** apiVersion as rendered, or `null`. */
|
|
69
|
+
apiVersion: string | null;
|
|
70
|
+
/** `metadata.name`, or `null`. */
|
|
71
|
+
name: string | null;
|
|
72
|
+
}
|
|
73
|
+
/** Machine-readable warning categories the routing emits. */
|
|
74
|
+
export type RoutedRenderWarningCode = "duplicate-crd" | "template-crd";
|
|
75
|
+
export interface RoutedRenderWarning {
|
|
76
|
+
/**
|
|
77
|
+
* - `duplicate-crd` — an aliased dependency emitted the same CRD twice;
|
|
78
|
+
* the first occurrence was kept, the duplicate dropped. The message
|
|
79
|
+
* names both sources.
|
|
80
|
+
* - `template-crd` — a `CustomResourceDefinition` was rendered from
|
|
81
|
+
* `templates/` (no `crds/` segment in its origin). It stays in the main
|
|
82
|
+
* group per the segment rule; this note makes the lifecycle choice
|
|
83
|
+
* visible.
|
|
84
|
+
*/
|
|
85
|
+
code: RoutedRenderWarningCode;
|
|
86
|
+
message: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A pinned render routed into the structure the wrapper chart preserves.
|
|
90
|
+
* The document groups partition the input stream (minus deduplicated CRD
|
|
91
|
+
* duplicates, each named in `warnings`); no document is ever silently
|
|
92
|
+
* dropped and no document text is ever altered.
|
|
93
|
+
*/
|
|
94
|
+
export interface RoutedRender {
|
|
95
|
+
/**
|
|
96
|
+
* Wrapper chart name — inherited from the source chart, so `helm history`
|
|
97
|
+
* stays continuous across the pinned migration (epic Decisions).
|
|
98
|
+
*/
|
|
99
|
+
chart: string;
|
|
100
|
+
/** Wrapper chart version — inherited from the source chart; `null` for a local chart rendered without one. */
|
|
101
|
+
chartVersion: string | null;
|
|
102
|
+
/**
|
|
103
|
+
* Documents whose origin has a `crds/` segment — the wrapper's `crds/`,
|
|
104
|
+
* which is what keeps `helm uninstall` from deleting them (epic finding
|
|
105
|
+
* 4). Deduplicated by `(group, kind)`, first occurrence winning.
|
|
106
|
+
*/
|
|
107
|
+
crds: RoutedDocument[];
|
|
108
|
+
/**
|
|
109
|
+
* Hook-annotated template documents (`helm.sh/hook`), annotations intact.
|
|
110
|
+
* Routed as their own group so the install path can account for them —
|
|
111
|
+
* never silently dropped (epic finding 5).
|
|
112
|
+
*/
|
|
113
|
+
hooks: RoutedDocument[];
|
|
114
|
+
/** Everything else — the wrapper's `templates/`. */
|
|
115
|
+
main: RoutedDocument[];
|
|
116
|
+
/** What routing had to decide beyond the mechanical rule: dropped duplicates, template-rendered CRDs. */
|
|
117
|
+
warnings: RoutedRenderWarning[];
|
|
118
|
+
}
|
|
119
|
+
export interface RouteRenderOptions {
|
|
120
|
+
/** Source chart name — becomes the wrapper's name. */
|
|
121
|
+
chart: string;
|
|
122
|
+
/** Source chart version — becomes the wrapper's version. */
|
|
123
|
+
chartVersion?: string | null;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Route a rendered stream (canonical or raw `helm template` output) into
|
|
127
|
+
* `RoutedRender` groups. Pure over the stream: no store access, no helm.
|
|
128
|
+
*/
|
|
129
|
+
export declare function routeRender(rendered: string, opts: RouteRenderOptions): RoutedRender;
|
|
130
|
+
/**
|
|
131
|
+
* Route a stored pinned render by its `contentDigest`: loads the canonical
|
|
132
|
+
* bytes and the `RenderManifest` from the render store (#1238) and routes
|
|
133
|
+
* them, inheriting the manifest's chart name and version. This is the seam
|
|
134
|
+
* the pinned-install path (#1242) consumes. `undefined` when the store has
|
|
135
|
+
* no such entry.
|
|
136
|
+
*/
|
|
137
|
+
export declare function routeStoredRender(contentDigest: string, opts?: {
|
|
138
|
+
root?: string;
|
|
139
|
+
}): RoutedRender | undefined;
|
|
140
|
+
//# sourceMappingURL=render-wrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-wrapper.d.ts","sourceRoot":"","sources":["../src/render-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AASH,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,sFAAsF;IACtF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,yCAAyC;IACzC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,kCAAkC;IAClC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,6DAA6D;AAC7D,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG,cAAc,CAAC;AAEvE,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;OAQG;IACH,IAAI,EAAE,uBAAuB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,8GAA8G;IAC9G,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;OAIG;IACH,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB;;;;OAIG;IACH,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,oDAAoD;IACpD,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,yGAAyG;IACzG,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC;AA0DD,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,GAAG,YAAY,CA0DpF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACvB,YAAY,GAAG,SAAS,CAM1B"}
|
package/dist/render.d.ts
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
* values: { installCRDs: true },
|
|
31
31
|
* });
|
|
32
32
|
*/
|
|
33
|
+
import { type HelmCapabilityProfile, type HelmCapabilityProfileRef } from "./config.js";
|
|
33
34
|
export interface HelmRenderProps {
|
|
34
35
|
/** Logical name for the render (used in cache key + composite name). */
|
|
35
36
|
name: string;
|
|
@@ -50,6 +51,86 @@ export interface HelmRenderProps {
|
|
|
50
51
|
* fresh render.
|
|
51
52
|
*/
|
|
52
53
|
noCache?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Capability profile the render is pinned against (#1235, epic #1228).
|
|
56
|
+
*
|
|
57
|
+
* A string names a profile declared in `chant.config.ts`'s
|
|
58
|
+
* `helm.capabilityProfiles` (per cluster — see `./config.ts`); an inline
|
|
59
|
+
* object carries the same facts directly. When set, `helm template` runs
|
|
60
|
+
* with `--kube-version` and `--api-versions` from the profile, so
|
|
61
|
+
* `.Capabilities` reflects the declared cluster instead of whatever the
|
|
62
|
+
* helm binary defaults to. A named profile the config does not declare is
|
|
63
|
+
* an error at synth, never a silent fallback. Absent, rendering is
|
|
64
|
+
* unpinned — exactly today's behavior.
|
|
65
|
+
*/
|
|
66
|
+
capabilityProfile?: HelmCapabilityProfileRef;
|
|
67
|
+
/**
|
|
68
|
+
* Whether this render persists to the content-addressed render store
|
|
69
|
+
* (#1238) — canonical bytes under their `contentDigest` plus a
|
|
70
|
+
* `RenderManifest`, in `~/.chant/helm-renders/sha256-<hex>/` (see
|
|
71
|
+
* ./render-store.ts).
|
|
72
|
+
*
|
|
73
|
+
* Only a pinned render (capabilityProfile present) can persist — an
|
|
74
|
+
* unpinned render has no content identity, and `persist: true` on one is
|
|
75
|
+
* a synth error naming that reason. For pinned renders the default
|
|
76
|
+
* follows the cache knob: persistence is on unless `noCache` is set
|
|
77
|
+
* (`noCache: true` + `persist: true` forces a fresh render that is still
|
|
78
|
+
* persisted; `persist: false` turns the store off entirely).
|
|
79
|
+
*/
|
|
80
|
+
persist?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Source ref/commit to record in the persisted `RenderManifest`, when the
|
|
83
|
+
* caller has one. Never resolved implicitly and never fabricated — absent
|
|
84
|
+
* means the manifest records `sourceRef: null`.
|
|
85
|
+
*/
|
|
86
|
+
sourceRef?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* What one `HelmRender` invocation recorded about itself. `capabilityProfile`
|
|
90
|
+
* is the profile identity the render was pinned against; `undefined` means
|
|
91
|
+
* the render was unpinned and its bytes depend on the local helm binary's
|
|
92
|
+
* defaults.
|
|
93
|
+
*
|
|
94
|
+
* Pinned renders (profile present — the v1 gate, see #1237) also carry the
|
|
95
|
+
* digest pair:
|
|
96
|
+
*
|
|
97
|
+
* - `inputDigest` — `sha256:` over the canonical JSON of the declared inputs
|
|
98
|
+
* (chart reference, version, values, capability facts). Shared with the
|
|
99
|
+
* release-ledger digest #1243 records on deploy, via `helmInputDigest`.
|
|
100
|
+
* Answers "same inputs?" without touching any bytes.
|
|
101
|
+
* - `contentDigest` — `sha256:` over the canonical rendered bytes
|
|
102
|
+
* (`canonicalizeRender`). The artifact identity: answers "same bytes on
|
|
103
|
+
* the cluster?".
|
|
104
|
+
*
|
|
105
|
+
* They diverge exactly when the render is not a function of its declared
|
|
106
|
+
* inputs — `renderStability` in ./render-digest.ts names that.
|
|
107
|
+
*
|
|
108
|
+
* Unpinned renders record neither digest. Their bytes are a function of the
|
|
109
|
+
* local helm binary's defaulted capabilities, so a digest over them would
|
|
110
|
+
* assert an identity the render does not have — it would differ across
|
|
111
|
+
* machines that did nothing differently, and equal digests would still
|
|
112
|
+
* prove nothing about a cluster. No digest is the honest record.
|
|
113
|
+
*/
|
|
114
|
+
export interface HelmRenderRecord {
|
|
115
|
+
/** The render's logical name (`HelmRenderProps.name`) — also the helm release name baked into the bytes. */
|
|
116
|
+
name: string;
|
|
117
|
+
chart: string;
|
|
118
|
+
version?: string;
|
|
119
|
+
capabilityProfile?: HelmCapabilityProfile;
|
|
120
|
+
/** Input-side identity (#1237/#1243). Present only for pinned renders. */
|
|
121
|
+
inputDigest?: string;
|
|
122
|
+
/** Content-side identity over canonical rendered bytes (#1237). Present only for pinned renders. */
|
|
123
|
+
contentDigest?: string;
|
|
124
|
+
/**
|
|
125
|
+
* The build-time coalesced-values probe's digest (#1251), present only
|
|
126
|
+
* when the probe ran — a pinned render of a local chart (the probe needs
|
|
127
|
+
* the chart source on disk, so a repo-fetched chart never gets one).
|
|
128
|
+
*/
|
|
129
|
+
coalescedValuesDigest?: string;
|
|
53
130
|
}
|
|
131
|
+
/** Every render recorded in this process, in invocation order. */
|
|
132
|
+
export declare function getHelmRenderRecords(): readonly HelmRenderRecord[];
|
|
133
|
+
/** Reset the record list (test isolation). */
|
|
134
|
+
export declare function clearHelmRenderRecords(): void;
|
|
54
135
|
export declare const HelmRender: import("@intentius/chant").CompositeDefinition<HelmRenderProps, import("@intentius/chant").CompositeMembers>;
|
|
55
136
|
//# sourceMappingURL=render.d.ts.map
|
package/dist/render.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAeH,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAeH,OAAO,EAA4B,KAAK,qBAAqB,EAAE,KAAK,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAU/G,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4GAA4G;IAC5G,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,qBAAqB,CAAC;IAC1C,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAID,kEAAkE;AAClE,wBAAgB,oBAAoB,IAAI,SAAS,gBAAgB,EAAE,CAElE;AAED,8CAA8C;AAC9C,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAmRD,eAAO,MAAM,UAAU,8GAsFP,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHM503: Pinned render artifact carries Secret data.
|
|
3
|
+
*
|
|
4
|
+
* WHM407 covers the pre-render concern — a chart TEMPLATE with an inline,
|
|
5
|
+
* literal `data`/`stringData` value baked into `templates/`. This rule
|
|
6
|
+
* covers a different concern (#1241, epic #1228 Phase 3): the STORED,
|
|
7
|
+
* POST-RENDER artifact (`render-store.ts`, #1238). A pinned render is
|
|
8
|
+
* durable, promoted, and pushed to a registry — unlike a normal `helm
|
|
9
|
+
* upgrade`, whose rendered bytes are computed at deploy time and discarded.
|
|
10
|
+
* By the time a render lands in the store, every `.Values` reference and
|
|
11
|
+
* `{{ }}` expression is resolved, so a `kind: Secret` document with
|
|
12
|
+
* populated `data`/`stringData` there is a live credential baked into
|
|
13
|
+
* something that outlives the deploy that produced it.
|
|
14
|
+
*
|
|
15
|
+
* Scans every pinned render recorded so far in this process
|
|
16
|
+
* (`getHelmRenderRecords()` from `../../render`) that carries a
|
|
17
|
+
* `contentDigest`, loads its manifest + canonical content from the render
|
|
18
|
+
* store, and flags any `Secret` document whose `data` or `stringData` is
|
|
19
|
+
* non-empty.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
23
|
+
import yaml from "js-yaml";
|
|
24
|
+
|
|
25
|
+
import type { HelmRenderRecord } from "../../render";
|
|
26
|
+
import { getHelmRenderRecords } from "../../render";
|
|
27
|
+
import { loadRenderManifest, readRenderDocument } from "../../render-store";
|
|
28
|
+
|
|
29
|
+
interface ParsedSecretDoc {
|
|
30
|
+
data?: unknown;
|
|
31
|
+
stringData?: unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** True when a `data`/`stringData` map carries at least one key. */
|
|
35
|
+
function isPopulated(value: unknown): boolean {
|
|
36
|
+
return typeof value === "object" && value !== null && Object.keys(value).length > 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Scan a set of `HelmRenderRecord`s for pinned renders whose stored artifact
|
|
41
|
+
* carries a `Secret` document with populated `data`/`stringData`. Exported
|
|
42
|
+
* separately from `whm503` so tests can drive it directly with hand-built
|
|
43
|
+
* records — no real `helm` binary required, unlike a `HelmRender()` call.
|
|
44
|
+
* `opts.root` overrides the render store root (test isolation).
|
|
45
|
+
*/
|
|
46
|
+
export function checkRenderRecordsForSecrets(
|
|
47
|
+
records: readonly HelmRenderRecord[],
|
|
48
|
+
opts?: { root?: string },
|
|
49
|
+
): PostSynthDiagnostic[] {
|
|
50
|
+
const diagnostics: PostSynthDiagnostic[] = [];
|
|
51
|
+
|
|
52
|
+
for (const record of records) {
|
|
53
|
+
if (!record.contentDigest) continue; // unpinned — no stored artifact to scan
|
|
54
|
+
|
|
55
|
+
const manifest = loadRenderManifest(record.contentDigest, opts);
|
|
56
|
+
if (!manifest) continue; // recorded but not (or no longer) in the store
|
|
57
|
+
|
|
58
|
+
for (const doc of manifest.documents) {
|
|
59
|
+
if (doc.kind !== "Secret") continue;
|
|
60
|
+
|
|
61
|
+
const found = readRenderDocument(record.contentDigest, { kind: doc.kind, name: doc.name, namespace: doc.namespace }, opts);
|
|
62
|
+
if (!found) continue;
|
|
63
|
+
|
|
64
|
+
let parsed: ParsedSecretDoc;
|
|
65
|
+
try {
|
|
66
|
+
parsed = (yaml.load(found.text) ?? {}) as ParsedSecretDoc;
|
|
67
|
+
} catch {
|
|
68
|
+
continue; // unparseable — not this check's problem to diagnose
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!isPopulated(parsed.data) && !isPopulated(parsed.stringData)) continue;
|
|
72
|
+
|
|
73
|
+
const locator = doc.namespace ? `${doc.namespace}/${doc.name}` : doc.name;
|
|
74
|
+
diagnostics.push({
|
|
75
|
+
checkId: "WHM503",
|
|
76
|
+
severity: "error",
|
|
77
|
+
message:
|
|
78
|
+
`pinned render "${record.name}" (${record.chart}, ${record.contentDigest}): Secret "${locator}" ` +
|
|
79
|
+
`carries populated data/stringData — a pinned render is stored, promoted, and pushed to a registry, ` +
|
|
80
|
+
`so this bakes a live credential into a durable artifact. Declare the value with runtimeSlot() so ` +
|
|
81
|
+
`it is supplied per environment, or replace this Secret with HelmExternalSecret.`,
|
|
82
|
+
entity: locator,
|
|
83
|
+
lexicon: "helm",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return diagnostics;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const whm503: PostSynthCheck = {
|
|
92
|
+
id: "WHM503",
|
|
93
|
+
description: "Pinned render artifact must not carry populated Secret data/stringData",
|
|
94
|
+
|
|
95
|
+
// This check's data source is the render store (#1238), not `ctx.outputs`
|
|
96
|
+
// (the un-rendered chart template files WHM005-WHM502 read) — see the file
|
|
97
|
+
// doc comment. `ctx` is accepted to satisfy `PostSynthCheck` and is unused.
|
|
98
|
+
check(_ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
99
|
+
return checkRenderRecordsForSecrets(getHelmRenderRecords());
|
|
100
|
+
},
|
|
101
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHM504: Dead value assignment (#1252, epic #1228 Phase 7).
|
|
3
|
+
*
|
|
4
|
+
* A supplied value that never survives coalescing is a lie in the config:
|
|
5
|
+
* it reads as if it configures something, and nothing ever sees it. The
|
|
6
|
+
* coalesced-values probe (#1251, ../../values-probe.ts) knows three ways a
|
|
7
|
+
* supplied value dies — shadowed by a later supplied layer, targeting a
|
|
8
|
+
* dependency a `condition:` disabled, or a values map under a top-level key
|
|
9
|
+
* that names no dependency at all (the silently-ignored subchart typo).
|
|
10
|
+
*
|
|
11
|
+
* The check reports over the probe records of the current process
|
|
12
|
+
* (`getValuesProbeRecords`): whatever ran the probe — the pinned-render
|
|
13
|
+
* build path, a test, a direct call — this check turns its dead assignments
|
|
14
|
+
* into diagnostics. No probe run, nothing to report; the probe itself needs
|
|
15
|
+
* the helm binary and the chart source, which a post-synth check must not
|
|
16
|
+
* require on its own.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
20
|
+
import { getValuesProbeRecords, type DeadAssignment } from "../../values-probe";
|
|
21
|
+
|
|
22
|
+
function describe(dead: DeadAssignment): string {
|
|
23
|
+
switch (dead.reason) {
|
|
24
|
+
case "shadowed":
|
|
25
|
+
return `supplied value "${dead.path}" (${dead.origin}) never survives coalescing — shadowed by ${dead.shadowedBy}`;
|
|
26
|
+
case "disabled-subchart":
|
|
27
|
+
return `supplied value "${dead.path}" (${dead.origin}) targets a disabled subchart — ${dead.shadowedBy}`;
|
|
28
|
+
case "unknown-subchart":
|
|
29
|
+
return `supplied values under "${dead.path}" (${dead.origin}) target no subchart — ${dead.shadowedBy}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const whm504: PostSynthCheck = {
|
|
34
|
+
id: "WHM504",
|
|
35
|
+
description: "Detect supplied values that never survive coalescing (shadowed, disabled subchart, unknown subchart)",
|
|
36
|
+
|
|
37
|
+
check(_ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
38
|
+
const diagnostics: PostSynthDiagnostic[] = [];
|
|
39
|
+
for (const record of getValuesProbeRecords()) {
|
|
40
|
+
for (const dead of record.probe.deadAssignments) {
|
|
41
|
+
diagnostics.push({
|
|
42
|
+
checkId: "WHM504",
|
|
43
|
+
severity: "warning",
|
|
44
|
+
message: describe(dead),
|
|
45
|
+
entity: record.name,
|
|
46
|
+
lexicon: "helm",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return diagnostics;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -289,6 +289,13 @@ const lifecycle = HelmCRDLifecycle({
|
|
|
289
289
|
| WHM407 | post-synth | Secret with inline data |
|
|
290
290
|
| WHM501 | post-synth | Unused values keys |
|
|
291
291
|
| WHM502 | post-synth | Deprecated K8s API versions |
|
|
292
|
+
| WHM503 | pinned-render | Pinned render artifact carries populated Secret data/stringData — use `runtimeSlot()` or `HelmExternalSecret` |
|
|
293
|
+
|
|
294
|
+
WHM503 is a different stage from the rest: it scans the STORED, rendered
|
|
295
|
+
artifact a pinned `HelmRender` writes to the render store (#1238), not the
|
|
296
|
+
chart source `WHM005`-`WHM502` validate. `WHM407` catches an inline literal
|
|
297
|
+
in a chart TEMPLATE before rendering; WHM503 catches a resolved credential
|
|
298
|
+
that made it into a durable, promotable artifact.
|
|
292
299
|
|
|
293
300
|
## OCI registry workflow
|
|
294
301
|
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time coalesced-values probe (#1251, epic #1228 Phase 7) and the
|
|
3
|
+
* provenance derived from it (#1252).
|
|
4
|
+
*
|
|
5
|
+
* `helm template --debug` does not print coalesced values on either major
|
|
6
|
+
* version, and `helm get values --all` needs an installed release — the
|
|
7
|
+
* wrong side of the build/deploy line. So the probe extracts them from helm
|
|
8
|
+
* itself: copy the chart, replace every (sub)chart's `templates/` with a
|
|
9
|
+
* single `chant-values-probe.yaml` template containing `{{ toYaml .Values }}`,
|
|
10
|
+
* render, lift the probe documents out, discard the copy. Coalescing —
|
|
11
|
+
* parent-overrides-child, `global` propagation, alias scoping,
|
|
12
|
+
* `import-values`, tags — is delegated to helm rather than reimplemented
|
|
13
|
+
* (the approximation in `pinnability/values.ts` remains only as the
|
|
14
|
+
* classifier's offline fallback).
|
|
15
|
+
*
|
|
16
|
+
* The probe filename must NOT begin with `_`: helm treats underscore-prefixed
|
|
17
|
+
* template files as partials and skips them without error.
|
|
18
|
+
*
|
|
19
|
+
* The probe runs against a private copy in a temp directory, so the probe
|
|
20
|
+
* document can never appear in a real render of the chart — the pinned
|
|
21
|
+
* artifact path (#1237/#1242) never sees the injected template.
|
|
22
|
+
*
|
|
23
|
+
* A dependency disabled by a `condition:` (or tags) is pruned by helm before
|
|
24
|
+
* rendering, so it yields no probe document. Those instances are reported in
|
|
25
|
+
* `disabled` instead, with the condition path where determinable. Note the
|
|
26
|
+
* ROOT probe document still carries the values subtree a disabled dependency
|
|
27
|
+
* would have received — an installed release omits it (epic findings 14, 15).
|
|
28
|
+
*
|
|
29
|
+
* On the probe output, three provenance products (#1252):
|
|
30
|
+
*
|
|
31
|
+
* - `digest` — `sha256:` over the canonical JSON (core's `canonicalJson`,
|
|
32
|
+
* the #1237 convention) of the per-instance coalesced trees, keyed by
|
|
33
|
+
* scope path. Same inputs, same coalesced values, same digest.
|
|
34
|
+
* - `valueSources` — each coalesced path attributed to its winning layer:
|
|
35
|
+
* chart default / parent override / supplied file / --set.
|
|
36
|
+
* - `deadAssignments` — supplied values that never survive coalescing:
|
|
37
|
+
* shadowed by a later supplied layer, or targeting a disabled or unknown
|
|
38
|
+
* subchart path. WHM504 turns these into lint diagnostics.
|
|
39
|
+
*/
|
|
40
|
+
/** Where a coalesced value came from. `computed` = no supplied or authored layer matches (e.g. `import-values`). */
|
|
41
|
+
export type ValueOrigin = "chart default" | "parent override" | "supplied file" | "--set" | "computed";
|
|
42
|
+
/**
|
|
43
|
+
* One layer of values supplied to the render, in ascending precedence order
|
|
44
|
+
* (a later layer overrides an earlier one, like repeated `--values` flags;
|
|
45
|
+
* `--set` layers conventionally come last). `origin` is the label reported
|
|
46
|
+
* by `valueSources` and dead-assignment findings.
|
|
47
|
+
*/
|
|
48
|
+
export interface SuppliedValuesLayer {
|
|
49
|
+
origin: "supplied file" | "--set";
|
|
50
|
+
/** Optional identifier (a file path, a flag) used in messages. */
|
|
51
|
+
name?: string;
|
|
52
|
+
values: Record<string, unknown>;
|
|
53
|
+
}
|
|
54
|
+
/** One chart instance and the values helm coalesced for it. */
|
|
55
|
+
export interface CoalescedChartValues {
|
|
56
|
+
/** Value scope from the root: `[]` for the root chart, `["kidtwo"]` for an aliased dependency, nested for grandchildren. */
|
|
57
|
+
scope: string[];
|
|
58
|
+
/** `.Chart.Name` as rendered — the alias for an aliased dependency. */
|
|
59
|
+
chartName: string;
|
|
60
|
+
/** The fully coalesced values this instance saw, exactly as helm computed them. */
|
|
61
|
+
values: Record<string, unknown>;
|
|
62
|
+
}
|
|
63
|
+
/** A declared dependency helm pruned before rendering. */
|
|
64
|
+
export interface DisabledDependency {
|
|
65
|
+
scope: string[];
|
|
66
|
+
/** The dependency's real chart name (not the alias). */
|
|
67
|
+
name: string;
|
|
68
|
+
/** The `condition:` path that resolved false, when determinable (tags-disabled dependencies carry none). */
|
|
69
|
+
condition?: string;
|
|
70
|
+
}
|
|
71
|
+
/** A supplied value that never survives coalescing. */
|
|
72
|
+
export interface DeadAssignment {
|
|
73
|
+
/** Dot-joined path in root coordinates. */
|
|
74
|
+
path: string;
|
|
75
|
+
/** The layer that supplied it, e.g. `supplied file (values-prod.yaml)`. */
|
|
76
|
+
origin: string;
|
|
77
|
+
reason: "shadowed" | "disabled-subchart" | "unknown-subchart";
|
|
78
|
+
/** What killed it: the shadowing layer, or the disabling condition. */
|
|
79
|
+
shadowedBy?: string;
|
|
80
|
+
}
|
|
81
|
+
export interface CoalescedValuesProbe {
|
|
82
|
+
/** Enabled chart instances, root first, then by scope path. */
|
|
83
|
+
instances: CoalescedChartValues[];
|
|
84
|
+
disabled: DisabledDependency[];
|
|
85
|
+
/** `sha256:` over the canonical JSON of the per-instance coalesced trees. */
|
|
86
|
+
digest: string;
|
|
87
|
+
/** Dot-joined path (root coordinates, subchart paths scope-prefixed) to winning layer. */
|
|
88
|
+
valueSources: Record<string, ValueOrigin>;
|
|
89
|
+
deadAssignments: DeadAssignment[];
|
|
90
|
+
warnings: string[];
|
|
91
|
+
}
|
|
92
|
+
export interface ValuesProbeOptions {
|
|
93
|
+
/** Directory of the chart to probe (must contain Chart.yaml). Never modified — the probe works on a copy. */
|
|
94
|
+
chartDir: string;
|
|
95
|
+
/** Logical name recorded with the probe. Defaults to the release name. */
|
|
96
|
+
name?: string;
|
|
97
|
+
/** Release name passed to `helm template`. Default `chant-values-probe`. */
|
|
98
|
+
releaseName?: string;
|
|
99
|
+
namespace?: string;
|
|
100
|
+
/** Values layers in ascending precedence order. */
|
|
101
|
+
supplied?: SuppliedValuesLayer[];
|
|
102
|
+
/** Injectable helm runner (tests). Receives the full argv after `helm`. */
|
|
103
|
+
runHelm?: (args: string[]) => string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The coalesced-values identity: `sha256:` over the canonical JSON of the
|
|
107
|
+
* per-instance trees keyed by scope path — the #1237 digest conventions
|
|
108
|
+
* (core `canonicalJson`, `sha256:` prefix). Two renders that coalesce the
|
|
109
|
+
* same values for every instance share it; any value, in any subchart,
|
|
110
|
+
* changing breaks it.
|
|
111
|
+
*/
|
|
112
|
+
export declare function coalescedValuesDigest(instances: readonly CoalescedChartValues[]): string;
|
|
113
|
+
/** Inputs the pure provenance analysis needs — separable from the render for tests. */
|
|
114
|
+
export interface ValuesAttributionInput {
|
|
115
|
+
instances: readonly CoalescedChartValues[];
|
|
116
|
+
supplied: readonly SuppliedValuesLayer[];
|
|
117
|
+
/** The chart-default `values.yaml` for an instance scope; undefined when unknown. */
|
|
118
|
+
defaultsFor: (scope: readonly string[]) => Record<string, unknown> | undefined;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Attribute each coalesced path to the layer that won it.
|
|
122
|
+
*
|
|
123
|
+
* Keys are dot-joined root-coordinate paths: a subchart instance's paths are
|
|
124
|
+
* prefixed with its scope, so `kidtwo.replicas` is the `replicas` the
|
|
125
|
+
* `kidtwo` instance actually sees. A key of an instance's tree that is
|
|
126
|
+
* itself an enabled child scope is skipped — helm pushes the child's
|
|
127
|
+
* coalesced tree back into the parent's `.Values`, and the child instance
|
|
128
|
+
* owns those paths.
|
|
129
|
+
*
|
|
130
|
+
* Layer precedence mirrors helm: supplied layers (last first), then ancestor
|
|
131
|
+
* chart defaults (root outranks intermediates — "parent override"), then the
|
|
132
|
+
* instance's own defaults ("chart default"). A path no layer explains — an
|
|
133
|
+
* `import-values` product, a helm-computed merge — reports `computed`.
|
|
134
|
+
* Attribution matches on value equality, so a layer that assigned a path but
|
|
135
|
+
* lost it reports as the layer that actually won.
|
|
136
|
+
*/
|
|
137
|
+
export declare function computeValueSources(input: ValuesAttributionInput): Record<string, ValueOrigin>;
|
|
138
|
+
/**
|
|
139
|
+
* Supplied values that never survive coalescing:
|
|
140
|
+
*
|
|
141
|
+
* - `shadowed` — a later supplied layer assigns the same path (a map merging
|
|
142
|
+
* into a map is not a shadow; anything else replaces).
|
|
143
|
+
* - `disabled-subchart` — the path targets a dependency a `condition:` (or
|
|
144
|
+
* tags) disabled, so no rendered chart ever reads it.
|
|
145
|
+
* - `unknown-subchart` — a map supplied under a top-level key that matches
|
|
146
|
+
* no dependency, no root default, and not `global`, on a chart that HAS
|
|
147
|
+
* dependencies: the classic silently-ignored typo of a subchart name.
|
|
148
|
+
* Reported once per top-level key per layer.
|
|
149
|
+
*/
|
|
150
|
+
export declare function findDeadAssignments(input: ValuesAttributionInput, disabled: readonly DisabledDependency[]): DeadAssignment[];
|
|
151
|
+
/**
|
|
152
|
+
* Run the probe: copy the chart, inject probe templates, render, lift the
|
|
153
|
+
* probe documents out, analyze, discard the copy. The source chart is never
|
|
154
|
+
* touched. Every run is recorded for WHM504 (`getValuesProbeRecords`).
|
|
155
|
+
*/
|
|
156
|
+
export declare function probeCoalescedValues(options: ValuesProbeOptions): CoalescedValuesProbe;
|
|
157
|
+
/** What one probe run recorded about itself — the WHM504 lint surface. */
|
|
158
|
+
export interface HelmValuesProbeRecord {
|
|
159
|
+
name: string;
|
|
160
|
+
chartDir: string;
|
|
161
|
+
probe: CoalescedValuesProbe;
|
|
162
|
+
}
|
|
163
|
+
/** Every probe recorded in this process, in invocation order. */
|
|
164
|
+
export declare function getValuesProbeRecords(): readonly HelmValuesProbeRecord[];
|
|
165
|
+
/** Record a probe computed elsewhere (the render path integration point). */
|
|
166
|
+
export declare function recordValuesProbe(record: HelmValuesProbeRecord): void;
|
|
167
|
+
/** Reset the record list (test isolation). */
|
|
168
|
+
export declare function clearValuesProbeRecords(): void;
|
|
169
|
+
/**
|
|
170
|
+
* The values gap between the probe and an installed release: an installed
|
|
171
|
+
* release's `helm get values --all` omits subtrees for disabled
|
|
172
|
+
* dependencies; the probe's root document keeps them (epic findings 14, 15).
|
|
173
|
+
* On shared keys the two agree — this helper names the shared-key view for
|
|
174
|
+
* comparisons against a live release.
|
|
175
|
+
*/
|
|
176
|
+
export declare function rootCoalescedValues(probe: CoalescedValuesProbe): Record<string, unknown>;
|
|
177
|
+
//# sourceMappingURL=values-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values-probe.d.ts","sourceRoot":"","sources":["../src/values-probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrapper-chart materialization for the pinned install path (#1242, epic
|
|
3
|
+
* #1228 Phase 4).
|
|
4
|
+
*
|
|
5
|
+
* Turns a `RoutedRender` (#1239) into an installable helm chart on disk.
|
|
6
|
+
* The wrapper preserves the recorded bytes exactly:
|
|
7
|
+
*
|
|
8
|
+
* - CRD-group documents are written verbatim into the wrapper's `crds/`,
|
|
9
|
+
* which is what keeps `helm uninstall` from deleting them — the A/B test
|
|
10
|
+
* behind epic finding 4 showed a flat wrap converts uninstall from safe
|
|
11
|
+
* to data-destroying.
|
|
12
|
+
* - Every other document (main and hook groups) is written verbatim into
|
|
13
|
+
* `manifests/`, and each gets a one-line shim in `templates/` that reads
|
|
14
|
+
* it back with `.Files.Get`. The shim exists because rendered output can
|
|
15
|
+
* legitimately contain template-looking text — a ConfigMap carrying
|
|
16
|
+
* alertmanager notification templates renders `{{ $labels }}` as literal
|
|
17
|
+
* bytes — and a document placed directly in `templates/` would be run
|
|
18
|
+
* through the template engine a second time, mangling or failing on
|
|
19
|
+
* exactly those bytes. `.Files.Get` returns file content untemplated, so
|
|
20
|
+
* what helm installs is what the render store recorded.
|
|
21
|
+
* - Hook documents go through the same shim; their `helm.sh/hook`
|
|
22
|
+
* annotations are part of the recorded bytes, so helm registers and runs
|
|
23
|
+
* them from the rendered output unchanged (epic finding 5).
|
|
24
|
+
*
|
|
25
|
+
* The wrapper inherits the source chart's name and version (epic
|
|
26
|
+
* Decisions), keeping `helm history` continuous across the pinned
|
|
27
|
+
* migration. A local chart path becomes its sanitized basename — helm
|
|
28
|
+
* requires a bare chart name — and a render recorded without a version
|
|
29
|
+
* falls back to `0.0.0`.
|
|
30
|
+
*/
|
|
31
|
+
import type { RoutedRender } from "./render-wrapper.js";
|
|
32
|
+
/** What `materializeWrapperChart` wrote, with the counts the install result reports. */
|
|
33
|
+
export interface MaterializedWrapperChart {
|
|
34
|
+
/** Chart root directory — the `helm upgrade --install` argument. */
|
|
35
|
+
dir: string;
|
|
36
|
+
/** Wrapper chart name (sanitized from the source chart reference). */
|
|
37
|
+
chartName: string;
|
|
38
|
+
/** Wrapper chart version (`0.0.0` when the render recorded none). */
|
|
39
|
+
chartVersion: string;
|
|
40
|
+
/** Files written under `crds/`, chart-relative. */
|
|
41
|
+
crdFiles: string[];
|
|
42
|
+
/** Verbatim document files written under `manifests/`, chart-relative, in emit order. */
|
|
43
|
+
manifestFiles: string[];
|
|
44
|
+
/** Number of hook documents among `manifestFiles`. */
|
|
45
|
+
hookCount: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A valid helm chart name from a chart reference that may be a local path
|
|
49
|
+
* (`./charts/web`) or a repo-qualified name. Takes the last path segment,
|
|
50
|
+
* lowercases it, and collapses anything outside `[a-z0-9-]` to `-` — helm
|
|
51
|
+
* chart names are DNS-label-shaped. Falls back to `pinned-chart` when
|
|
52
|
+
* nothing survives.
|
|
53
|
+
*/
|
|
54
|
+
export declare function wrapperChartName(chart: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Write `routed` as an installable wrapper chart under `dir` (which must
|
|
57
|
+
* exist and should be empty). Document text is written byte-for-byte; the
|
|
58
|
+
* only authored files are `Chart.yaml` and the `.Files.Get` shims.
|
|
59
|
+
*/
|
|
60
|
+
export declare function materializeWrapperChart(routed: RoutedRender, dir: string): MaterializedWrapperChart;
|
|
61
|
+
//# sourceMappingURL=wrapper-chart.d.ts.map
|