@intentius/chant-lexicon-k8s 0.41.16 → 0.41.17
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/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "579bf4095e47e58c245aa6e2531cabeaf1b6b558a25a5e1090810d9bf31f2675",
|
|
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": "
|
|
53
|
+
"composite": "d2f25a5b946a9065204fc9c38ac8a5c39417015120bbdaeee93c12c2597dc397"
|
|
54
54
|
}
|
package/dist/manifest.json
CHANGED
|
@@ -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;
|
|
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;AAmGD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,gBAAgB,EACtB,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,YAAkC,GAC1C,OAAO,CAAC,mBAAmB,CAAC,CAkE9B;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.
|
|
3
|
+
"version": "0.41.17",
|
|
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.
|
|
87
|
+
"@intentius/chant": "^0.41.17",
|
|
88
88
|
"typescript": "^5.9.3"
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -164,6 +164,76 @@ describe("kubectlApply", () => {
|
|
|
164
164
|
expect(bodies[1].metadata?.labels?.["chant.intentius.io/env"]).toBeUndefined();
|
|
165
165
|
});
|
|
166
166
|
|
|
167
|
+
test("a conflict owned entirely by chant's own managers is retaken with force — the stack-label migration path", async () => {
|
|
168
|
+
// An estate applied before its components named per-unit stacks has every
|
|
169
|
+
// object's labels owned by `chant:<ownership.stack>`. The re-stamp under
|
|
170
|
+
// the unit's manager conflicts — with chant itself. Refusing that forever
|
|
171
|
+
// would strand the estate with no non-force path (the capability exposes
|
|
172
|
+
// no force flag), so chant retakes its OWN fields, once, per document.
|
|
173
|
+
const file = join(dir, "k8s.yaml");
|
|
174
|
+
writeFileSync(file, deploymentYaml);
|
|
175
|
+
let patches = 0;
|
|
176
|
+
const cluster = fakeCluster({
|
|
177
|
+
respond: (req) => {
|
|
178
|
+
if (req.method !== "PATCH") return undefined;
|
|
179
|
+
patches++;
|
|
180
|
+
const forced = req.query.force === "true";
|
|
181
|
+
if (forced) return { body: JSON.parse(String(req.body)) };
|
|
182
|
+
return {
|
|
183
|
+
status: 409,
|
|
184
|
+
body: {
|
|
185
|
+
...statusBody(409, "Conflict", 'Apply failed with 1 conflict: conflict with "chant:kubemicrovm-ops"'),
|
|
186
|
+
details: {
|
|
187
|
+
causes: [
|
|
188
|
+
{
|
|
189
|
+
type: "FieldManagerConflict",
|
|
190
|
+
message: 'conflict with "chant:kubemicrovm-ops"',
|
|
191
|
+
field: ".metadata.labels.chant.intentius.io/stack",
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const result = await applyManifest({ manifest: file, stack: "kmv-workload" }, undefined, cluster.connector);
|
|
201
|
+
expect(result.applied).toHaveLength(2);
|
|
202
|
+
// Each of the two documents: one refused apply + one forced retake.
|
|
203
|
+
expect(patches).toBe(4);
|
|
204
|
+
const requests = cluster.layer.requests.filter((r) => r.method === "PATCH");
|
|
205
|
+
expect(requests.map((r) => r.query.force)).toEqual(["false", "true", "false", "true"]);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("a conflict involving any FOREIGN manager still refuses — self-retake never widens", async () => {
|
|
209
|
+
const file = join(dir, "k8s.yaml");
|
|
210
|
+
writeFileSync(file, deploymentYaml);
|
|
211
|
+
const cluster = fakeCluster({
|
|
212
|
+
respond: (req) =>
|
|
213
|
+
req.method === "PATCH"
|
|
214
|
+
? {
|
|
215
|
+
status: 409,
|
|
216
|
+
body: {
|
|
217
|
+
...statusBody(409, "Conflict", "Apply failed with 2 conflicts"),
|
|
218
|
+
details: {
|
|
219
|
+
causes: [
|
|
220
|
+
{ type: "FieldManagerConflict", message: 'conflict with "chant:old"', field: ".metadata.labels.chant.intentius.io/stack" },
|
|
221
|
+
{ type: "FieldManagerConflict", message: 'conflict with "helm"', field: ".spec.replicas" },
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
}
|
|
226
|
+
: undefined,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const err = (await applyManifest({ manifest: file, stack: "kmv-workload" }, undefined, cluster.connector).catch(
|
|
230
|
+
(e: unknown) => e,
|
|
231
|
+
)) as Error;
|
|
232
|
+
expect(err.name).toBe("FieldManagerConflictError");
|
|
233
|
+
// No forced retry was attempted.
|
|
234
|
+
expect(cluster.layer.requests.filter((r) => r.method === "PATCH" && r.query.force === "true")).toHaveLength(0);
|
|
235
|
+
});
|
|
236
|
+
|
|
167
237
|
test("no resolvable stack applies the documents verbatim — no marker invented", async () => {
|
|
168
238
|
const file = join(dir, "k8s.yaml");
|
|
169
239
|
writeFileSync(file, deploymentYaml);
|
|
@@ -191,6 +191,31 @@ async function resolveApplyIdentity(
|
|
|
191
191
|
};
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Structural mirror of the client's `FieldManagerConflictError` surface —
|
|
196
|
+
* matched by `name` + shape, NOT `instanceof`, because a static value import
|
|
197
|
+
* of `@intentius/chant-k8s-client` here would put the API-client chain on the
|
|
198
|
+
* build path (the #1074 boundary; same reason the applier itself is reached
|
|
199
|
+
* by dynamic import).
|
|
200
|
+
*/
|
|
201
|
+
interface ConflictErrorLike {
|
|
202
|
+
name: string;
|
|
203
|
+
conflicts?: Array<{ manager?: unknown }>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Is every contested field in this conflict owned by chant itself (under any
|
|
208
|
+
* of its field managers — `chant` bare or `chant:<stack>`)? True means the
|
|
209
|
+
* conflict is a self-migration, never a dispute with another tool.
|
|
210
|
+
*/
|
|
211
|
+
function isChantSelfConflict(err: unknown): boolean {
|
|
212
|
+
const e = err as ConflictErrorLike;
|
|
213
|
+
if (!e || e.name !== "FieldManagerConflictError" || !Array.isArray(e.conflicts) || e.conflicts.length === 0) return false;
|
|
214
|
+
return e.conflicts.every(
|
|
215
|
+
(c) => typeof c.manager === "string" && (c.manager === "chant" || c.manager.startsWith("chant:")),
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
194
219
|
/**
|
|
195
220
|
* Stamp the apply's own stack identity onto a document's labels.
|
|
196
221
|
*
|
|
@@ -257,12 +282,26 @@ export async function applyManifest(
|
|
|
257
282
|
|
|
258
283
|
const applied: AppliedRef[] = [];
|
|
259
284
|
for (const document of documents) {
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
285
|
+
const stamped = stampOwnership(document as K8sObject, stack);
|
|
286
|
+
let result: K8sObject;
|
|
287
|
+
try {
|
|
288
|
+
result = await client.apply(stamped, {
|
|
289
|
+
fieldManager,
|
|
290
|
+
force: args.force ?? false,
|
|
291
|
+
dryRun: args.dryRun,
|
|
292
|
+
signal,
|
|
293
|
+
});
|
|
294
|
+
} catch (err) {
|
|
295
|
+
// "chant never forces a conflict on its own" is about taking fields
|
|
296
|
+
// from ANOTHER tool. A conflict where every contested field is owned
|
|
297
|
+
// by another `chant:*` manager is chant contesting itself — the
|
|
298
|
+
// ownership-stack → unit-stack label migration, or a renamed deploy
|
|
299
|
+
// unit — and refusing that forever would strand every estate applied
|
|
300
|
+
// before the rename with no non-force path back. Retake those fields
|
|
301
|
+
// deliberately, once, and only when no foreign manager is involved.
|
|
302
|
+
if (!isChantSelfConflict(err)) throw err;
|
|
303
|
+
result = await client.apply(stamped, { fieldManager, force: true, dryRun: args.dryRun, signal });
|
|
304
|
+
}
|
|
266
305
|
const ref: AppliedRef = {
|
|
267
306
|
apiVersion: String(result.apiVersion ?? document.apiVersion ?? ""),
|
|
268
307
|
kind: String(result.kind ?? document.kind ?? ""),
|