@intentius/chant-lexicon-k8s 0.41.14 → 0.41.16

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.
@@ -1 +1 @@
1
- {"version":3,"file":"deep-observe-hooks.d.ts","sourceRoot":"","sources":["../src/deep-observe-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAY,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAGnG;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAcxE,CAAC;AA+EF;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAYnF;AAMD,eAAO,MAAM,yBAAyB,EAAE,sBAWvC,CAAC"}
1
+ {"version":3,"file":"deep-observe-hooks.d.ts","sourceRoot":"","sources":["../src/deep-observe-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAY,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAYnG;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAcxE,CAAC;AA+EF;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAYnF;AAMD,eAAO,MAAM,yBAAyB,EAAE,sBAWvC,CAAC"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "ba8a86870c372520c29075795e436c0d6b75bdfcf0efa31e659d02ade4a05d65",
4
+ "manifest.json": "528b5cb5e20dcb4ab991f8ab6d98da91f361d833b65d8e40bdb62867498ddc0e",
5
5
  "meta.json": "c0b141b882c51483c1d1aead748a0eb171aceca7432edd2a0404b062bf6d7831",
6
6
  "types/index.d.ts": "3be2af7494aca94adfa16269cb9c4e7a155529872207a3d70b0c4d39914f9eec",
7
7
  "rules/argo-appset-single-project.ts": "afa9f310753aa2d475f35012b13135b2dfaebed2a35d44edbe185ebc07673674",
@@ -50,5 +50,5 @@
50
50
  "skills/chant-k8s-aks.md": "e18f0e2b055f72cd7a37deaf258d7027c2d4d3e286e8fd4975b27a1f981a3ad9",
51
51
  "skills/chant-k8s-argo.md": "b1a0b826559d8c5033a479c5781efaf650320f0aee4419d8841170bd3393cea5"
52
52
  },
53
- "composite": "da8f0e0aec605eff3c8ca4fca6c31f3bac6f8a2e9070e7708fd97cc49daf93a6"
53
+ "composite": "f895a3588933ce1fa536eeceb58265524ea731115d96b1ca7b3a93df9c19d1e1"
54
54
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "k8s",
3
- "version": "0.41.14",
3
+ "version": "0.41.16",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "K8s",
6
6
  "intrinsics": [],
@@ -1 +1 @@
1
- {"version":3,"file":"kubectl.d.ts","sourceRoot":"","sources":["../../../src/op/activities/kubectl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAaH,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAI3E;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,YAAY,GAAG,OAAO,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sFAAsF;IACtF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,oCAAoC;AACpC,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,sCAAsC;AACtC,MAAM,WAAW,mBAAmB;IAClC,qDAAqD;IACrD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,sFAAsF;IACtF,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAiB7E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAEjF;AAoCD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,gBAAgB,EACtB,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,YAAkC,GAC1C,OAAO,CAAC,mBAAmB,CAAC,CAoD9B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,gBAAgB,EACtB,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,YAAkC,GAC1C,OAAO,CAAC,IAAI,CAAC,CAEf"}
1
+ {"version":3,"file":"kubectl.d.ts","sourceRoot":"","sources":["../../../src/op/activities/kubectl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAaH,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAI3E;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,YAAY,GAAG,OAAO,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sFAAsF;IACtF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,oCAAoC;AACpC,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,sCAAsC;AACtC,MAAM,WAAW,mBAAmB;IAClC,qDAAqD;IACrD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,sFAAsF;IACtF,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAiB7E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAEjF;AA0ED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,gBAAgB,EACtB,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,YAAkC,GAC1C,OAAO,CAAC,mBAAmB,CAAC,CAoD9B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,gBAAgB,EACtB,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,YAAkC,GAC1C,OAAO,CAAC,IAAI,CAAC,CAEf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-k8s",
3
- "version": "0.41.14",
3
+ "version": "0.41.16",
4
4
  "description": "Kubernetes lexicon for chant — declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -84,7 +84,7 @@
84
84
  },
85
85
  "peerDependencies": {
86
86
  "zod": "^4.3.6",
87
- "@intentius/chant": "^0.41.14",
87
+ "@intentius/chant": "^0.41.16",
88
88
  "typescript": "^5.9.3"
89
89
  }
90
90
  }
@@ -41,9 +41,19 @@
41
41
  * keyed by chant's own k8s entityType catalog.
42
42
  */
43
43
 
44
+ import { createRequire } from "module";
44
45
  import type { DeepArrayElement, DeepNode, DeepNormalizationHooks } from "@intentius/chant/lexicon";
45
46
  import { K8S_OBJECT_ENVELOPE_PRUNE_PATTERNS, k8sListMapOrderKey } from "@intentius/chant/managed-fields";
46
47
 
48
+ // This module ships as ESM (tsx strips types from src/ directly), where a bare
49
+ // `require` is not defined — the same reason serializer.ts and the LSP modules
50
+ // already build one. The bug only surfaced on a LIVE deep read that meets an
51
+ // associative list (every k8s estate does: a Deployment's containers), so
52
+ // `lifecycle diff --live` crashed with `require is not defined` on exactly the
53
+ // estates the generated table exists for (#1441 regression, found on
54
+ // kubemicrovm-ops).
55
+ const require = createRequire(import.meta.url);
56
+
47
57
  /**
48
58
  * Kubernetes-defaulted fields, per entity type, as index-erased property
49
59
  * paths. Subtracted only where source never declared the property
@@ -132,6 +132,52 @@ describe("kubectlApply", () => {
132
132
  }
133
133
  });
134
134
 
135
+ test("the apply stamps its resolved stack onto every document's labels — the identity the prune and the status sweep query", async () => {
136
+ // The serializer bakes the PROJECT stack (`ownership.stack`) into what it
137
+ // emits, but a component's kubectl-apply step applies under its own unit
138
+ // stack — and that is what both label readers select on. A manifest with
139
+ // the project label (or none at all: upstream CRDs) must leave the apply
140
+ // carrying the unit's identity, or the unit reads absent forever.
141
+ const file = join(dir, "k8s.yaml");
142
+ const labeled = deploymentYaml.replace(
143
+ " name: web\n namespace: prod\n",
144
+ " name: web\n namespace: prod\n labels:\n app.kubernetes.io/managed-by: chant\n chant.intentius.io/stack: whole-project\n chant.intentius.io/env: dev\n",
145
+ );
146
+ writeFileSync(file, labeled);
147
+ const cluster = fakeCluster({ respond: echoApplies });
148
+
149
+ await applyManifest({ manifest: file, stack: "kmv-workload" }, undefined, cluster.connector);
150
+
151
+ const bodies = cluster.layer.requests
152
+ .filter((r) => r.method === "PATCH")
153
+ .map((r) => JSON.parse(String(r.body)) as { metadata?: { labels?: Record<string, string> } });
154
+ expect(bodies).toHaveLength(2);
155
+ for (const body of bodies) {
156
+ expect(body.metadata?.labels).toMatchObject({
157
+ "app.kubernetes.io/managed-by": "chant",
158
+ "chant.intentius.io/stack": "kmv-workload",
159
+ });
160
+ }
161
+ // The env label is the serializer's channel — restamped never, kept as-is.
162
+ expect(bodies[0].metadata?.labels?.["chant.intentius.io/env"]).toBe("dev");
163
+ // The previously-unlabeled Service now carries the marker too.
164
+ expect(bodies[1].metadata?.labels?.["chant.intentius.io/env"]).toBeUndefined();
165
+ });
166
+
167
+ test("no resolvable stack applies the documents verbatim — no marker invented", async () => {
168
+ const file = join(dir, "k8s.yaml");
169
+ writeFileSync(file, deploymentYaml);
170
+ const cluster = fakeCluster({ respond: echoApplies });
171
+
172
+ // No stack arg, no project config: identity resolution yields none.
173
+ await applyManifest({ manifest: file, cwd: dir }, undefined, cluster.connector);
174
+
175
+ const body = JSON.parse(
176
+ String(cluster.layer.requests.find((r) => r.method === "PATCH")!.body),
177
+ ) as { metadata?: { labels?: Record<string, string> } };
178
+ expect(body.metadata?.labels).toBeUndefined();
179
+ });
180
+
135
181
  test("an explicit context is honored and skips the environment lookup entirely", async () => {
136
182
  const file = join(dir, "k8s.yaml");
137
183
  writeFileSync(file, deploymentYaml);
@@ -191,6 +191,44 @@ async function resolveApplyIdentity(
191
191
  };
192
192
  }
193
193
 
194
+ /**
195
+ * Stamp the apply's own stack identity onto a document's labels.
196
+ *
197
+ * The serializer bakes `ownership.stack` — the *project* identity from
198
+ * `chant.config.ts` — into every manifest it emits. But the apply's identity
199
+ * is the *stack argument it resolved* (a component's `kubectl-apply` step
200
+ * names its own deploy unit, e.g. `kmv-workload`), and that is the value both
201
+ * consumers of the label query for: the owned-only prune's selector and
202
+ * `describeStackStatus`'s presence sweep. Applying the manifest verbatim left
203
+ * the label saying `kubemicrovm-ops` while both readers asked for
204
+ * `kmv-workload` — the prune silently matched nothing and every kubectl-apply
205
+ * unit read absent in `components status --live` (a green estate painted
206
+ * dead). A manifest chant never serialized (upstream CRDs pinned into a
207
+ * `crds` unit) carried no marker at all, with the same two failures.
208
+ *
209
+ * So the apply now re-stamps what it applies: `managed-by=chant` plus the
210
+ * resolved stack. The ownership *verdict* keys on `managed-by` alone
211
+ * (core/ownership.ts `hasOwnershipMarker`), so overlay classification is
212
+ * unchanged; the env label is the serializer's to write and is left as-is.
213
+ * No stack resolved (no explicit arg, no project ownership) applies verbatim,
214
+ * exactly as before.
215
+ */
216
+ function stampOwnership(document: K8sObject, stack: string | undefined): K8sObject {
217
+ if (stack === undefined) return document;
218
+ const metadata = (document.metadata ?? {}) as { labels?: Record<string, string> };
219
+ return {
220
+ ...document,
221
+ metadata: {
222
+ ...metadata,
223
+ labels: {
224
+ ...(metadata.labels ?? {}),
225
+ [LABEL_OWNERSHIP_KEYS.managedBy]: OWNERSHIP_MANAGED_BY_VALUE,
226
+ [LABEL_OWNERSHIP_KEYS.stack]: stack,
227
+ },
228
+ },
229
+ } as K8sObject;
230
+ }
231
+
194
232
  /**
195
233
  * Apply every document in `args.manifest`, then prune when asked.
196
234
  *
@@ -219,7 +257,7 @@ export async function applyManifest(
219
257
 
220
258
  const applied: AppliedRef[] = [];
221
259
  for (const document of documents) {
222
- const result = await client.apply(document as K8sObject, {
260
+ const result = await client.apply(stampOwnership(document as K8sObject, stack), {
223
261
  fieldManager,
224
262
  force: args.force ?? false,
225
263
  dryRun: args.dryRun,