@intentius/chant-lexicon-k8s 0.44.7 → 0.44.8
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":"describe-resources.d.ts","sourceRoot":"","sources":["../src/describe-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAwD,MAAM,0BAA0B,CAAC;AAGxH,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAmBvE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CA2CvD;AA4FD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,EAAE,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"describe-resources.d.ts","sourceRoot":"","sources":["../src/describe-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAwD,MAAM,0BAA0B,CAAC;AAGxH,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAmBvE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CA2CvD;AA4FD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,EAAE,GAAG,SAAS,CAuBtE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG;IAClD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAUA;AAQD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sFAAsF;IACtF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,EACjC,OAAO,GAAE,YAAkC,GAC1C,OAAO,CAAC,iBAAiB,CAAC,CA6J5B"}
|
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "1f650968faca1af0e095cca8ffae3d53597a3bb14013bec3e528d395e9e09b28",
|
|
5
5
|
"meta.json": "f568fb8a0cbd4adf041baccaa3e1164c2e3c5c0090186236f887f0084f5521a8",
|
|
6
6
|
"types/index.d.ts": "ef2c9df6a4d1ebfbe33f96c094fbbe3fc7909522ea38e086666fbf3c8ac477fd",
|
|
7
7
|
"rules/argo-appset-single-project.ts": "afa9f310753aa2d475f35012b13135b2dfaebed2a35d44edbe185ebc07673674",
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"skills/chant-k8s-argo.md": "b1a0b826559d8c5033a479c5781efaf650320f0aee4419d8841170bd3393cea5",
|
|
55
55
|
"skills/chant-k8s-flux.md": "9670efc2e9854bd14686b5adeb707396b9030a4dcaee6529b30abf56efe2c50c"
|
|
56
56
|
},
|
|
57
|
-
"composite": "
|
|
57
|
+
"composite": "a7892db10dc02e8e856dcd2b7f1d64fd6f59fd2e1b3997e609f6c519a39f07da"
|
|
58
58
|
}
|
package/dist/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-k8s",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.8",
|
|
4
4
|
"description": "Kubernetes lexicon for chant — declarative IaC in TypeScript",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@types/js-yaml": "^4.0.9"
|
|
77
77
|
},
|
|
78
78
|
"optionalDependencies": {
|
|
79
|
-
"@intentius/chant-k8s-client": "^0.44.
|
|
79
|
+
"@intentius/chant-k8s-client": "^0.44.8"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@intentius/chant": "*",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|
|
86
86
|
"zod": "^4.3.6",
|
|
87
|
-
"@intentius/chant": "^0.44.
|
|
87
|
+
"@intentius/chant": "^0.44.8",
|
|
88
88
|
"typescript": "^5.9.3"
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -657,7 +657,7 @@ describe("k8s describeResources", () => {
|
|
|
657
657
|
cluster.connector,
|
|
658
658
|
);
|
|
659
659
|
|
|
660
|
-
const child = result.resources["prod/backup-29157"];
|
|
660
|
+
const child = result.resources["Job/prod/backup-29157"];
|
|
661
661
|
expect(child).toMatchObject({
|
|
662
662
|
type: "K8s::Batch::Job",
|
|
663
663
|
physicalId: "job-uid",
|
|
@@ -683,7 +683,7 @@ describe("k8s describeResources", () => {
|
|
|
683
683
|
cluster.connector,
|
|
684
684
|
);
|
|
685
685
|
|
|
686
|
-
expect(result.resources["prod/hand-made"]).toBeUndefined();
|
|
686
|
+
expect(result.resources["Job/prod/hand-made"]).toBeUndefined();
|
|
687
687
|
});
|
|
688
688
|
|
|
689
689
|
// The issue's own estate: a declared MicroVMReplicaSet whose operator
|
|
@@ -730,7 +730,7 @@ describe("k8s describeResources", () => {
|
|
|
730
730
|
cluster.connector,
|
|
731
731
|
);
|
|
732
732
|
|
|
733
|
-
expect(result.resources["microvm-demo/kmv-dev-a-vm-42sgf"]).toMatchObject({
|
|
733
|
+
expect(result.resources["MicroVM/microvm-demo/kmv-dev-a-vm-42sgf"]).toMatchObject({
|
|
734
734
|
type: "K8s::KubeMicroVM::MicroVM",
|
|
735
735
|
physicalId: "vm-uid",
|
|
736
736
|
ownerChain: { root: "declared", entity: "workloadReplicaSet" },
|
|
@@ -771,7 +771,7 @@ describe("k8s describeResources", () => {
|
|
|
771
771
|
cluster.connector,
|
|
772
772
|
);
|
|
773
773
|
|
|
774
|
-
expect(result.resources["ray/ml-head"]).toMatchObject({
|
|
774
|
+
expect(result.resources["Deployment/ray/ml-head"]).toMatchObject({
|
|
775
775
|
type: "K8s::Apps::Deployment",
|
|
776
776
|
physicalId: "head-uid",
|
|
777
777
|
ownerChain: { root: "declared", entity: "ml" },
|
|
@@ -834,7 +834,7 @@ describe("k8s describeResources", () => {
|
|
|
834
834
|
cluster.connector,
|
|
835
835
|
);
|
|
836
836
|
|
|
837
|
-
expect(result.resources["cluster:team-a-admin"]).toMatchObject({
|
|
837
|
+
expect(result.resources["cluster:ClusterRole/team-a-admin"]).toMatchObject({
|
|
838
838
|
type: "K8s::Rbac::ClusterRole",
|
|
839
839
|
physicalId: "role-uid",
|
|
840
840
|
ownerChain: { root: "declared", entity: "team" },
|
|
@@ -887,7 +887,7 @@ describe("k8s describeResources", () => {
|
|
|
887
887
|
cluster.connector,
|
|
888
888
|
);
|
|
889
889
|
|
|
890
|
-
expect(result.resources["prod/web"]).toMatchObject({
|
|
890
|
+
expect(result.resources["Deployment/prod/web"]).toMatchObject({
|
|
891
891
|
type: "K8s::Apps::Deployment",
|
|
892
892
|
ownerChain: { root: "declared", entity: "apps" },
|
|
893
893
|
});
|
|
@@ -928,12 +928,62 @@ describe("k8s describeResources", () => {
|
|
|
928
928
|
cluster.connector,
|
|
929
929
|
);
|
|
930
930
|
|
|
931
|
-
expect(result.resources["prod/web"]).toMatchObject({
|
|
931
|
+
expect(result.resources["Deployment/prod/web"]).toMatchObject({
|
|
932
932
|
type: "K8s::Apps::Deployment",
|
|
933
933
|
ownerChain: { root: "declared", entity: "webApp" },
|
|
934
934
|
});
|
|
935
935
|
});
|
|
936
936
|
|
|
937
|
+
// #1643 — the common convention names a workload and its Service alike, so
|
|
938
|
+
// a kind-less `namespace/name` key made them one row and only whichever
|
|
939
|
+
// kind swept first survived. Found by behold's argo estate: Application
|
|
940
|
+
// boxes held Endpoints instead of the Deployment.
|
|
941
|
+
test("same-named objects of different kinds are all reported — the key carries the kind (#1643)", async () => {
|
|
942
|
+
const app = {
|
|
943
|
+
apiVersion: "argoproj.io/v1alpha1",
|
|
944
|
+
kind: "Application",
|
|
945
|
+
metadata: { name: "app-a", namespace: "argocd", uid: "app-uid" },
|
|
946
|
+
status: { health: { status: "Healthy" }, sync: { status: "Synced" } },
|
|
947
|
+
};
|
|
948
|
+
const label = { "app.kubernetes.io/instance": "app-a" };
|
|
949
|
+
const deployment = {
|
|
950
|
+
apiVersion: "apps/v1",
|
|
951
|
+
kind: "Deployment",
|
|
952
|
+
metadata: { name: "app-a", namespace: "app-a", uid: "dep-uid", labels: label },
|
|
953
|
+
};
|
|
954
|
+
const service = {
|
|
955
|
+
apiVersion: "v1",
|
|
956
|
+
kind: "Service",
|
|
957
|
+
metadata: { name: "app-a", namespace: "app-a", uid: "svc-uid", labels: label },
|
|
958
|
+
};
|
|
959
|
+
const cluster = fakeCluster({
|
|
960
|
+
objects: {
|
|
961
|
+
[objectKey("argoproj.io/v1alpha1", "Application", "app-a", "argocd")]: app,
|
|
962
|
+
[objectKey("apps/v1", "Deployment", "app-a", "app-a")]: deployment,
|
|
963
|
+
[objectKey("v1", "Service", "app-a", "app-a")]: service,
|
|
964
|
+
},
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
const result = await describeResources(
|
|
968
|
+
{
|
|
969
|
+
environment: "prod",
|
|
970
|
+
buildOutput: "",
|
|
971
|
+
entityNames: ["appA"],
|
|
972
|
+
entities: makeEntities([
|
|
973
|
+
{
|
|
974
|
+
name: "appA",
|
|
975
|
+
entityType: "K8s::Argo::Application",
|
|
976
|
+
props: { metadata: { name: "app-a", namespace: "argocd" }, spec: { destination: { namespace: "app-a" } } },
|
|
977
|
+
},
|
|
978
|
+
]),
|
|
979
|
+
},
|
|
980
|
+
cluster.connector,
|
|
981
|
+
);
|
|
982
|
+
|
|
983
|
+
expect(result.resources["Deployment/app-a/app-a"]).toMatchObject({ type: "K8s::Apps::Deployment", physicalId: "dep-uid" });
|
|
984
|
+
expect(result.resources["Service/app-a/app-a"]).toMatchObject({ type: "K8s::Core::Service", physicalId: "svc-uid" });
|
|
985
|
+
});
|
|
986
|
+
|
|
937
987
|
test("a generic instance label matching NO declared Application claims nothing — not an inventory (#1549)", async () => {
|
|
938
988
|
// `app.kubernetes.io/instance` is also what plain helm sets; on an
|
|
939
989
|
// estate declaring a Flux CR (so the widened sweep runs), a foreign
|
|
@@ -967,7 +1017,7 @@ describe("k8s describeResources", () => {
|
|
|
967
1017
|
cluster.connector,
|
|
968
1018
|
);
|
|
969
1019
|
|
|
970
|
-
expect(result.resources["flux-system/cert-manager"]).toBeUndefined();
|
|
1020
|
+
expect(result.resources["Deployment/flux-system/cert-manager"]).toBeUndefined();
|
|
971
1021
|
});
|
|
972
1022
|
|
|
973
1023
|
test("the sweep's bound is the estate's namespaces, not a kind list — and no cluster-scoped list without a cluster-scoped entity", async () => {
|
|
@@ -1047,7 +1097,7 @@ describe("k8s describeResources", () => {
|
|
|
1047
1097
|
cluster.connector,
|
|
1048
1098
|
);
|
|
1049
1099
|
|
|
1050
|
-
const child = result.resources["prod/web-7d9f8c9c8-abcde"];
|
|
1100
|
+
const child = result.resources["Pod/prod/web-7d9f8c9c8-abcde"];
|
|
1051
1101
|
expect(child).toMatchObject({
|
|
1052
1102
|
type: "K8s::Core::Pod",
|
|
1053
1103
|
physicalId: "pod-uid",
|
|
@@ -1078,7 +1128,7 @@ describe("k8s describeResources", () => {
|
|
|
1078
1128
|
cluster.connector,
|
|
1079
1129
|
);
|
|
1080
1130
|
|
|
1081
|
-
expect(result.resources["prod/standalone"]).toMatchObject({
|
|
1131
|
+
expect(result.resources["Pod/prod/standalone"]).toMatchObject({
|
|
1082
1132
|
type: "K8s::Core::Pod",
|
|
1083
1133
|
ownerChain: { root: "unowned" },
|
|
1084
1134
|
});
|
|
@@ -1113,7 +1163,7 @@ describe("k8s describeResources", () => {
|
|
|
1113
1163
|
cluster.connector,
|
|
1114
1164
|
);
|
|
1115
1165
|
|
|
1116
|
-
expect(result.resources["prod/other-pod"]).toMatchObject({ ownerChain: { root: "foreign" } });
|
|
1166
|
+
expect(result.resources["Pod/prod/other-pod"]).toMatchObject({ ownerChain: { root: "foreign" } });
|
|
1117
1167
|
});
|
|
1118
1168
|
|
|
1119
1169
|
test("--owned withholds an unrelated Pod, but keeps a runtime child of a declared (owned) entity", async () => {
|
|
@@ -1156,8 +1206,8 @@ describe("k8s describeResources", () => {
|
|
|
1156
1206
|
);
|
|
1157
1207
|
|
|
1158
1208
|
expect(result.resources.web).toBeDefined(); // the marker let it through
|
|
1159
|
-
expect(result.resources["prod/standalone"]).toBeUndefined();
|
|
1160
|
-
expect(result.resources["prod/web-abc"]).toMatchObject({ ownerChain: { root: "declared", entity: "web" } });
|
|
1209
|
+
expect(result.resources["Pod/prod/standalone"]).toBeUndefined();
|
|
1210
|
+
expect(result.resources["Pod/prod/web-abc"]).toMatchObject({ ownerChain: { root: "declared", entity: "web" } });
|
|
1161
1211
|
});
|
|
1162
1212
|
|
|
1163
1213
|
test("a Pod that is itself declared is never duplicated as a runtime child", async () => {
|
|
@@ -1188,7 +1238,7 @@ describe("k8s describeResources", () => {
|
|
|
1188
1238
|
);
|
|
1189
1239
|
|
|
1190
1240
|
expect(result.resources.standalonePod).toBeDefined();
|
|
1191
|
-
expect(result.resources["prod/standalone-pod"]).toBeUndefined();
|
|
1241
|
+
expect(result.resources["Pod/prod/standalone-pod"]).toBeUndefined();
|
|
1192
1242
|
expect(Object.keys(result.resources)).toHaveLength(2); // web + standalonePod, no synthetic duplicate
|
|
1193
1243
|
});
|
|
1194
1244
|
|
|
@@ -1398,6 +1448,34 @@ describe("unhappyConditions (#1401)", () => {
|
|
|
1398
1448
|
expect(unhappyConditions({ status: {} } as never)).toBeUndefined();
|
|
1399
1449
|
expect(unhappyConditions({} as never)).toBeUndefined();
|
|
1400
1450
|
});
|
|
1451
|
+
|
|
1452
|
+
// #1644 — Argo's ApplicationCondition is {type, message, lastTransitionTime},
|
|
1453
|
+
// no status field, written only for problems. The polarity test has nothing
|
|
1454
|
+
// to read on it; the message IS the report, and it was the one diagnostic
|
|
1455
|
+
// line a broken Application writes.
|
|
1456
|
+
test("a status-less condition with a message passes through — Argo's ComparisonError (#1644)", () => {
|
|
1457
|
+
expect(
|
|
1458
|
+
unhappyConditions({
|
|
1459
|
+
status: {
|
|
1460
|
+
conditions: [
|
|
1461
|
+
{
|
|
1462
|
+
type: "ComparisonError",
|
|
1463
|
+
message: "Failed to load target state: app path does not exist",
|
|
1464
|
+
lastTransitionTime: "2026-08-10T00:00:00Z",
|
|
1465
|
+
},
|
|
1466
|
+
],
|
|
1467
|
+
},
|
|
1468
|
+
} as never),
|
|
1469
|
+
).toEqual(["ComparisonError: Failed to load target state: app path does not exist"]);
|
|
1470
|
+
});
|
|
1471
|
+
|
|
1472
|
+
test("a status-less condition with no message stays silent", () => {
|
|
1473
|
+
expect(
|
|
1474
|
+
unhappyConditions({
|
|
1475
|
+
status: { conditions: [{ type: "SomeMarker", lastTransitionTime: "2026-08-10T00:00:00Z" }] },
|
|
1476
|
+
} as never),
|
|
1477
|
+
).toBeUndefined();
|
|
1478
|
+
});
|
|
1401
1479
|
});
|
|
1402
1480
|
|
|
1403
1481
|
describe("revisionAttributes — the GitOps convergence fields (#1632)", () => {
|
|
@@ -222,10 +222,18 @@ export function unhappyConditions(obj: K8sObject): string[] | undefined {
|
|
|
222
222
|
const out: string[] = [];
|
|
223
223
|
for (const c of conditions) {
|
|
224
224
|
const cond = c as { type?: unknown; status?: unknown; reason?: unknown; message?: unknown };
|
|
225
|
-
if (typeof cond.type !== "string"
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
225
|
+
if (typeof cond.type !== "string") continue;
|
|
226
|
+
if (typeof cond.status === "string") {
|
|
227
|
+
const goodWhenFalse = CONDITIONS_GOOD_WHEN_FALSE.test(cond.type);
|
|
228
|
+
const happy = goodWhenFalse ? cond.status === "False" : cond.status === "True";
|
|
229
|
+
if (happy) continue;
|
|
230
|
+
} else if (!(typeof cond.message === "string" && cond.message)) {
|
|
231
|
+
// No status, no message: nothing to say. But a status-less condition
|
|
232
|
+
// WITH a message is an object speaking — Argo's ApplicationCondition is
|
|
233
|
+
// `{type, message, lastTransitionTime}`, written only for problems, and
|
|
234
|
+
// the polarity test above has nothing to read on it (#1644).
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
229
237
|
const reason = typeof cond.reason === "string" && cond.reason ? `=${cond.reason}` : "";
|
|
230
238
|
const message = typeof cond.message === "string" && cond.message ? `: ${cond.message}` : "";
|
|
231
239
|
out.push(`${cond.type}${reason}${message}`);
|
|
@@ -701,8 +709,11 @@ async function addRuntimeChildren(
|
|
|
701
709
|
const uid = obj.metadata?.uid;
|
|
702
710
|
const name = obj.metadata?.name;
|
|
703
711
|
if (!uid || !name || declaredByUid.has(uid)) return; // declared directly, or unaddressable
|
|
704
|
-
|
|
705
|
-
|
|
712
|
+
// The kind is part of the identity: a Deployment, Service and Endpoints
|
|
713
|
+
// all named `app-a` in namespace `app-a` are three objects, and a
|
|
714
|
+
// kind-less key reported only whichever kind swept first (#1643).
|
|
715
|
+
const key = namespace ? `${swept.kind}/${namespace}/${name}` : `cluster:${swept.kind}/${name}`;
|
|
716
|
+
if (resources[key]) return; // re-swept object, not a new report
|
|
706
717
|
|
|
707
718
|
let ownerChain = await resolveK8sOwnerChain(obj, { declaredByUid, reader: client, namespace });
|
|
708
719
|
// The label channel (#1549) — only when the chain itself said nothing:
|