@intentius/chant-lexicon-helm 0.45.0 → 0.49.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 +18 -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 +1 -1
- 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/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 +98 -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/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 +47 -0
- 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,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Go template action extraction and control-flow scoping (#1234, epic #1228).
|
|
3
|
+
*
|
|
4
|
+
* The pinnability gate inspects template ACTIONS (`{{ ... }}`), never raw
|
|
5
|
+
* text. That distinction is finding 9: cert-manager carries 52 textual
|
|
6
|
+
* "lookup" occurrences, all comment prose, and a real template-action count
|
|
7
|
+
* of 0 — a text-matching gate refuses a chart that is perfectly pinnable.
|
|
8
|
+
*
|
|
9
|
+
* Beyond extraction, this module reconstructs the control-flow structure of a
|
|
10
|
+
* template file — which `if` / `with` / `range` blocks enclose each action —
|
|
11
|
+
* so the classifier can ask whether a construct is REACHABLE under the
|
|
12
|
+
* supplied values, not merely present. Reachability is what separates
|
|
13
|
+
* "unpinnable" from "pinnable with a recorded conditional hazard": bundled
|
|
14
|
+
* grafana's control-flow `lookup` sits behind `persistence.enabled`, off by
|
|
15
|
+
* default, so a default-values render never consults the cluster.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export type ActionKind =
|
|
19
|
+
| "if"
|
|
20
|
+
| "elseif"
|
|
21
|
+
| "else"
|
|
22
|
+
| "with"
|
|
23
|
+
| "range"
|
|
24
|
+
| "define"
|
|
25
|
+
| "block"
|
|
26
|
+
| "end"
|
|
27
|
+
| "other";
|
|
28
|
+
|
|
29
|
+
export interface TemplateAction {
|
|
30
|
+
/** Path of the file the action was found in (as given by the caller). */
|
|
31
|
+
file: string;
|
|
32
|
+
/** 1-based line the action starts on. */
|
|
33
|
+
line: number;
|
|
34
|
+
/** The action body between `{{` and `}}`, trim markers stripped. */
|
|
35
|
+
body: string;
|
|
36
|
+
/** Structural role of the action, from its leading keyword. */
|
|
37
|
+
kind: ActionKind;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* One enclosing control-flow frame for an action. `conditions` are the
|
|
42
|
+
* expressions that must hold for the frame's branch to run; `negatedConditions`
|
|
43
|
+
* are prior branch conditions that must NOT hold (an `else` / `else if`
|
|
44
|
+
* branch runs only when every earlier branch condition was false).
|
|
45
|
+
*/
|
|
46
|
+
export interface ScopeFrame {
|
|
47
|
+
kind: "if" | "with" | "range" | "define" | "block" | "dependency-condition";
|
|
48
|
+
conditions: string[];
|
|
49
|
+
negatedConditions: string[];
|
|
50
|
+
/**
|
|
51
|
+
* When a `with` block pins the dot to a `.Values` subtree, the path of that
|
|
52
|
+
* subtree — so bare `.enabled` inside `with .Values.persistence` resolves
|
|
53
|
+
* to `persistence.enabled`. `undefined` means the dot is unresolvable
|
|
54
|
+
* (a `range` element, a non-values `with`, a `define` invoked from an
|
|
55
|
+
* unknown context).
|
|
56
|
+
*/
|
|
57
|
+
dotValuesPath?: string[];
|
|
58
|
+
/** Dot is rebound to something we cannot resolve (range element etc.). */
|
|
59
|
+
dotUnresolvable?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ScopedAction {
|
|
63
|
+
action: TemplateAction;
|
|
64
|
+
/** Enclosing frames, outermost first. Empty for top-level actions. */
|
|
65
|
+
frames: ScopeFrame[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const KIND_RE =
|
|
69
|
+
/^(if\b|else\s+if\b|else\b|with\b|range\b|define\b|block\b|end\b)/;
|
|
70
|
+
|
|
71
|
+
function kindOf(body: string): ActionKind {
|
|
72
|
+
const m = body.match(KIND_RE);
|
|
73
|
+
if (!m) return "other";
|
|
74
|
+
const kw = m[1].replace(/\s+/g, " ").trim();
|
|
75
|
+
if (kw === "else if") return "elseif";
|
|
76
|
+
return kw.replace(/\b\s.*$/, "") as ActionKind;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Extract template actions from a source file, skipping comment actions
|
|
81
|
+
* (`{{/* ... *\/}}`). Text outside actions — including YAML `#` comments,
|
|
82
|
+
* where finding 9's 52 false positives lived — is never inspected by any
|
|
83
|
+
* scan built on this.
|
|
84
|
+
*/
|
|
85
|
+
export function extractActions(source: string, file: string): TemplateAction[] {
|
|
86
|
+
const actions: TemplateAction[] = [];
|
|
87
|
+
let i = 0;
|
|
88
|
+
let line = 1;
|
|
89
|
+
let lineScanPos = 0;
|
|
90
|
+
const lineAt = (pos: number): number => {
|
|
91
|
+
// Incremental line counting: `pos` is monotonically increasing.
|
|
92
|
+
for (; lineScanPos < pos; lineScanPos++) {
|
|
93
|
+
if (source[lineScanPos] === "\n") line += 1;
|
|
94
|
+
}
|
|
95
|
+
return line;
|
|
96
|
+
};
|
|
97
|
+
while (i < source.length) {
|
|
98
|
+
const open = source.indexOf("{{", i);
|
|
99
|
+
if (open === -1) break;
|
|
100
|
+
const actionLine = lineAt(open);
|
|
101
|
+
// Body starts after `{{` and an optional trim marker.
|
|
102
|
+
let bodyStart = open + 2;
|
|
103
|
+
if (source[bodyStart] === "-") bodyStart += 1;
|
|
104
|
+
const rest = source.slice(bodyStart);
|
|
105
|
+
// Comment action: {{/* ... */}} — skip to its closing */}}.
|
|
106
|
+
if (/^\s*\/\*/.test(rest)) {
|
|
107
|
+
const closeComment = source.indexOf("*/", bodyStart);
|
|
108
|
+
if (closeComment === -1) break;
|
|
109
|
+
const close = source.indexOf("}}", closeComment);
|
|
110
|
+
i = close === -1 ? source.length : close + 2;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const close = source.indexOf("}}", bodyStart);
|
|
114
|
+
if (close === -1) break;
|
|
115
|
+
let body = source.slice(bodyStart, close);
|
|
116
|
+
if (body.endsWith("-")) body = body.slice(0, -1);
|
|
117
|
+
body = body.trim();
|
|
118
|
+
actions.push({ file, line: actionLine, body, kind: kindOf(body) });
|
|
119
|
+
i = close + 2;
|
|
120
|
+
}
|
|
121
|
+
return actions;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The pipeline of an action, structural keyword and variable assignment
|
|
126
|
+
* stripped: `if X` → `X`, `range $i, $v := X` → `X`, `$pw := X` → `X`.
|
|
127
|
+
* This is what condition evaluation and call-reachability parse.
|
|
128
|
+
*/
|
|
129
|
+
export function actionPipeline(action: TemplateAction): string {
|
|
130
|
+
let expr = action.body.replace(KIND_RE, "").trim();
|
|
131
|
+
// `range $i, $v := .Values.x` / `$pw := .Values.x` — the pipeline is what
|
|
132
|
+
// follows the assignment.
|
|
133
|
+
const assign = expr.match(/^\$[\w]*\s*(?:,\s*\$[\w]*\s*)?:?=\s*(.*)$/);
|
|
134
|
+
if (assign) expr = assign[1].trim();
|
|
135
|
+
return expr;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
/** `.Values.a.b` (or `$.Values.a.b`) as a path array, else undefined. */
|
|
140
|
+
function valuesPathOf(expr: string): string[] | undefined {
|
|
141
|
+
const m = expr.match(/^\$?\.Values((?:\.[A-Za-z0-9_-]+)+)$/);
|
|
142
|
+
return m ? m[1].slice(1).split(".") : undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
interface BranchState {
|
|
146
|
+
frame: ScopeFrame;
|
|
147
|
+
/** All branch conditions seen so far in this if-chain. */
|
|
148
|
+
chain: string[];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Walk a file's actions and attach the enclosing control-flow frames to each.
|
|
153
|
+
* `else` / `else if` branches carry the prior branch conditions as
|
|
154
|
+
* `negatedConditions`. Structure that cannot be tracked (an unbalanced
|
|
155
|
+
* `end`, template text split across files) degrades to fewer frames — which
|
|
156
|
+
* only ever makes the classifier MORE conservative, never less: a missing
|
|
157
|
+
* frame means a gate we cannot prove closed.
|
|
158
|
+
*/
|
|
159
|
+
export function scopeActions(actions: TemplateAction[]): ScopedAction[] {
|
|
160
|
+
const scoped: ScopedAction[] = [];
|
|
161
|
+
const stack: BranchState[] = [];
|
|
162
|
+
|
|
163
|
+
for (const action of actions) {
|
|
164
|
+
switch (action.kind) {
|
|
165
|
+
case "if": {
|
|
166
|
+
const cond = actionPipeline(action);
|
|
167
|
+
// The `if` action itself is evaluated in the ENCLOSING scope.
|
|
168
|
+
scoped.push({ action, frames: stack.map((s) => s.frame) });
|
|
169
|
+
stack.push({
|
|
170
|
+
frame: { kind: "if", conditions: [cond], negatedConditions: [] },
|
|
171
|
+
chain: [cond],
|
|
172
|
+
});
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
case "elseif": {
|
|
176
|
+
scoped.push({
|
|
177
|
+
action,
|
|
178
|
+
frames: stack.slice(0, -1).map((s) => s.frame),
|
|
179
|
+
});
|
|
180
|
+
const top = stack[stack.length - 1];
|
|
181
|
+
const cond = action.body.replace(/^else\s+if\b/, "").trim();
|
|
182
|
+
if (top) {
|
|
183
|
+
top.frame = {
|
|
184
|
+
kind: "if",
|
|
185
|
+
conditions: [cond],
|
|
186
|
+
negatedConditions: [...top.chain],
|
|
187
|
+
};
|
|
188
|
+
top.chain.push(cond);
|
|
189
|
+
}
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
case "else": {
|
|
193
|
+
scoped.push({
|
|
194
|
+
action,
|
|
195
|
+
frames: stack.slice(0, -1).map((s) => s.frame),
|
|
196
|
+
});
|
|
197
|
+
const top = stack[stack.length - 1];
|
|
198
|
+
if (top) {
|
|
199
|
+
top.frame = {
|
|
200
|
+
kind: top.frame.kind === "if" ? "if" : top.frame.kind,
|
|
201
|
+
conditions: [],
|
|
202
|
+
negatedConditions: [...top.chain],
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
case "with": {
|
|
208
|
+
const expr = actionPipeline(action);
|
|
209
|
+
scoped.push({ action, frames: stack.map((s) => s.frame) });
|
|
210
|
+
const path = valuesPathOf(expr);
|
|
211
|
+
stack.push({
|
|
212
|
+
frame: {
|
|
213
|
+
kind: "with",
|
|
214
|
+
conditions: [expr],
|
|
215
|
+
negatedConditions: [],
|
|
216
|
+
dotValuesPath: path,
|
|
217
|
+
dotUnresolvable: path === undefined,
|
|
218
|
+
},
|
|
219
|
+
chain: [expr],
|
|
220
|
+
});
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
case "range": {
|
|
224
|
+
const expr = actionPipeline(action);
|
|
225
|
+
scoped.push({ action, frames: stack.map((s) => s.frame) });
|
|
226
|
+
stack.push({
|
|
227
|
+
frame: {
|
|
228
|
+
kind: "range",
|
|
229
|
+
conditions: [expr],
|
|
230
|
+
negatedConditions: [],
|
|
231
|
+
dotUnresolvable: true,
|
|
232
|
+
},
|
|
233
|
+
chain: [expr],
|
|
234
|
+
});
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
case "define":
|
|
238
|
+
case "block": {
|
|
239
|
+
scoped.push({ action, frames: stack.map((s) => s.frame) });
|
|
240
|
+
// A define body runs with whatever context `include`/`template`
|
|
241
|
+
// passes. Most charts pass the root context; the frame records
|
|
242
|
+
// nothing to gate on, so constructs inside a define are treated as
|
|
243
|
+
// reachable unless gated within the define itself.
|
|
244
|
+
stack.push({
|
|
245
|
+
frame: { kind: action.kind, conditions: [], negatedConditions: [] },
|
|
246
|
+
chain: [],
|
|
247
|
+
});
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
case "end": {
|
|
251
|
+
scoped.push({
|
|
252
|
+
action,
|
|
253
|
+
frames: stack.slice(0, -1).map((s) => s.frame),
|
|
254
|
+
});
|
|
255
|
+
stack.pop();
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
default:
|
|
259
|
+
scoped.push({ action, frames: stack.map((s) => s.frame) });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return scoped;
|
|
263
|
+
}
|