@intentius/chant-lexicon-k8s 0.124.31 → 0.124.32

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.
Files changed (270) hide show
  1. package/dist/actions/apps.js +18 -0
  2. package/dist/actions/batch.js +6 -0
  3. package/dist/actions/core.js +48 -0
  4. package/dist/actions/index.js +13 -0
  5. package/dist/actions/networking.js +11 -0
  6. package/dist/actions/rbac.js +8 -0
  7. package/dist/api/classify.js +123 -0
  8. package/dist/api/connect.js +62 -0
  9. package/dist/api/fake-cluster.js +175 -0
  10. package/dist/api/operation-surface.d.ts.map +1 -1
  11. package/dist/api/operation-surface.js +109 -0
  12. package/dist/api/owner-chain.js +100 -0
  13. package/dist/api/sweep-types.js +35 -0
  14. package/dist/behaviour-kinds.js +82 -0
  15. package/dist/codegen/docs-cli.js +2 -0
  16. package/dist/codegen/docs.js +146 -0
  17. package/dist/codegen/generate-cli.js +30 -0
  18. package/dist/codegen/generate-lexicon.js +74 -0
  19. package/dist/codegen/generate-list-map-keys.js +88 -0
  20. package/dist/codegen/generate-operations.js +53 -0
  21. package/dist/codegen/generate-typescript.js +124 -0
  22. package/dist/codegen/generate.js +173 -0
  23. package/dist/codegen/naming.js +174 -0
  24. package/dist/codegen/package.js +36 -0
  25. package/dist/codegen/patches.js +88 -0
  26. package/dist/codegen/typecheck.js +4 -0
  27. package/dist/codegen/versions.js +41 -0
  28. package/dist/components/argo-app.js +51 -0
  29. package/dist/components/builders.js +22 -0
  30. package/dist/components/capability-plugin.js +31 -0
  31. package/dist/components/flux-reconcile.js +61 -0
  32. package/dist/components/index.d.ts +1 -1
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/components/index.js +18 -0
  35. package/dist/components/kubectl-apply.d.ts +83 -1
  36. package/dist/components/kubectl-apply.d.ts.map +1 -1
  37. package/dist/components/kubectl-apply.js +274 -0
  38. package/dist/components/kustomize-apply.js +25 -0
  39. package/dist/composites/adot-collector.js +184 -0
  40. package/dist/composites/agic-ingress.js +85 -0
  41. package/dist/composites/aks-external-dns-agent.js +146 -0
  42. package/dist/composites/alb-ingress.js +86 -0
  43. package/dist/composites/argo-app.js +199 -0
  44. package/dist/composites/autoscaled-service.js +174 -0
  45. package/dist/composites/azure-disk-storage-class.js +47 -0
  46. package/dist/composites/azure-file-storage-class.js +48 -0
  47. package/dist/composites/azure-monitor-collector.js +176 -0
  48. package/dist/composites/batch-job.js +139 -0
  49. package/dist/composites/catalog.js +4110 -0
  50. package/dist/composites/cockroachdb-cluster.js +371 -0
  51. package/dist/composites/cockroachdb-region-stack.js +369 -0
  52. package/dist/composites/config-connector-context.js +40 -0
  53. package/dist/composites/configured-app.js +135 -0
  54. package/dist/composites/cron-schedule.js +38 -0
  55. package/dist/composites/cron-workload.js +109 -0
  56. package/dist/composites/ebs-storage-class.js +54 -0
  57. package/dist/composites/efs-storage-class.js +46 -0
  58. package/dist/composites/external-dns-agent.js +122 -0
  59. package/dist/composites/filestore-storage-class.js +49 -0
  60. package/dist/composites/fluent-bit-agent.js +157 -0
  61. package/dist/composites/flux-app.js +156 -0
  62. package/dist/composites/gce-ingress.js +83 -0
  63. package/dist/composites/gce-pd-storage-class.js +49 -0
  64. package/dist/composites/gke-external-dns-agent.js +129 -0
  65. package/dist/composites/gke-fluent-bit-agent.js +165 -0
  66. package/dist/composites/gke-gateway.js +91 -0
  67. package/dist/composites/gke-otel-collector.js +94 -0
  68. package/dist/composites/index.js +51 -0
  69. package/dist/composites/inference-service.js +76 -0
  70. package/dist/composites/irsa-service-account.js +77 -0
  71. package/dist/composites/member-defaults.js +14 -0
  72. package/dist/composites/metrics-server.js +181 -0
  73. package/dist/composites/model.js +92 -0
  74. package/dist/composites/monitored-service.js +152 -0
  75. package/dist/composites/namespace-env.js +114 -0
  76. package/dist/composites/network-isolated-app.js +124 -0
  77. package/dist/composites/node-agent.js +149 -0
  78. package/dist/composites/operator-stack.js +268 -0
  79. package/dist/composites/otel-collector-agent.js +142 -0
  80. package/dist/composites/otel-collector-gateway.js +216 -0
  81. package/dist/composites/otel-collector-node.js +176 -0
  82. package/dist/composites/otel-collector-rbac.js +115 -0
  83. package/dist/composites/otel-collector-shape.js +128 -0
  84. package/dist/composites/otel-collector.js +115 -0
  85. package/dist/composites/otel-operator-collector.js +123 -0
  86. package/dist/composites/ray-cluster.js +378 -0
  87. package/dist/composites/ray-job.js +136 -0
  88. package/dist/composites/ray-service.js +178 -0
  89. package/dist/composites/secure-ingress.js +100 -0
  90. package/dist/composites/security-context.js +1 -0
  91. package/dist/composites/sidecar-app.js +105 -0
  92. package/dist/composites/stateful-app.js +111 -0
  93. package/dist/composites/vllm-serving-runtime.js +114 -0
  94. package/dist/composites/web-app.js +157 -0
  95. package/dist/composites/worker-pool.js +167 -0
  96. package/dist/composites/workload-identity-sa.js +81 -0
  97. package/dist/composites/workload-identity-service-account.js +77 -0
  98. package/dist/config-schema.js +72 -0
  99. package/dist/config.js +59 -0
  100. package/dist/coverage.js +27 -0
  101. package/dist/crd/crd-sources.js +615 -0
  102. package/dist/crd/loader.js +181 -0
  103. package/dist/crd/oci-chart.js +144 -0
  104. package/dist/crd/parser.js +382 -0
  105. package/dist/crd/project-codegen.js +273 -0
  106. package/dist/crd/types.js +7 -0
  107. package/dist/deep-observe-hooks.js +306 -0
  108. package/dist/deep-observe.js +234 -0
  109. package/dist/default-labels.js +87 -0
  110. package/dist/describe-resources.js +699 -0
  111. package/dist/describe-stack-status.js +99 -0
  112. package/dist/detect.js +11 -0
  113. package/dist/effect-receipt-row.js +205 -0
  114. package/dist/export-resources.js +39 -0
  115. package/dist/generated/index.js +1092 -0
  116. package/dist/generated/runtime.js +4 -0
  117. package/dist/group-namespace.js +96 -0
  118. package/dist/import/embedded.js +197 -0
  119. package/dist/import/generator.js +288 -0
  120. package/dist/import/live-export.js +85 -0
  121. package/dist/import/parser.js +204 -0
  122. package/dist/import/testdata/embedded/fixtures.js +60 -0
  123. package/dist/include/entity.js +78 -0
  124. package/dist/include/resolve.js +170 -0
  125. package/dist/index.js +59 -0
  126. package/dist/integrity.json +3 -3
  127. package/dist/kube/apply.js +90 -0
  128. package/dist/kube/connect.js +46 -0
  129. package/dist/kube/delete.js +138 -0
  130. package/dist/kube/describe.js +169 -0
  131. package/dist/kube/events.js +132 -0
  132. package/dist/kube/flags.js +91 -0
  133. package/dist/kube/get.js +159 -0
  134. package/dist/kube/group.js +123 -0
  135. package/dist/kube/logs.js +82 -0
  136. package/dist/kube/project.js +94 -0
  137. package/dist/kube/render.js +227 -0
  138. package/dist/kube/source.js +122 -0
  139. package/dist/kube/target.js +63 -0
  140. package/dist/kube/testing.js +28 -0
  141. package/dist/kube/top.js +99 -0
  142. package/dist/kube/verdict.js +72 -0
  143. package/dist/kube/wait.js +129 -0
  144. package/dist/kustomize/render.js +73 -0
  145. package/dist/kustomize/rendered-entity.js +67 -0
  146. package/dist/kustomize/root.js +68 -0
  147. package/dist/lint/audit-catalog.js +61 -0
  148. package/dist/lint/audit-lineage.js +118 -0
  149. package/dist/lint/post-synth/argo-helpers.js +36 -0
  150. package/dist/lint/post-synth/argo002.js +31 -0
  151. package/dist/lint/post-synth/argo003.js +53 -0
  152. package/dist/lint/post-synth/argo005.js +54 -0
  153. package/dist/lint/post-synth/crd-schema-helpers.d.ts.map +1 -1
  154. package/dist/lint/post-synth/crd-schema-helpers.js +214 -0
  155. package/dist/lint/post-synth/flux002.js +56 -0
  156. package/dist/lint/post-synth/flux003.js +50 -0
  157. package/dist/lint/post-synth/index.js +104 -0
  158. package/dist/lint/post-synth/k8s-helpers.js +186 -0
  159. package/dist/lint/post-synth/monitoring-selection-helpers.js +163 -0
  160. package/dist/lint/post-synth/otel-placement-helpers.js +293 -0
  161. package/dist/lint/post-synth/sops-helpers.js +43 -0
  162. package/dist/lint/post-synth/wk8005.js +44 -0
  163. package/dist/lint/post-synth/wk8006.js +56 -0
  164. package/dist/lint/post-synth/wk8041.js +60 -0
  165. package/dist/lint/post-synth/wk8042.js +36 -0
  166. package/dist/lint/post-synth/wk8101.js +52 -0
  167. package/dist/lint/post-synth/wk8102.js +30 -0
  168. package/dist/lint/post-synth/wk8103.js +33 -0
  169. package/dist/lint/post-synth/wk8104.js +58 -0
  170. package/dist/lint/post-synth/wk8105.js +33 -0
  171. package/dist/lint/post-synth/wk8201.js +44 -0
  172. package/dist/lint/post-synth/wk8202.js +34 -0
  173. package/dist/lint/post-synth/wk8203.js +34 -0
  174. package/dist/lint/post-synth/wk8204.js +71 -0
  175. package/dist/lint/post-synth/wk8205.js +38 -0
  176. package/dist/lint/post-synth/wk8207.js +33 -0
  177. package/dist/lint/post-synth/wk8208.js +33 -0
  178. package/dist/lint/post-synth/wk8209.js +33 -0
  179. package/dist/lint/post-synth/wk8301.js +49 -0
  180. package/dist/lint/post-synth/wk8302.js +34 -0
  181. package/dist/lint/post-synth/wk8303.js +68 -0
  182. package/dist/lint/post-synth/wk8304.js +58 -0
  183. package/dist/lint/post-synth/wk8305.js +96 -0
  184. package/dist/lint/post-synth/wk8306.js +38 -0
  185. package/dist/lint/post-synth/wk8401.js +86 -0
  186. package/dist/lint/post-synth/wk8402.js +31 -0
  187. package/dist/lint/post-synth/wk8403.js +49 -0
  188. package/dist/lint/post-synth/wk8404.js +36 -0
  189. package/dist/lint/post-synth/wk8405.js +65 -0
  190. package/dist/lint/post-synth/wk8406.js +50 -0
  191. package/dist/lint/post-synth/wk8407.js +58 -0
  192. package/dist/lint/post-synth/wk8501.js +36 -0
  193. package/dist/lint/post-synth/wk8502.js +35 -0
  194. package/dist/lint/post-synth/wk8503.js +164 -0
  195. package/dist/lint/post-synth/wk8504.js +20 -0
  196. package/dist/lint/post-synth/wk8505.js +31 -0
  197. package/dist/lint/post-synth/wk8601.js +40 -0
  198. package/dist/lint/post-synth/wk8602.js +120 -0
  199. package/dist/lint/post-synth/wk8603.js +63 -0
  200. package/dist/lint/post-synth/wk8604.js +31 -0
  201. package/dist/lint/post-synth/wk8605.js +124 -0
  202. package/dist/lint/post-synth/wk8606.js +22 -0
  203. package/dist/lint/post-synth/wk8701.js +31 -0
  204. package/dist/lint/post-synth/wk8702.js +37 -0
  205. package/dist/lint/post-synth/wk8703.js +31 -0
  206. package/dist/lint/post-synth/wk8704.js +135 -0
  207. package/dist/lint/post-synth/wk8705.js +38 -0
  208. package/dist/lint/rules/argo-appset-single-project.js +56 -0
  209. package/dist/lint/rules/argo-ast.js +94 -0
  210. package/dist/lint/rules/argo-automated-prune.js +59 -0
  211. package/dist/lint/rules/flux-source-ref-pin.js +44 -0
  212. package/dist/lint/rules/hardcoded-namespace.js +57 -0
  213. package/dist/lint/rules/latest-image-tag.js +103 -0
  214. package/dist/lint/rules/missing-resource-limits.js +85 -0
  215. package/dist/lsp/completions.d.ts.map +1 -1
  216. package/dist/lsp/completions.js +18 -0
  217. package/dist/lsp/hover.d.ts.map +1 -1
  218. package/dist/lsp/hover.js +57 -0
  219. package/dist/manifest-entity.js +71 -0
  220. package/dist/manifest.json +1 -1
  221. package/dist/micro-time.js +49 -0
  222. package/dist/op/activities/apply-diff.d.ts +31 -0
  223. package/dist/op/activities/apply-diff.d.ts.map +1 -0
  224. package/dist/op/activities/apply-diff.js +79 -0
  225. package/dist/op/activities/argo.js +98 -0
  226. package/dist/op/activities/ensure-secret.js +38 -0
  227. package/dist/op/activities/index.js +51 -0
  228. package/dist/op/activities/kubectl.d.ts +64 -0
  229. package/dist/op/activities/kubectl.d.ts.map +1 -1
  230. package/dist/op/activities/kubectl.js +517 -0
  231. package/dist/op/activities/wait-for-ready.js +229 -0
  232. package/dist/op/builders.js +68 -0
  233. package/dist/package-cli.js +21 -0
  234. package/dist/patch/json-patch.js +187 -0
  235. package/dist/patch/rendered-patch.js +94 -0
  236. package/dist/plugin.js +741 -0
  237. package/dist/project-kinds.js +56 -0
  238. package/dist/receipt-store.js +216 -0
  239. package/dist/rules/crd-schema-helpers.ts +2 -1
  240. package/dist/secret-labels.js +33 -0
  241. package/dist/secret-store.js +116 -0
  242. package/dist/serializer.d.ts.map +1 -1
  243. package/dist/serializer.js +578 -0
  244. package/dist/sops/encrypted-secret-file.js +194 -0
  245. package/dist/sops/entity.js +32 -0
  246. package/dist/spec/fetch.js +58 -0
  247. package/dist/spec/parse.js +622 -0
  248. package/dist/subscribe-changes.js +168 -0
  249. package/dist/teardown.js +197 -0
  250. package/dist/telemetry-release.js +86 -0
  251. package/dist/validate-cli.js +17 -0
  252. package/dist/validate.js +47 -0
  253. package/dist/variables.js +34 -0
  254. package/dist/whoami.js +109 -0
  255. package/package.json +12 -12
  256. package/src/api/operation-surface.ts +2 -1
  257. package/src/codegen/package.ts +2 -2
  258. package/src/components/index.ts +3 -0
  259. package/src/components/kubectl-apply-plan.k3d.e2e.test.ts +127 -0
  260. package/src/components/kubectl-apply.test.ts +262 -0
  261. package/src/components/kubectl-apply.ts +341 -12
  262. package/src/deep-observe-hooks.ts +2 -2
  263. package/src/import/roundtrip-build.test.ts +46 -0
  264. package/src/lint/post-synth/crd-schema-helpers.ts +2 -1
  265. package/src/lsp/completions.ts +2 -1
  266. package/src/lsp/hover.ts +2 -1
  267. package/src/op/activities/apply-diff.ts +87 -0
  268. package/src/op/activities/kubectl-plan.test.ts +224 -0
  269. package/src/op/activities/kubectl.ts +204 -16
  270. package/src/serializer.ts +2 -1
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Committed SOPS ciphertext as a build artifact (epic lex00/iac-cd-bench#6).
3
+ *
4
+ * A `declareSecret({ provenance: "committed-encrypted", file })` names a
5
+ * repo-relative path to ciphertext that lives in git. This module is the
6
+ * resolution stage: at `buildRoots()` — chant's one sanctioned impure seam,
7
+ * the same one the kustomize roots and cedar's `Schema` use — it reads those
8
+ * bytes, validates the document is what the declaration claims, and wraps
9
+ * them in an entity the serializer copies out VERBATIM as a sidecar file.
10
+ *
11
+ * Three properties this is built to keep:
12
+ *
13
+ * - **Never inlined.** The bytes go to `SerializerResult.files`, never into
14
+ * the primary multi-document YAML. chant's own appliers read the primary
15
+ * output, so "chant pushes an undecrypted Secret into a cluster" is
16
+ * structurally impossible rather than merely unlikely. Flux is the only
17
+ * thing that applies the sidecar, and Flux decrypts first.
18
+ * - **Deterministic and offline.** The bytes are copied, not re-serialized:
19
+ * no parse-and-re-emit round trip, no key sorting, no digest. No `sops`
20
+ * binary is invoked in either direction, so a missing binary and a missing
21
+ * age key are not failure modes — the plaintext has no representation here
22
+ * at any stage.
23
+ * - **Fails loudly, not weirdly.** A missing file, a non-Secret document, a
24
+ * name mismatch, a missing `sops` block, or a `data`/`stringData` value
25
+ * that is not `ENC[...]`-shaped refuses with the declared path in the
26
+ * message. That last check is the one that earns the feature: it catches
27
+ * "edited the file and forgot to re-encrypt", the exact failure mode that
28
+ * puts plaintext into git.
29
+ *
30
+ * The entity is deliberately internal — not exported from the package entry
31
+ * point, not constructible by an author. The authored surface is
32
+ * `declareSecret`; a public entity taking inline bytes is the one thing this
33
+ * whole design exists to prevent.
34
+ *
35
+ * Design: docs/design/committed-encrypted-sops-provenance.md §3.
36
+ */
37
+ import { readFileSync } from "node:fs";
38
+ import { resolve } from "node:path";
39
+ import { loadAll } from "js-yaml";
40
+ import { DECLARABLE_MARKER } from "@intentius/chant/declarable";
41
+ import { ENCRYPTED_SECRET_ENTITY_PREFIX, ENCRYPTED_SECRET_FILE_MARKER, ENCRYPTED_SECRET_FILE_TYPE, sidecarFilename, } from "./entity.js";
42
+ import { collectSecretDeclarations, isCommittedEncryptedSecret, } from "@intentius/chant/secret-provenance";
43
+ export { ENCRYPTED_SECRET_FILE_MARKER, ENCRYPTED_SECRET_FILE_TYPE, ENCRYPTED_SECRET_ENTITY_PREFIX, isEncryptedSecretFileEntity, sidecarFilename, } from "./entity.js";
44
+ /**
45
+ * Validate one committed ciphertext document against its declaration.
46
+ *
47
+ * Returns every problem found, so an author sees all of them at once rather
48
+ * than one per build. Both consumers share this: the `buildRoots()` stage
49
+ * turns the list into a refusal, and WK8504 turns it into diagnostics.
50
+ *
51
+ * A value is only ever tested for the `ENC[` prefix, inside this one frame,
52
+ * and only the offending KEY name is reported — the discipline
53
+ * `declareSecret`'s own runtime guard uses.
54
+ */
55
+ export function validateEncryptedSecretDocument(text, declared) {
56
+ const problems = [];
57
+ let docs;
58
+ try {
59
+ docs = loadAll(text);
60
+ }
61
+ catch (err) {
62
+ return {
63
+ problems: [`${declared.file} is not valid YAML: ${err instanceof Error ? err.message : String(err)}`],
64
+ };
65
+ }
66
+ const present = docs.filter((d) => d !== null && d !== undefined);
67
+ if (present.length === 0) {
68
+ return { problems: [`${declared.file} contains no YAML document`] };
69
+ }
70
+ if (present.length > 1) {
71
+ // v1 keys a declaration by one `name`; a declaration-per-document sharing
72
+ // a file, or a `names: string[]` field, is a design change to make
73
+ // deliberately rather than by accident.
74
+ return {
75
+ problems: [
76
+ `${declared.file} contains ${present.length} YAML documents — ` +
77
+ `a committed-encrypted declaration covers exactly one Secret`,
78
+ ],
79
+ };
80
+ }
81
+ const doc = present[0];
82
+ if (typeof doc !== "object" || doc === null || Array.isArray(doc)) {
83
+ return { problems: [`${declared.file} is not a Kubernetes object`] };
84
+ }
85
+ const record = doc;
86
+ if (record.apiVersion !== "v1" || record.kind !== "Secret") {
87
+ problems.push(`${declared.file} is not a v1 Secret ` +
88
+ `(apiVersion "${String(record.apiVersion)}", kind "${String(record.kind)}")`);
89
+ }
90
+ const metadata = asRecord(record.metadata);
91
+ const name = typeof metadata?.name === "string" ? metadata.name : undefined;
92
+ const namespace = typeof metadata?.namespace === "string" ? metadata.namespace : undefined;
93
+ if (name !== declared.name) {
94
+ problems.push(`${declared.file} has metadata.name "${name ?? "(none)"}", ` +
95
+ `but the declaration names "${declared.name}"`);
96
+ }
97
+ // SOPS's own metadata block. Its absence means the file was never encrypted
98
+ // (or was decrypted in place and committed), which is the whole point of
99
+ // checking. `sops.mac` is a MAC over the PLAINTEXT — it is carried by the
100
+ // verbatim copy and must never be read as a semantic value, so nothing here
101
+ // looks past the block's presence.
102
+ if (asRecord(record.sops) === undefined) {
103
+ problems.push(`${declared.file} has no top-level \`sops\` block — it does not look encrypted. ` +
104
+ `Run \`sops -e -i\` before committing.`);
105
+ }
106
+ // Scoped to data/stringData alone: SOPS's `encrypted_regex` leaves
107
+ // apiVersion, kind and metadata cleartext by design.
108
+ const keys = [];
109
+ for (const field of ["data", "stringData"]) {
110
+ const block = asRecord(record[field]);
111
+ if (block === undefined)
112
+ continue;
113
+ for (const [key, value] of Object.entries(block)) {
114
+ keys.push(key);
115
+ if (typeof value !== "string" || !value.startsWith("ENC[")) {
116
+ problems.push(`${declared.file}: ${field}."${key}" is not encrypted (expected an ENC[...] value) — ` +
117
+ `re-run \`sops -e -i\` before committing`);
118
+ }
119
+ }
120
+ }
121
+ return { problems, document: { name, namespace, keys } };
122
+ }
123
+ function asRecord(value) {
124
+ return typeof value === "object" && value !== null && !Array.isArray(value)
125
+ ? value
126
+ : undefined;
127
+ }
128
+ /**
129
+ * Read and validate every committed-encrypted declaration, returning one
130
+ * entity per resolved file. Throws on the first declaration that does not
131
+ * resolve, with every problem for that declaration in the message — a build
132
+ * that would emit a broken or unencrypted Secret must not proceed.
133
+ */
134
+ export function resolveEncryptedSecrets(options) {
135
+ const read = options.readFile ?? ((path) => readFileSync(path, "utf-8"));
136
+ const entities = new Map();
137
+ const byFilename = new Map();
138
+ for (const decl of options.declarations.values()) {
139
+ const absolute = resolve(options.projectRoot, decl.file);
140
+ let text;
141
+ try {
142
+ text = read(absolute);
143
+ }
144
+ catch (err) {
145
+ throw new Error(`declareSecret("${decl.name}"): committed ciphertext not readable at ${absolute} ` +
146
+ `(declared as "${decl.file}") — ${err instanceof Error ? err.message : String(err)}`);
147
+ }
148
+ const { problems, document } = validateEncryptedSecretDocument(text, decl);
149
+ if (problems.length > 0) {
150
+ throw new Error(`declareSecret("${decl.name}"): committed ciphertext does not resolve —\n ` +
151
+ problems.join("\n "));
152
+ }
153
+ const filename = sidecarFilename(decl.file);
154
+ const collides = byFilename.get(filename);
155
+ if (collides !== undefined) {
156
+ throw new Error(`declareSecret("${decl.name}"): sidecar filename "${filename}" collides with the one ` +
157
+ `"${collides}" already emits — additional files share one flat namespace, so two ` +
158
+ `declarations whose paths share a basename would silently overwrite each other`);
159
+ }
160
+ byFilename.set(filename, decl.file);
161
+ const entity = {
162
+ lexicon: "k8s",
163
+ entityType: ENCRYPTED_SECRET_FILE_TYPE,
164
+ filename,
165
+ text,
166
+ secretName: decl.name,
167
+ ...(document?.namespace !== undefined ? { namespace: document.namespace } : {}),
168
+ sourcePath: decl.file,
169
+ [DECLARABLE_MARKER]: true,
170
+ [ENCRYPTED_SECRET_FILE_MARKER]: true,
171
+ };
172
+ entities.set(`${ENCRYPTED_SECRET_ENTITY_PREFIX}${decl.name}`, entity);
173
+ }
174
+ return entities;
175
+ }
176
+ /** Every committed-encrypted declaration in an entity map, keyed by entity name. */
177
+ export function committedEncryptedDeclarations(entities) {
178
+ const out = new Map();
179
+ for (const [name, decl] of collectSecretDeclarations(entities)) {
180
+ if (isCommittedEncryptedSecret(decl))
181
+ out.set(name, decl);
182
+ }
183
+ return out;
184
+ }
185
+ /**
186
+ * The `buildRoots` contribution: one entity per committed-encrypted
187
+ * declaration, holding the file's bytes verbatim.
188
+ */
189
+ export async function encryptedSecretBuildRoot(ctx) {
190
+ const declarations = committedEncryptedDeclarations(ctx.entities ?? new Map());
191
+ if (declarations.size === 0)
192
+ return { entities: new Map() };
193
+ return { entities: resolveEncryptedSecrets({ projectRoot: ctx.projectRoot, declarations }) };
194
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The committed-ciphertext entity: marker, shape and type guard only.
3
+ *
4
+ * Split from `./encrypted-secret-file.ts` so the serializer can recognise the
5
+ * entity without pulling `node:fs` and a YAML parser into its module graph —
6
+ * the resolution stage needs both, the emission stage needs neither.
7
+ *
8
+ * Not exported from the package entry point and not constructible by an
9
+ * author: the authored surface is `declareSecret({ provenance:
10
+ * "committed-encrypted", file })`. A public entity taking inline bytes is
11
+ * exactly what this design exists to prevent.
12
+ */
13
+ import { basename } from "node:path";
14
+ /** Marks an entity whose bytes are committed ciphertext, emitted verbatim. */
15
+ export const ENCRYPTED_SECRET_FILE_MARKER = Symbol.for("chant.k8s.encryptedSecretFile");
16
+ /**
17
+ * The entity's type name. Deliberately outside the `K8s::{Group}::{Kind}`
18
+ * surface a real Secret speaks: an observer must NOT read this against a live
19
+ * cluster — the ciphertext is not the thing in the cluster, the decrypted
20
+ * Secret is — so a type with no generated operation surface, reporting the
21
+ * honest NOT-OBSERVED, is the right answer.
22
+ */
23
+ export const ENCRYPTED_SECRET_FILE_TYPE = "K8s::Sops::EncryptedSecretFile";
24
+ /** Entity-map key prefix, colon-separated so it cannot collide with a TS export name. */
25
+ export const ENCRYPTED_SECRET_ENTITY_PREFIX = "sops:";
26
+ export function isEncryptedSecretFileEntity(entity) {
27
+ return entity[ENCRYPTED_SECRET_FILE_MARKER] === true;
28
+ }
29
+ /** The sidecar filename a declaration's file is emitted under. */
30
+ export function sidecarFilename(file) {
31
+ return basename(file);
32
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Kubernetes OpenAPI schema fetching — downloads the Swagger 2.0 spec
3
+ * and caches it locally.
4
+ */
5
+ import { join } from "path";
6
+ import { homedir } from "os";
7
+ import { fetchWithCache, clearCacheFile } from "@intentius/chant/codegen/fetch";
8
+ /**
9
+ * Pinned Kubernetes version for schema download.
10
+ */
11
+ export const K8S_SCHEMA_VERSION = "v1.36.2";
12
+ /**
13
+ * Build the schema URL for a given version.
14
+ */
15
+ function schemaUrl(version) {
16
+ return `https://raw.githubusercontent.com/kubernetes/kubernetes/${version}/api/openapi-spec/swagger.json`;
17
+ }
18
+ /**
19
+ * Get the cache file path for the K8s schema.
20
+ */
21
+ export function getCachePath(version) {
22
+ const ref = version ?? K8S_SCHEMA_VERSION;
23
+ return join(homedir(), ".chant", `k8s-swagger-${ref}.json`);
24
+ }
25
+ /**
26
+ * Fetch the Kubernetes OpenAPI Swagger spec, returning the raw JSON buffer.
27
+ * Uses local file caching with 24-hour TTL.
28
+ *
29
+ * @param force Bypass cache and download fresh.
30
+ * @param version Kubernetes version tag. Defaults to {@link K8S_SCHEMA_VERSION}.
31
+ */
32
+ export async function fetchK8sSchema(force, version) {
33
+ const ref = version ?? K8S_SCHEMA_VERSION;
34
+ return fetchWithCache({
35
+ url: schemaUrl(ref),
36
+ cacheFile: getCachePath(ref),
37
+ }, force);
38
+ }
39
+ /**
40
+ * Fetch the K8s schema and return it as a Map<typeName, Buffer>
41
+ * compatible with the generatePipeline fetchSchemas callback.
42
+ *
43
+ * The K8s schema is a single document, so we return a single entry
44
+ * keyed by "Kubernetes::OpenAPI" — the parse step will split it
45
+ * into multiple resources.
46
+ */
47
+ export async function fetchSchemas(force, version) {
48
+ const data = await fetchK8sSchema(force, version);
49
+ const schemas = new Map();
50
+ schemas.set("Kubernetes::OpenAPI", data);
51
+ return schemas;
52
+ }
53
+ /**
54
+ * Clear the cached schema file.
55
+ */
56
+ export function clearCache(version) {
57
+ clearCacheFile(getCachePath(version));
58
+ }