@intentius/chant-lexicon-k8s 0.124.30 → 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,204 @@
1
+ /**
2
+ * Kubernetes YAML parser for `chant import`.
3
+ *
4
+ * Parses Kubernetes manifests (single or multi-document YAML) into the core
5
+ * TemplateIR format, mapping K8s resources to the K8s::{Group}::{Kind} type
6
+ * convention.
7
+ */
8
+ import { parseYAML, splitYAMLDocuments } from "@intentius/chant/yaml";
9
+ import { namespaceSegmentForGroup } from "../group-namespace.js";
10
+ import { delegateEmbedded } from "./embedded.js";
11
+ // ── GVK to type name mapping ───────────────────────────────────────
12
+ /**
13
+ * Well-known kind+apiVersion pairs mapped to K8s type names.
14
+ * Key format: "apiVersion/kind" (core group uses just "kind").
15
+ */
16
+ const GVK_TYPE_MAP = {
17
+ // Core (v1)
18
+ "v1/Pod": "K8s::Core::Pod",
19
+ "v1/Service": "K8s::Core::Service",
20
+ "v1/ConfigMap": "K8s::Core::ConfigMap",
21
+ "v1/Secret": "K8s::Core::Secret",
22
+ "v1/Namespace": "K8s::Core::Namespace",
23
+ "v1/ServiceAccount": "K8s::Core::ServiceAccount",
24
+ "v1/PersistentVolume": "K8s::Core::PersistentVolume",
25
+ "v1/PersistentVolumeClaim": "K8s::Core::PersistentVolumeClaim",
26
+ "v1/Endpoints": "K8s::Core::Endpoints",
27
+ "v1/LimitRange": "K8s::Core::LimitRange",
28
+ "v1/ResourceQuota": "K8s::Core::ResourceQuota",
29
+ // Apps (apps/v1)
30
+ "apps/v1/Deployment": "K8s::Apps::Deployment",
31
+ "apps/v1/StatefulSet": "K8s::Apps::StatefulSet",
32
+ "apps/v1/DaemonSet": "K8s::Apps::DaemonSet",
33
+ "apps/v1/ReplicaSet": "K8s::Apps::ReplicaSet",
34
+ // Batch (batch/v1)
35
+ "batch/v1/Job": "K8s::Batch::Job",
36
+ "batch/v1/CronJob": "K8s::Batch::CronJob",
37
+ // Networking (networking.k8s.io/v1)
38
+ "networking.k8s.io/v1/Ingress": "K8s::Networking::Ingress",
39
+ "networking.k8s.io/v1/NetworkPolicy": "K8s::Networking::NetworkPolicy",
40
+ "networking.k8s.io/v1/IngressClass": "K8s::Networking::IngressClass",
41
+ // RBAC (rbac.authorization.k8s.io/v1)
42
+ "rbac.authorization.k8s.io/v1/Role": "K8s::Rbac::Role",
43
+ "rbac.authorization.k8s.io/v1/ClusterRole": "K8s::Rbac::ClusterRole",
44
+ "rbac.authorization.k8s.io/v1/RoleBinding": "K8s::Rbac::RoleBinding",
45
+ "rbac.authorization.k8s.io/v1/ClusterRoleBinding": "K8s::Rbac::ClusterRoleBinding",
46
+ // Autoscaling (autoscaling/v2)
47
+ "autoscaling/v2/HorizontalPodAutoscaler": "K8s::Autoscaling::HorizontalPodAutoscaler",
48
+ "autoscaling/v1/HorizontalPodAutoscaler": "K8s::Autoscaling::HorizontalPodAutoscaler",
49
+ // Policy (policy/v1)
50
+ "policy/v1/PodDisruptionBudget": "K8s::Policy::PodDisruptionBudget",
51
+ // Storage (storage.k8s.io/v1)
52
+ "storage.k8s.io/v1/StorageClass": "K8s::Storage::StorageClass",
53
+ // Certificates (certificates.k8s.io/v1)
54
+ "certificates.k8s.io/v1/CertificateSigningRequest": "K8s::Certificates::CertificateSigningRequest",
55
+ // Coordination (coordination.k8s.io/v1)
56
+ "coordination.k8s.io/v1/Lease": "K8s::Coordination::Lease",
57
+ // Discovery (discovery.k8s.io/v1)
58
+ "discovery.k8s.io/v1/EndpointSlice": "K8s::Discovery::EndpointSlice",
59
+ };
60
+ /**
61
+ * Resolve apiVersion + kind to a K8s type name.
62
+ * Falls back to constructing from the apiVersion group.
63
+ */
64
+ /**
65
+ * `<apiVersion>/<kind>` keys that map to a type another key maps to first.
66
+ * The build writes the first key's apiVersion for that type, so a document
67
+ * written against a later key (`autoscaling/v1` HorizontalPodAutoscaler)
68
+ * keeps its own apiVersion as a property.
69
+ */
70
+ const ALIASED_GVKS = (() => {
71
+ const firstForType = new Set();
72
+ const aliased = new Set();
73
+ for (const [key, type] of Object.entries(GVK_TYPE_MAP)) {
74
+ if (firstForType.has(type))
75
+ aliased.add(key);
76
+ else
77
+ firstForType.add(type);
78
+ }
79
+ return aliased;
80
+ })();
81
+ function resolveTypeName(apiVersion, kind) {
82
+ // Try exact match
83
+ const key = `${apiVersion}/${kind}`;
84
+ if (GVK_TYPE_MAP[key])
85
+ return GVK_TYPE_MAP[key];
86
+ // Core group uses just kind
87
+ if (apiVersion === "v1") {
88
+ const coreKey = `v1/${kind}`;
89
+ if (GVK_TYPE_MAP[coreKey])
90
+ return GVK_TYPE_MAP[coreKey];
91
+ }
92
+ // Construct from apiVersion group
93
+ const group = apiVersionToGroup(apiVersion);
94
+ return `K8s::${group}::${kind}`;
95
+ }
96
+ /**
97
+ * Extract the namespace segment from an apiVersion string.
98
+ * "apps/v1" → "Apps"
99
+ * "v1" → "Core"
100
+ * "rbac.authorization.k8s.io/v1" → "Rbac"
101
+ * "argoproj.io/v1alpha1" → "Argo" (override)
102
+ *
103
+ * Splits the version off and hands the group to the shared rule, so an
104
+ * imported manifest is typed exactly as a declared one is.
105
+ */
106
+ function apiVersionToGroup(apiVersion) {
107
+ const slashIdx = apiVersion.indexOf("/");
108
+ if (slashIdx === -1)
109
+ return "Core"; // core group (v1)
110
+ return namespaceSegmentForGroup(apiVersion.slice(0, slashIdx));
111
+ }
112
+ /**
113
+ * Convert a K8s object name to a camelCase logical identifier.
114
+ * Combines kind (lowercased first char) with the object name (PascalCased).
115
+ *
116
+ * E.g., kind="Deployment", name="my-app" → "deploymentMyApp"
117
+ */
118
+ function toLogicalId(kind, name) {
119
+ const prefix = kind.charAt(0).toLowerCase() + kind.slice(1);
120
+ if (!name)
121
+ return prefix;
122
+ const pascalName = name
123
+ .split(/[-_.]/)
124
+ .map((seg) => seg.charAt(0).toUpperCase() + seg.slice(1))
125
+ .join("");
126
+ return `${prefix}${pascalName}`;
127
+ }
128
+ // ── Parser ──────────────────────────────────────────────────────────
129
+ /**
130
+ * Kubernetes YAML parser implementation.
131
+ *
132
+ * Supports multi-document YAML (split on `---`, see `splitYAMLDocuments`). Each document is expected
133
+ * to be a standard Kubernetes object with apiVersion, kind, and metadata.
134
+ */
135
+ export class K8sParser {
136
+ /**
137
+ * With `context.embedded` (`chant import`), content another lexicon owns
138
+ * is offered to it: every ConfigMap `data` value and a PrometheusRule's
139
+ * `spec.groups` (see ./embedded.ts). Without it, everything is kept as
140
+ * written.
141
+ */
142
+ parse(content, context) {
143
+ const resources = [];
144
+ const namespaces = new Set();
145
+ // Split into documents on `---` / `...` markers (a trailing `# comment`
146
+ // allowed); empty and comment-only documents are dropped (#2965).
147
+ const documents = splitYAMLDocuments(content);
148
+ for (const docStr of documents) {
149
+ const doc = parseYAML(docStr);
150
+ if (!doc || typeof doc !== "object")
151
+ continue;
152
+ const resource = this.parseDocument(doc, context?.embedded);
153
+ if (resource) {
154
+ resources.push(resource);
155
+ // Track namespaces
156
+ const ns = doc.metadata;
157
+ if (ns?.namespace && typeof ns.namespace === "string") {
158
+ namespaces.add(ns.namespace);
159
+ }
160
+ }
161
+ }
162
+ const metadata = {};
163
+ if (namespaces.size > 0) {
164
+ metadata.namespaces = [...namespaces];
165
+ }
166
+ return {
167
+ resources,
168
+ parameters: [],
169
+ metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
170
+ };
171
+ }
172
+ parseDocument(doc, embedded) {
173
+ const apiVersion = doc.apiVersion;
174
+ const kind = doc.kind;
175
+ if (!apiVersion || !kind)
176
+ return null;
177
+ const metadata = (doc.metadata ?? {});
178
+ const name = metadata.name;
179
+ const type = resolveTypeName(apiVersion, kind);
180
+ const logicalId = toLogicalId(kind, name);
181
+ // Extract the user-configurable properties (skip apiVersion, kind)
182
+ const properties = {};
183
+ for (const [key, value] of Object.entries(doc)) {
184
+ if (key === "kind")
185
+ continue;
186
+ if (key === "apiVersion" && !ALIASED_GVKS.has(`${apiVersion}/${kind}`))
187
+ continue;
188
+ properties[key] = value;
189
+ }
190
+ if (embedded)
191
+ delegateEmbedded(type, kind, properties, embedded);
192
+ return {
193
+ logicalId,
194
+ type,
195
+ properties,
196
+ metadata: {
197
+ originalName: name,
198
+ apiVersion,
199
+ kind,
200
+ ...(metadata.namespace ? { namespace: metadata.namespace } : {}),
201
+ },
202
+ };
203
+ }
204
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Shared by the embedded-content round trip (embedded-roundtrip.test.ts) and
3
+ * the type check of what it generates (embedded-types.e2e.test.ts): run
4
+ * `chant import` over a manifest file the way a user does, through
5
+ * `importCommand`, in a project inside this package so the lexicons resolve
6
+ * as they would for them.
7
+ */
8
+ import { mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "fs";
9
+ import { join, relative, resolve } from "path";
10
+ import { importCommand } from "@intentius/chant/cli/commands/import";
11
+ import { parsePrometheusYaml } from "@intentius/chant-lexicon-prometheus/import/parser";
12
+ export const pkgDir = resolve(import.meta.dirname, "../../../..");
13
+ export const repoRoot = resolve(pkgDir, "../..");
14
+ export const read = (name) => readFileSync(join(import.meta.dirname, name), "utf-8");
15
+ function walk(dir, root, out) {
16
+ for (const entry of readdirSync(dir)) {
17
+ const path = join(dir, entry);
18
+ if (statSync(path).isDirectory())
19
+ walk(path, root, out);
20
+ else
21
+ out[relative(root, path)] = readFileSync(path, "utf-8");
22
+ }
23
+ }
24
+ /**
25
+ * `chant import manifest.yaml --lexicon k8s` into a fresh project, or with
26
+ * `detect`, `chant import manifest.yaml` with the lexicon detected.
27
+ */
28
+ export async function importManifest(yaml, options = {}) {
29
+ const dir = mkdtempSync(join(pkgDir, ".roundtrip-tmp-"));
30
+ writeFileSync(join(dir, "package.json"), '{ "name": "k8s-embedded-roundtrip", "private": true, "type": "module" }\n');
31
+ writeFileSync(join(dir, "chant.config.ts"), 'export default { lexicons: ["k8s"] };\n');
32
+ const srcDir = join(dir, "src");
33
+ mkdirSync(srcDir);
34
+ const templatePath = join(dir, "manifest.yaml");
35
+ writeFileSync(templatePath, yaml);
36
+ const result = await importCommand({ templatePath, output: srcDir, ...(options.detect ? {} : { lexicon: "k8s" }) });
37
+ const files = {};
38
+ walk(srcDir, srcDir, files);
39
+ return { result, dir, srcDir, files };
40
+ }
41
+ export function removeDir(dir) {
42
+ rmSync(dir, { recursive: true, force: true });
43
+ }
44
+ /**
45
+ * An alertmanager.yml as the prometheus importer reads it, receivers and
46
+ * time intervals sorted by name (the serializer sorts them): what an
47
+ * imported ConfigMap's `alertmanager.yml` must give back (#3031).
48
+ */
49
+ export function alertmanagerConfig(text) {
50
+ const parsed = parsePrometheusYaml(text);
51
+ if (parsed.kind !== "alertmanager")
52
+ throw new Error("not an alertmanager.yml");
53
+ const byName = (a, b) => a.name.localeCompare(b.name);
54
+ const { receivers, time_intervals, ...rest } = parsed.config;
55
+ return {
56
+ ...rest,
57
+ ...(receivers ? { receivers: [...receivers].sort(byName) } : {}),
58
+ ...(time_intervals ? { time_intervals: [...time_intervals].sort(byName) } : {}),
59
+ };
60
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * `k8sInclude`: bring a plain multi-document YAML file or pinned URL into a
3
+ * build as it is (#3566 item 4).
4
+ *
5
+ * Before this, the way to ship a vendored manifest bundle (an operator's
6
+ * install.yaml, a CRD bundle) through chant was a kustomization directory
7
+ * listing it as its only resource. `k8sInclude` declares the file or URL
8
+ * directly. Its documents become the same verbatim manifest entities a
9
+ * kustomize build root produces (`../manifest-entity.ts`), so they get
10
+ * default labels and ownership stamping, post-synth checks, and
11
+ * `lifecycle diff --live` like any declared resource.
12
+ *
13
+ * This module is the declaration only, with no filesystem or network access,
14
+ * so the factory stays pure and folds under `--sandbox`. The bytes are read
15
+ * at `buildRoots()`, the build's one impure seam, in `./resolve.ts`, the same
16
+ * split `declareSecret({ provenance: "committed-encrypted" })` uses.
17
+ *
18
+ * The declaration itself never reaches the output: the serializer skips it,
19
+ * and it carries no `props`, so the live read paths never ask a cluster
20
+ * about it.
21
+ */
22
+ import { DECLARABLE_MARKER } from "@intentius/chant/declarable";
23
+ /** Marks a `k8sInclude` declaration. */
24
+ export const K8S_INCLUDE_MARKER = Symbol.for("chant.k8s.include");
25
+ export const K8S_INCLUDE_ENTITY_TYPE = "chant:k8s:include";
26
+ /** Annotation stamped on every included document, valued with its source. */
27
+ export const INCLUDE_SOURCE_ANNOTATION = "chant.intentius.io/include-source";
28
+ const DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
29
+ export function isK8sInclude(value) {
30
+ return (typeof value === "object" &&
31
+ value !== null &&
32
+ value[K8S_INCLUDE_MARKER] === true);
33
+ }
34
+ /** True for an `http://` or `https://` source. */
35
+ export function isRemoteSource(source) {
36
+ return /^https?:\/\//i.test(source);
37
+ }
38
+ /**
39
+ * Declare a local or pinned remote multi-document YAML to include in the
40
+ * build.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { k8sInclude } from "@intentius/chant-lexicon-k8s";
45
+ *
46
+ * export const certManager = k8sInclude({
47
+ * source: "https://github.com/cert-manager/cert-manager/releases/download/v1.16.2/cert-manager.yaml",
48
+ * digest: "sha256:...",
49
+ * });
50
+ *
51
+ * export const legacy = k8sInclude({ source: "manifests/legacy.yaml" });
52
+ * ```
53
+ */
54
+ export function k8sInclude(props) {
55
+ const source = props?.source;
56
+ if (typeof source !== "string" || source.length === 0) {
57
+ throw new Error("k8sInclude: `source` must be a non-empty path or URL");
58
+ }
59
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(source) && !isRemoteSource(source)) {
60
+ throw new Error(`k8sInclude("${source}"): only local paths and http(s) URLs are supported`);
61
+ }
62
+ if (props.digest !== undefined && !DIGEST_RE.test(props.digest)) {
63
+ throw new Error(`k8sInclude("${source}"): digest ${JSON.stringify(props.digest)} is not of the form "sha256:<64 lowercase hex>"`);
64
+ }
65
+ if (isRemoteSource(source) && props.digest === undefined) {
66
+ throw new Error(`k8sInclude("${source}"): a URL source must be pinned with \`digest: "sha256:<hex>"\`. ` +
67
+ `Compute it from a copy you have reviewed, e.g. \`curl -sL <url> | shasum -a 256\`.`);
68
+ }
69
+ return {
70
+ lexicon: "k8s",
71
+ entityType: K8S_INCLUDE_ENTITY_TYPE,
72
+ source,
73
+ ...(props.digest !== undefined ? { digest: props.digest } : {}),
74
+ ...(props.patches !== undefined ? { patches: JSON.parse(JSON.stringify(props.patches)) } : {}),
75
+ [DECLARABLE_MARKER]: true,
76
+ [K8S_INCLUDE_MARKER]: true,
77
+ };
78
+ }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Resolving `k8sInclude` declarations at `buildRoots()` (#3566 item 4).
3
+ *
4
+ * For each declaration in the discovered entity set: read the local file or
5
+ * fetch the URL, check the bytes against the pinned digest, parse the
6
+ * multi-document YAML, apply the declaration's patches, and wrap each
7
+ * document in a verbatim manifest entity stamped with the source.
8
+ *
9
+ * - Local paths resolve against the project root (the directory holding
10
+ * `chant.config.*`), as `declareSecret`'s committed ciphertext and
11
+ * `k8s.kustomize.roots` do.
12
+ * - A URL is fetched once. The bytes are cached under their digest in
13
+ * `~/.chant/includes/` (override with `CHANT_INCLUDE_CACHE_ROOT`, the
14
+ * counterpart of the helm lexicon's `CHANT_HELM_RENDER_ROOT`), and a build
15
+ * that finds a cached copy matching the digest never touches the network.
16
+ * Fetched bytes that do not match the digest fail the build and are not
17
+ * cached.
18
+ * - Entity names are `<declaration name>/<kindName>`, qualified by
19
+ * namespace and then numbered in document order on collision, the scheme
20
+ * kustomize roots use. Keying on the declaration's export name rather than
21
+ * the URL keeps the names stable when a pinned version is bumped, so the
22
+ * live diff lines up across the upgrade.
23
+ * - A missing file, a failed fetch, a file with no documents, and a
24
+ * document without a string `apiVersion` and `kind` each fail the build
25
+ * with the path or URL in the message. Empty documents (a stray `---`)
26
+ * are skipped.
27
+ */
28
+ import { createHash } from "node:crypto";
29
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
30
+ import { homedir } from "node:os";
31
+ import { join, resolve } from "node:path";
32
+ import { loadAll } from "js-yaml";
33
+ import { applyRenderedPatches } from "../patch/rendered-patch.js";
34
+ import { addRenderedEntity, renderedManifestEntity } from "../kustomize/rendered-entity.js";
35
+ import { INCLUDE_SOURCE_ANNOTATION, isK8sInclude, isRemoteSource } from "./entity.js";
36
+ export const defaultIncludeFetcher = async (url) => {
37
+ const response = await fetch(url, { redirect: "follow" });
38
+ if (!response.ok)
39
+ throw new Error(`HTTP ${response.status} ${response.statusText}`.trim());
40
+ return new Uint8Array(await response.arrayBuffer());
41
+ };
42
+ /** Where fetched include sources are cached, keyed by digest. */
43
+ export function includeCacheRoot() {
44
+ return process.env.CHANT_INCLUDE_CACHE_ROOT ?? join(homedir(), ".chant", "includes");
45
+ }
46
+ export function sha256Digest(bytes) {
47
+ return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
48
+ }
49
+ /** `sha256:<hex>` -> `sha256-<hex>.yaml`; colons are not filesystem-safe everywhere. */
50
+ function cachePath(root, digest) {
51
+ return join(root, `${digest.replace(":", "-")}.yaml`);
52
+ }
53
+ async function loadBytes(name, decl, opts) {
54
+ const read = opts.readFile ?? ((path) => readFileSync(path));
55
+ const label = `k8sInclude "${name}" (${decl.source})`;
56
+ if (!isRemoteSource(decl.source)) {
57
+ const absolute = resolve(opts.projectRoot, decl.source);
58
+ let bytes;
59
+ try {
60
+ bytes = read(absolute);
61
+ }
62
+ catch (err) {
63
+ throw new Error(`${label}: file not readable at ${absolute} — ${err instanceof Error ? err.message : String(err)}`);
64
+ }
65
+ if (decl.digest !== undefined) {
66
+ const actual = sha256Digest(bytes);
67
+ if (actual !== decl.digest) {
68
+ throw new Error(`${label}: ${absolute} does not match its pinned digest: expected ${decl.digest}, found ${actual}`);
69
+ }
70
+ }
71
+ return bytes;
72
+ }
73
+ // The factory refuses an unpinned URL; this guards a declaration revived
74
+ // from the entity wire format or built by hand.
75
+ if (decl.digest === undefined) {
76
+ throw new Error(`${label}: a URL source must be pinned with a sha256 digest`);
77
+ }
78
+ const root = opts.cacheRoot ?? includeCacheRoot();
79
+ const cached = cachePath(root, decl.digest);
80
+ if (existsSync(cached)) {
81
+ const bytes = readFileSync(cached);
82
+ // A corrupt or hand-edited cache entry is refetched, never trusted.
83
+ if (sha256Digest(bytes) === decl.digest)
84
+ return bytes;
85
+ }
86
+ const fetcher = opts.fetch ?? defaultIncludeFetcher;
87
+ let bytes;
88
+ try {
89
+ bytes = await fetcher(decl.source);
90
+ }
91
+ catch (err) {
92
+ throw new Error(`${label}: fetch failed — ${err instanceof Error ? err.message : String(err)}`);
93
+ }
94
+ const actual = sha256Digest(bytes);
95
+ if (actual !== decl.digest) {
96
+ throw new Error(`${label}: fetched bytes do not match the pinned digest: expected ${decl.digest}, fetched ${actual}. ` +
97
+ `The content at the URL changed, or the digest is wrong.`);
98
+ }
99
+ try {
100
+ mkdirSync(root, { recursive: true });
101
+ const tmp = `${cached}.${process.pid}.tmp`;
102
+ writeFileSync(tmp, bytes);
103
+ renameSync(tmp, cached);
104
+ }
105
+ catch {
106
+ // A cache write failure is not fatal: the verified bytes are in memory,
107
+ // and the next build fetches again.
108
+ }
109
+ return bytes;
110
+ }
111
+ /** Parse, validate and patch one source's documents. */
112
+ function documentsOf(name, decl, text) {
113
+ const label = `k8sInclude "${name}" (${decl.source})`;
114
+ let parsed;
115
+ try {
116
+ parsed = loadAll(text);
117
+ }
118
+ catch (err) {
119
+ throw new Error(`${label} is not valid YAML: ${err instanceof Error ? err.message : String(err)}`);
120
+ }
121
+ const docs = [];
122
+ parsed.forEach((doc, i) => {
123
+ if (doc === null || doc === undefined)
124
+ return;
125
+ if (typeof doc !== "object" || Array.isArray(doc)) {
126
+ throw new Error(`${label}: document ${i} is not a Kubernetes object`);
127
+ }
128
+ const record = doc;
129
+ if (typeof record.apiVersion !== "string" || !record.apiVersion || typeof record.kind !== "string" || !record.kind) {
130
+ throw new Error(`${label}: document ${i} has no string apiVersion and kind`);
131
+ }
132
+ docs.push(record);
133
+ });
134
+ if (docs.length === 0)
135
+ throw new Error(`${label} contains no YAML documents`);
136
+ return applyRenderedPatches(docs, decl.patches, label);
137
+ }
138
+ /**
139
+ * Resolve every declaration into entities. Throws on the first one that
140
+ * does not resolve: a build that would silently drop an included bundle
141
+ * must not proceed.
142
+ */
143
+ export async function resolveIncludes(opts) {
144
+ const entities = new Map();
145
+ for (const [name, decl] of opts.declarations) {
146
+ const bytes = await loadBytes(name, decl, opts);
147
+ const text = Buffer.from(bytes).toString("utf-8");
148
+ for (const doc of documentsOf(name, decl, text)) {
149
+ // documentsOf checked apiVersion/kind, so the wrap cannot return null.
150
+ addRenderedEntity(entities, name, renderedManifestEntity(doc, decl.source, INCLUDE_SOURCE_ANNOTATION));
151
+ }
152
+ }
153
+ return entities;
154
+ }
155
+ /** Every `k8sInclude` declaration in an entity map, keyed by entity name. */
156
+ export function includeDeclarations(entities) {
157
+ const out = new Map();
158
+ for (const [name, entity] of entities) {
159
+ if (isK8sInclude(entity))
160
+ out.set(name, entity);
161
+ }
162
+ return out;
163
+ }
164
+ /** The `buildRoots` contribution: the documents of every `k8sInclude`. */
165
+ export async function includeBuildRoot(ctx, overrides) {
166
+ const declarations = includeDeclarations(ctx.entities ?? new Map());
167
+ if (declarations.size === 0)
168
+ return { entities: new Map() };
169
+ return { entities: await resolveIncludes({ projectRoot: ctx.projectRoot, declarations, ...overrides }) };
170
+ }
package/dist/index.js ADDED
@@ -0,0 +1,59 @@
1
+ // Serializer
2
+ export { k8sSerializer } from "./serializer.js";
3
+ // Plugin
4
+ export { k8sPlugin } from "./plugin.js";
5
+ // Typed Op step-builder wrappers (chant #1288 Stage 2) — kubectlApply/
6
+ // waitForReady/ensureSecret — are deliberately NOT re-exported here: their
7
+ // types derive from the activities' own *Args interfaces, which name the API
8
+ // client and therefore sit behind the #1074 dynamic-import boundary this
9
+ // entry point must never reach, even type-only
10
+ // (examples/k8s-client-boundary.test.ts). Import them via the subpath
11
+ // `@intentius/chant-lexicon-k8s/op/builders`, the same way workers import
12
+ // `@intentius/chant-lexicon-k8s/op/activities`.
13
+ // The capability plugin core's loader discovers on this package (#1495 piece 2)
14
+ // — the kubectl-apply leaf a component composes, the way aws contributes
15
+ // cfn-deploy.
16
+ export { k8sCapabilityPlugin, K8S_VERB_FAMILIES } from "./components/capability-plugin.js";
17
+ export { kubectlApplyCapability, createKubectlApplyCapability } from "./components/kubectl-apply.js";
18
+ export { kustomizeApplyCapability, createKustomizeApplyCapability } from "./components/kustomize-apply.js";
19
+ // Default labels & annotations
20
+ export { defaultLabels, defaultAnnotations, isDefaultLabels, isDefaultAnnotations } from "./default-labels.js";
21
+ export { DEFAULT_LABELS_MARKER, DEFAULT_ANNOTATIONS_MARKER } from "./default-labels.js";
22
+ // Variables / label constants
23
+ export { K8sLabels, K8sAnnotations } from "./variables.js";
24
+ // Effect receipts (#2074, epic #1703): the k8s materialization row, meaning the
25
+ // factory a project declares (core's shape under the k8s lexicon, carrying
26
+ // the marker) and the name/label constants. The ConfigMap-backed store itself
27
+ // lives at the `/receipt-store` subpath, off the build path (#1074).
28
+ export { EffectReceipt, receiptConfigMapName, receiptConfigMapRef, receiptNamespaceFrom, isEffectReceiptObject, K8S_EFFECT_RECEIPT_ENTITY_TYPE, EFFECT_RECEIPTS_COMMENT_MARKER, RECEIPT_NAME_PREFIX, RECEIPT_DATA_KEY, RECEIPT_LABEL_KEY, RECEIPT_DEFAULT_NAMESPACE, RECEIPT_UNRESOLVED_VALUE_NOTE, parseReceiptComment, renderReceiptComment, } from "./effect-receipt-row.js";
29
+ // Generated-once secret marker (#1830) — constants only; the store adapter
30
+ // itself lives at the `/secret-store` subpath, off the build path (#1074).
31
+ export { GENERATED_ONCE_LABEL_KEY, GENERATED_ONCE_LABEL_VALUE, isGeneratedOnce } from "./secret-labels.js";
32
+ // MicroTime helpers — see micro-time.ts for why this exists.
33
+ export { microTime, isMicroTimeFormatted } from "./micro-time.js";
34
+ // Verbatim manifest escape hatch — a kind with no generated class, and what
35
+ // `chant carve emit` writes for a Terraform kubernetes_manifest (#999).
36
+ export { k8sManifest } from "./manifest-entity.js";
37
+ // Plain YAML included as it is, local or pinned URL (#3566). The factory is
38
+ // pure; the bytes are read at buildRoots() (./include/resolve.ts).
39
+ export { k8sInclude, isK8sInclude, INCLUDE_SOURCE_ANNOTATION } from "./include/entity.js";
40
+ // Patches on rendered documents: k8sInclude, kustomize roots, HelmRender (#3566).
41
+ export { renderedPatch, applyRenderedPatches, applyJsonPatch, applyMergePatch } from "./patch/rendered-patch.js";
42
+ // Generated entities — export everything from generated index
43
+ // After running `chant generate`, this re-exports all K8s resource classes
44
+ export * from "./generated/index.js";
45
+ // Composites
46
+ export { WebApp, StatefulApp, CronWorkload, AutoscaledService, WorkerPool, NamespaceEnv, NodeAgent, BatchJob, SecureIngress, ConfiguredApp, SidecarApp, MonitoredService, NetworkIsolatedApp, IrsaServiceAccount, AlbIngress, EbsStorageClass, EfsStorageClass, FluentBitAgent, ExternalDnsAgent, AdotCollector, OtelCollector, OtelCollectorGateway, gatewayExporter, OTEL_COLLECTOR_ANNOTATIONS, OtelOperatorCollector, MetricsServer, WorkloadIdentityServiceAccount, GcePdStorageClass, FilestoreStorageClass, GkeGateway, ConfigConnectorContext, GceIngress, CockroachDbCluster, CockroachDbRegionStack, RayCluster, RayJob, RayService, ArgoAppFor, ArgoAppSetForRegions, registerArgoCluster, FluxGitSource, FluxAppFor, AgicIngress, AzureDiskStorageClass, AzureFileStorageClass, AzureMonitorCollector, AksWorkloadIdentityServiceAccount, GkeFluentBitAgent, GkeOtelCollector, GkeExternalDnsAgent, AksExternalDnsAgent, Model, resolveModelStorageUri, OperatorStack, deriveHostVerbClass, DEFAULT_RESOURCE_RULES, } from "./composites/index.js";
47
+ // RBAC verb constants
48
+ export * from "./actions/index.js";
49
+ // Spec utilities (for tooling)
50
+ export { fetchK8sSchema, fetchSchemas, K8S_SCHEMA_VERSION } from "./spec/fetch.js";
51
+ export { parseK8sSwagger, k8sShortName, k8sServiceName, gvkToTypeName, gvkToApiVersion } from "./spec/parse.js";
52
+ // Code generation pipeline
53
+ export { generate, writeGeneratedFiles } from "./codegen/generate.js";
54
+ export { packageLexicon } from "./codegen/package.js";
55
+ export { parseCRD, parseCRDSpec } from "./crd/parser.js";
56
+ export { loadCRDs, loadMultipleCRDs } from "./crd/loader.js";
57
+ // Project-local CRD classes (`k8s.crds`, `chant generate`): the generated
58
+ // module registers its kinds through this.
59
+ export { registerProjectKinds } from "./project-kinds.js";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "35c3cfce38095b6ef87685a2b4c2f38401c33ac6473ce5353b5acbe50042d146",
4
+ "manifest.json": "297c642f88996e02ecc1c6a83cd2421f6d9a9aa71ea68b89b0a78ec9efef65c8",
5
5
  "meta.json": "c1831ac15083f5e0e45b29698d7b77f1c01646240fe6de5d6320753188594f69",
6
6
  "types/index.d.ts": "5c5340046d090ae9db5553039d923cf92a8b2eb57aa4dc941273ed5bcfb5bc9d",
7
7
  "rules/argo-appset-single-project.ts": "afa9f310753aa2d475f35012b13135b2dfaebed2a35d44edbe185ebc07673674",
@@ -15,7 +15,7 @@
15
15
  "rules/argo002.ts": "d2f07daabfc7a4624d3d60ea151fd2380d43f1578dd6a17825f6f6e0ebc610ba",
16
16
  "rules/argo003.ts": "a61024fbd3db772eface6b2e4fee618a5818f12a1050faea8e358e0fdc992396",
17
17
  "rules/argo005.ts": "611ea489e005e3ead925013e636f0d7c6899fd0ce68c59a97541fc6fe4e8d25c",
18
- "rules/crd-schema-helpers.ts": "06dd82481653c42a50be546e321d7fcc870ea210c079fc606a114516aaa53432",
18
+ "rules/crd-schema-helpers.ts": "131783fd70ccb3e829084550f6e66e5af3d436d909803b2ab60b5c06f9f32039",
19
19
  "rules/flux002.ts": "4269ce13121bc5b28c02aad06765dc85085a1c9ebcc936ae958663b85de07bc6",
20
20
  "rules/flux003.ts": "a174af9941bd2491a9bbf72039ab2fc4d4f4de388b2884ddf7123f05594d9d4e",
21
21
  "rules/k8s-helpers.ts": "868cac99b4505a8e060384a716047646da1583568ef6da471a186dc760961212",
@@ -78,5 +78,5 @@
78
78
  "skills/chant-k8s-argo.md": "24c9a85b78a2fc5c6657424baac9cc6d6caff6f47605b8146b2c0082133181cf",
79
79
  "skills/chant-k8s-flux.md": "9670efc2e9854bd14686b5adeb707396b9030a4dcaee6529b30abf56efe2c50c"
80
80
  },
81
- "composite": "79727761d5ff2addfaa2458cd8b7d01850f5669d52cd3f38a4b5cc8ec6b21778"
81
+ "composite": "067ab31520928c9a103272ab7cac3ae17752fe1bec0c6cee9bf54653005eb187"
82
82
  }