@intentius/chant 0.124.13 → 0.124.14

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 (907) hide show
  1. package/bin/chant +11 -0
  2. package/dist/agents/checks.js +326 -0
  3. package/dist/agents/discover.js +885 -0
  4. package/dist/agents/importer.js +17 -0
  5. package/dist/agents/index.js +12 -0
  6. package/dist/agents/types.js +19 -0
  7. package/dist/apply.js +151 -0
  8. package/dist/attrref.js +70 -0
  9. package/dist/audit/catalog.js +350 -0
  10. package/dist/audit/core.js +252 -0
  11. package/dist/audit/discover.js +633 -0
  12. package/dist/audit/fetch.js +666 -0
  13. package/dist/audit/lineage.js +91 -0
  14. package/dist/audit/nginx.js +366 -0
  15. package/dist/audit/prior-art.js +132 -0
  16. package/dist/audit/proof.js +321 -0
  17. package/dist/audit/report-html.js +194 -0
  18. package/dist/audit/report-model.js +198 -0
  19. package/dist/audit/report.js +102 -0
  20. package/dist/audit/rules-doc.js +144 -0
  21. package/dist/audit/secrets.js +405 -0
  22. package/dist/audit/terraform-state.js +140 -0
  23. package/dist/audit/wrangler.js +262 -0
  24. package/dist/behaviour-delta.js +401 -0
  25. package/dist/behaviour-engine.js +357 -0
  26. package/dist/behaviour-graph.js +83 -0
  27. package/dist/behaviour-http.js +188 -0
  28. package/dist/behaviour-kinds.js +172 -0
  29. package/dist/behaviour-overlay.js +50 -0
  30. package/dist/behaviour-predict.js +188 -0
  31. package/dist/behaviour-request.js +194 -0
  32. package/dist/behaviour.js +1325 -0
  33. package/dist/build-params.js +108 -0
  34. package/dist/build.js +668 -0
  35. package/dist/builder.js +44 -0
  36. package/dist/cdk/advise.js +30 -0
  37. package/dist/cdk/assembly.js +122 -0
  38. package/dist/cdk/graph.js +444 -0
  39. package/dist/cdk/tier-map.js +64 -0
  40. package/dist/cdk/types.js +24 -0
  41. package/dist/change-set.js +312 -0
  42. package/dist/child-project.js +21 -0
  43. package/dist/claimed-fields.js +135 -0
  44. package/dist/cli/build-options.js +70 -0
  45. package/dist/cli/build-params-cli.js +139 -0
  46. package/dist/cli/command-group.js +123 -0
  47. package/dist/cli/commands/audit-agents.js +326 -0
  48. package/dist/cli/commands/audit.js +571 -0
  49. package/dist/cli/commands/build.js +920 -0
  50. package/dist/cli/commands/carve-apply.js +153 -0
  51. package/dist/cli/commands/carve-bridge.js +201 -0
  52. package/dist/cli/commands/carve-emit.js +332 -0
  53. package/dist/cli/commands/carve-status.js +119 -0
  54. package/dist/cli/commands/carve.js +204 -0
  55. package/dist/cli/commands/check-lexicon-docs.js +79 -0
  56. package/dist/cli/commands/check-lexicon-examples.js +177 -0
  57. package/dist/cli/commands/check-lexicon-intrinsics.js +291 -0
  58. package/dist/cli/commands/check-lexicon-mcp.js +82 -0
  59. package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
  60. package/dist/cli/commands/check-lexicon-plugin.js +104 -0
  61. package/dist/cli/commands/check-lexicon.js +766 -0
  62. package/dist/cli/commands/describe.js +85 -0
  63. package/dist/cli/commands/diff.js +175 -0
  64. package/dist/cli/commands/doctor.js +350 -0
  65. package/dist/cli/commands/import-agents.js +155 -0
  66. package/dist/cli/commands/import.js +670 -0
  67. package/dist/cli/commands/init-lexicon/templates/codegen.js +194 -0
  68. package/dist/cli/commands/init-lexicon/templates/docs.js +100 -0
  69. package/dist/cli/commands/init-lexicon/templates/examples.js +29 -0
  70. package/dist/cli/commands/init-lexicon/templates/lint.js +34 -0
  71. package/dist/cli/commands/init-lexicon/templates/lsp.js +37 -0
  72. package/dist/cli/commands/init-lexicon/templates/plugin.js +108 -0
  73. package/dist/cli/commands/init-lexicon/templates/project.js +240 -0
  74. package/dist/cli/commands/init-lexicon/templates/spec.js +56 -0
  75. package/dist/cli/commands/init-lexicon/templates/tests.js +66 -0
  76. package/dist/cli/commands/init-lexicon.js +172 -0
  77. package/dist/cli/commands/init.js +381 -0
  78. package/dist/cli/commands/lexicon-rolling-upgrade.js +145 -0
  79. package/dist/cli/commands/lexicon-surface-diff.js +145 -0
  80. package/dist/cli/commands/licenses.js +125 -0
  81. package/dist/cli/commands/lint.d.ts.map +1 -1
  82. package/dist/cli/commands/lint.js +948 -0
  83. package/dist/cli/commands/list.js +63 -0
  84. package/dist/cli/commands/migrate.d.ts.map +1 -1
  85. package/dist/cli/commands/migrate.js +423 -0
  86. package/dist/cli/commands/onboard.js +403 -0
  87. package/dist/cli/commands/pinned-upgrade.js +191 -0
  88. package/dist/cli/commands/update.js +194 -0
  89. package/dist/cli/commands/vendor.js +217 -0
  90. package/dist/cli/conflict-check.js +104 -0
  91. package/dist/cli/debug.js +8 -0
  92. package/dist/cli/format.js +104 -0
  93. package/dist/cli/handlers/build.js +267 -0
  94. package/dist/cli/handlers/carve-apply.js +30 -0
  95. package/dist/cli/handlers/carve-bridge.js +28 -0
  96. package/dist/cli/handlers/carve-emit.js +50 -0
  97. package/dist/cli/handlers/carve-status.js +26 -0
  98. package/dist/cli/handlers/carve.js +40 -0
  99. package/dist/cli/handlers/change-set.js +46 -0
  100. package/dist/cli/handlers/components.js +730 -0
  101. package/dist/cli/handlers/dev.js +113 -0
  102. package/dist/cli/handlers/emulator.js +233 -0
  103. package/dist/cli/handlers/explain.js +54 -0
  104. package/dist/cli/handlers/fan-out.js +422 -0
  105. package/dist/cli/handlers/gate-resume.js +275 -0
  106. package/dist/cli/handlers/generate.js +84 -0
  107. package/dist/cli/handlers/graph.js +969 -0
  108. package/dist/cli/handlers/init.js +102 -0
  109. package/dist/cli/handlers/lifecycle.js +1727 -0
  110. package/dist/cli/handlers/lint.js +62 -0
  111. package/dist/cli/handlers/migrate.js +48 -0
  112. package/dist/cli/handlers/misc.js +391 -0
  113. package/dist/cli/handlers/operator.js +1162 -0
  114. package/dist/cli/handlers/override-approve.js +102 -0
  115. package/dist/cli/handlers/pr.js +503 -0
  116. package/dist/cli/handlers/promote.js +342 -0
  117. package/dist/cli/handlers/run-generate.js +206 -0
  118. package/dist/cli/handlers/run-wave.js +66 -0
  119. package/dist/cli/handlers/run.js +1191 -0
  120. package/dist/cli/handlers/scenario.js +325 -0
  121. package/dist/cli/handlers/search.js +924 -0
  122. package/dist/cli/handlers/serve.js +32 -0
  123. package/dist/cli/handlers/vendor.js +154 -0
  124. package/dist/cli/index.js +3 -0
  125. package/dist/cli/is-entry-point.js +23 -0
  126. package/dist/cli/lsp/capabilities.js +28 -0
  127. package/dist/cli/lsp/diagnostics.js +34 -0
  128. package/dist/cli/lsp/server.js +329 -0
  129. package/dist/cli/main.d.ts.map +1 -1
  130. package/dist/cli/main.js +2540 -0
  131. package/dist/cli/mcp/lifecycle-tools.js +80 -0
  132. package/dist/cli/mcp/op-tools.js +306 -0
  133. package/dist/cli/mcp/resource-handlers.js +258 -0
  134. package/dist/cli/mcp/resources/context.js +85 -0
  135. package/dist/cli/mcp/server.js +353 -0
  136. package/dist/cli/mcp/tools/build.js +111 -0
  137. package/dist/cli/mcp/tools/composites.js +95 -0
  138. package/dist/cli/mcp/tools/explain.js +166 -0
  139. package/dist/cli/mcp/tools/import.js +49 -0
  140. package/dist/cli/mcp/tools/lint.js +41 -0
  141. package/dist/cli/mcp/tools/scaffold.js +111 -0
  142. package/dist/cli/mcp/tools/search.js +112 -0
  143. package/dist/cli/mcp/types.js +1 -0
  144. package/dist/cli/mcp/workspace-plugins.js +91 -0
  145. package/dist/cli/mcp/workspace-tools.d.ts +1 -1
  146. package/dist/cli/mcp/workspace-tools.js +564 -0
  147. package/dist/cli/mcp-config.js +70 -0
  148. package/dist/cli/plugins.js +313 -0
  149. package/dist/cli/registry.js +23 -0
  150. package/dist/cli/reporters/stylish.js +329 -0
  151. package/dist/cli/version.js +15 -0
  152. package/dist/cli/watch.js +79 -0
  153. package/dist/codegen/bound-property-types.js +82 -0
  154. package/dist/codegen/coverage.js +119 -0
  155. package/dist/codegen/docs-file-markers.js +60 -0
  156. package/dist/codegen/docs-pages.js +115 -0
  157. package/dist/codegen/docs-rule-scanning.js +164 -0
  158. package/dist/codegen/docs-rules.js +76 -0
  159. package/dist/codegen/docs-sections.js +117 -0
  160. package/dist/codegen/docs-sidebar.js +65 -0
  161. package/dist/codegen/docs-types.js +4 -0
  162. package/dist/codegen/docs.js +356 -0
  163. package/dist/codegen/fetch.js +340 -0
  164. package/dist/codegen/generate-post-synth-barrel.js +63 -0
  165. package/dist/codegen/generate-registry.js +71 -0
  166. package/dist/codegen/generate-runtime-index.js +56 -0
  167. package/dist/codegen/generate-typescript.js +119 -0
  168. package/dist/codegen/generate.js +115 -0
  169. package/dist/codegen/json-patch.js +141 -0
  170. package/dist/codegen/json-schema-to-ts.js +344 -0
  171. package/dist/codegen/json-schema.js +246 -0
  172. package/dist/codegen/lexicon-regen.js +412 -0
  173. package/dist/codegen/naming.js +217 -0
  174. package/dist/codegen/okf-lexicon.js +245 -0
  175. package/dist/codegen/package.js +150 -0
  176. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  177. package/dist/codegen/pinned-upgrade.js +494 -0
  178. package/dist/codegen/registry.js +60 -0
  179. package/dist/codegen/rehype-base-url.mjs +68 -0
  180. package/dist/codegen/rolling-upgrade.js +217 -0
  181. package/dist/codegen/surface-snapshot.js +537 -0
  182. package/dist/codegen/testdata/postgres-tags.json +242 -0
  183. package/dist/codegen/topo-sort.js +36 -0
  184. package/dist/codegen/typecheck.js +115 -0
  185. package/dist/codegen/validate.js +200 -0
  186. package/dist/codegen/version-bump.js +35 -0
  187. package/dist/components/auto-release.js +143 -0
  188. package/dist/components/builders.js +47 -0
  189. package/dist/components/capability-plugin-loader.js +175 -0
  190. package/dist/components/capability-plugin-schema.js +46 -0
  191. package/dist/components/capability-plugin.js +99 -0
  192. package/dist/components/capability.js +60 -0
  193. package/dist/components/changed-files.js +72 -0
  194. package/dist/components/cli-support.js +427 -0
  195. package/dist/components/component.js +120 -0
  196. package/dist/components/component.schema.json +271 -0
  197. package/dist/components/config-defaults.js +130 -0
  198. package/dist/components/deploy-units.js +60 -0
  199. package/dist/components/discover.d.ts.map +1 -1
  200. package/dist/components/discover.js +189 -0
  201. package/dist/components/driver-output.js +86 -0
  202. package/dist/components/driver.js +728 -0
  203. package/dist/components/fan-out-output.js +165 -0
  204. package/dist/components/fan-out-record.js +94 -0
  205. package/dist/components/fan-out-run.js +373 -0
  206. package/dist/components/fan-out-support.js +60 -0
  207. package/dist/components/fan-out.js +273 -0
  208. package/dist/components/gate-plan.js +41 -0
  209. package/dist/components/gated-wave-pipeline.js +46 -0
  210. package/dist/components/index.js +24 -0
  211. package/dist/components/layers.js +28 -0
  212. package/dist/components/manifest-persistence.js +108 -0
  213. package/dist/components/pilots/alb-ecs.pilot.js +59 -0
  214. package/dist/components/pilots/dynamodb.pilot.js +51 -0
  215. package/dist/components/pilots/jar-emr.pilot.js +65 -0
  216. package/dist/components/pilots/lambda.pilot.js +52 -0
  217. package/dist/components/pilots/neo4j-fanout.pilot.js +68 -0
  218. package/dist/components/pilots/project.js +12 -0
  219. package/dist/components/pr-pipeline.js +134 -0
  220. package/dist/components/pr-run.js +363 -0
  221. package/dist/components/presets/ecs-fargate.js +72 -0
  222. package/dist/components/presets/index.js +28 -0
  223. package/dist/components/presets/lambda.js +34 -0
  224. package/dist/components/presets/single-host-compose.js +41 -0
  225. package/dist/components/promote.js +549 -0
  226. package/dist/components/registry.js +34 -0
  227. package/dist/components/run-progress.js +33 -0
  228. package/dist/components/sandbox/driver.d.ts.map +1 -1
  229. package/dist/components/sandbox/driver.js +93 -0
  230. package/dist/components/sandbox/run.js +115 -0
  231. package/dist/components/starter-plugin.js +104 -0
  232. package/dist/components/verbs/__tests__/mock-cloud-executor.js +68 -0
  233. package/dist/components/verbs/__tests__/mock-process-runner.js +45 -0
  234. package/dist/components/verbs/__tests__/mock-sbom-generator.js +56 -0
  235. package/dist/components/verbs/bom-writer.js +287 -0
  236. package/dist/components/verbs/build-archive.js +188 -0
  237. package/dist/components/verbs/build.js +142 -0
  238. package/dist/components/verbs/cloud-executor.js +110 -0
  239. package/dist/components/verbs/component-bom.js +125 -0
  240. package/dist/components/verbs/ensure-secret.js +50 -0
  241. package/dist/components/verbs/index.js +61 -0
  242. package/dist/components/verbs/license-policy.js +75 -0
  243. package/dist/components/verbs/lockfile-sbom-generator.js +191 -0
  244. package/dist/components/verbs/process-runner.js +78 -0
  245. package/dist/components/verbs/r2-sync.js +93 -0
  246. package/dist/components/verbs/reproducibility.js +62 -0
  247. package/dist/components/verbs/run-agent.js +577 -0
  248. package/dist/components/verbs/sbom-generator.js +119 -0
  249. package/dist/components/verbs/sbom.js +97 -0
  250. package/dist/components/verbs/shell.js +32 -0
  251. package/dist/components/verbs/sign.js +221 -0
  252. package/dist/components/verbs/stub.js +28 -0
  253. package/dist/components/verbs/tool-sbom-generator.js +154 -0
  254. package/dist/components/verbs/verify.js +112 -0
  255. package/dist/components/verbs/vex.js +131 -0
  256. package/dist/components/verbs/vuln-gate.js +152 -0
  257. package/dist/components/verbs/vuln-scan.js +288 -0
  258. package/dist/components/verbs/wait-verify.js +106 -0
  259. package/dist/components/verbs/wrangler.js +179 -0
  260. package/dist/components/wave-plan.js +102 -0
  261. package/dist/composite.js +305 -0
  262. package/dist/config-import.d.ts.map +1 -1
  263. package/dist/config-import.js +22 -0
  264. package/dist/config-sandbox.js +122 -0
  265. package/dist/config-static.js +206 -0
  266. package/dist/config.js +605 -0
  267. package/dist/content-digest.js +23 -0
  268. package/dist/declarable.js +114 -0
  269. package/dist/deep-observation.js +437 -0
  270. package/dist/detectLexicon.js +54 -0
  271. package/dist/discovery/cache.js +70 -0
  272. package/dist/discovery/collect.js +208 -0
  273. package/dist/discovery/cycles.js +95 -0
  274. package/dist/discovery/entity-wire-codec.js +391 -0
  275. package/dist/discovery/entity-wire.js +42 -0
  276. package/dist/discovery/files.js +121 -0
  277. package/dist/discovery/fold-import.d.ts.map +1 -1
  278. package/dist/discovery/fold-import.js +4178 -0
  279. package/dist/discovery/fold-rank.js +292 -0
  280. package/dist/discovery/graph.js +115 -0
  281. package/dist/discovery/import.d.ts.map +1 -1
  282. package/dist/discovery/import.js +65 -0
  283. package/dist/discovery/index.js +333 -0
  284. package/dist/discovery/param-deps.js +487 -0
  285. package/dist/discovery/resolve.js +39 -0
  286. package/dist/discovery/sandbox/bundle.js +214 -0
  287. package/dist/discovery/sandbox/child-errors.js +26 -0
  288. package/dist/discovery/sandbox/config-run.js +100 -0
  289. package/dist/discovery/sandbox/config-wire.js +183 -0
  290. package/dist/discovery/sandbox/driver.d.ts.map +1 -1
  291. package/dist/discovery/sandbox/driver.js +333 -0
  292. package/dist/discovery/sandbox/fork.js +229 -0
  293. package/dist/discovery/sandbox/policy-run.js +142 -0
  294. package/dist/discovery/sandbox/policy-wire.js +152 -0
  295. package/dist/discovery/sandbox/run.js +77 -0
  296. package/dist/discovery/specifier-resolve.js +320 -0
  297. package/dist/discovery/walk.js +284 -0
  298. package/dist/effect-receipt.js +340 -0
  299. package/dist/env.js +55 -0
  300. package/dist/errors.js +62 -0
  301. package/dist/fold/fold.js +1434 -0
  302. package/dist/fold/foldable-helpers.js +229 -0
  303. package/dist/fold/subset.js +696 -0
  304. package/dist/fold-provenance.js +414 -0
  305. package/dist/gate-decision.js +260 -0
  306. package/dist/gate-resume-run.js +154 -0
  307. package/dist/gated-waves.js +165 -0
  308. package/dist/governance.js +43 -0
  309. package/dist/graph-declared.js +45 -0
  310. package/dist/graph-detail.js +207 -0
  311. package/dist/graph-dot.js +54 -0
  312. package/dist/graph-effective.js +107 -0
  313. package/dist/graph-ir.js +623 -0
  314. package/dist/graph-layout.js +184 -0
  315. package/dist/graph-lens.js +105 -0
  316. package/dist/graph-mermaid.js +83 -0
  317. package/dist/graph-ops.js +39 -0
  318. package/dist/graph-refs.js +156 -0
  319. package/dist/held-elsewhere.js +87 -0
  320. package/dist/identity.js +251 -0
  321. package/dist/import/base-parser.js +34 -0
  322. package/dist/import/embedded.js +255 -0
  323. package/dist/import/generator.js +1 -0
  324. package/dist/import/ir-utils.js +85 -0
  325. package/dist/import/parser-options.js +45 -0
  326. package/dist/import/parser.js +1 -0
  327. package/dist/index.js +118 -0
  328. package/dist/intrinsic-interpolation.js +73 -0
  329. package/dist/intrinsic.js +31 -0
  330. package/dist/join-key.js +35 -0
  331. package/dist/kubectl-context.js +150 -0
  332. package/dist/lexicon-config.js +58 -0
  333. package/dist/lexicon-integrity.js +47 -0
  334. package/dist/lexicon-manifest.js +70 -0
  335. package/dist/lexicon-module.d.ts.map +1 -1
  336. package/dist/lexicon-module.js +241 -0
  337. package/dist/lexicon-output.js +218 -0
  338. package/dist/lexicon-plugin-helpers.js +104 -0
  339. package/dist/lexicon-schema.js +136 -0
  340. package/dist/lexicon.js +130 -0
  341. package/dist/lifecycle/affected.js +224 -0
  342. package/dist/lifecycle/assert-live.js +110 -0
  343. package/dist/lifecycle/build-ledger-store.js +160 -0
  344. package/dist/lifecycle/build-ledger.js +155 -0
  345. package/dist/lifecycle/change-set.js +356 -0
  346. package/dist/lifecycle/converge-ledger.js +161 -0
  347. package/dist/lifecycle/deep-diff.js +233 -0
  348. package/dist/lifecycle/deep-observe.js +147 -0
  349. package/dist/lifecycle/digest.js +143 -0
  350. package/dist/lifecycle/disruption.js +135 -0
  351. package/dist/lifecycle/gate-applied.js +113 -0
  352. package/dist/lifecycle/gate-audit.js +341 -0
  353. package/dist/lifecycle/gate-ledger-select.js +89 -0
  354. package/dist/lifecycle/gate-ledger.js +193 -0
  355. package/dist/lifecycle/gate-origin.js +117 -0
  356. package/dist/lifecycle/gate-pending.js +58 -0
  357. package/dist/lifecycle/git.js +1182 -0
  358. package/dist/lifecycle/identity.js +58 -0
  359. package/dist/lifecycle/index.js +26 -0
  360. package/dist/lifecycle/lease.js +283 -0
  361. package/dist/lifecycle/ledger-port.js +1 -0
  362. package/dist/lifecycle/legacy-digest.js +91 -0
  363. package/dist/lifecycle/live-diff.js +274 -0
  364. package/dist/lifecycle/local-note.js +15 -0
  365. package/dist/lifecycle/member-ledger.js +122 -0
  366. package/dist/lifecycle/observation-baseline.js +155 -0
  367. package/dist/lifecycle/observe.js +375 -0
  368. package/dist/lifecycle/oras-referrer-lookup.js +82 -0
  369. package/dist/lifecycle/override-ledger.js +54 -0
  370. package/dist/lifecycle/plan-digest.js +110 -0
  371. package/dist/lifecycle/plan-ledger.js +129 -0
  372. package/dist/lifecycle/receipt-plan.js +192 -0
  373. package/dist/lifecycle/release-ledger.js +155 -0
  374. package/dist/lifecycle/release-read.js +64 -0
  375. package/dist/lifecycle/replay.js +193 -0
  376. package/dist/lifecycle/rollback.js +102 -0
  377. package/dist/lifecycle/run-ledger.js +183 -0
  378. package/dist/lifecycle/scenario-eval.js +204 -0
  379. package/dist/lifecycle/scenario.js +214 -0
  380. package/dist/lifecycle/snapshot.js +239 -0
  381. package/dist/lifecycle/status.js +447 -0
  382. package/dist/lifecycle/symptoms.js +117 -0
  383. package/dist/lifecycle/teardown.js +255 -0
  384. package/dist/lifecycle/types.js +1 -0
  385. package/dist/lifecycle/unobserved-gate.js +33 -0
  386. package/dist/lifecycle/wave-plans.js +68 -0
  387. package/dist/lifecycle/work-item-id.js +36 -0
  388. package/dist/lifecycle/work-lease.js +393 -0
  389. package/dist/lint/component-checks.js +87 -0
  390. package/dist/lint/config.js +483 -0
  391. package/dist/lint/declarative.js +122 -0
  392. package/dist/lint/discover.d.ts.map +1 -1
  393. package/dist/lint/discover.js +138 -0
  394. package/dist/lint/engine.js +246 -0
  395. package/dist/lint/knowledge-checks.js +64 -0
  396. package/dist/lint/named-checks.js +22 -0
  397. package/dist/lint/output-checks.js +87 -0
  398. package/dist/lint/output-docs.js +163 -0
  399. package/dist/lint/parser.js +33 -0
  400. package/dist/lint/pipeline-change-gate.js +70 -0
  401. package/dist/lint/policy-import.d.ts +1 -1
  402. package/dist/lint/policy-import.d.ts.map +1 -1
  403. package/dist/lint/policy-import.js +62 -0
  404. package/dist/lint/policy-sandbox.js +86 -0
  405. package/dist/lint/policy.js +122 -0
  406. package/dist/lint/post-synth.js +87 -0
  407. package/dist/lint/presets/relaxed.json +26 -0
  408. package/dist/lint/presets/strict.json +24 -24
  409. package/dist/lint/receipt-checks.js +83 -0
  410. package/dist/lint/rule-loader.d.ts.map +1 -1
  411. package/dist/lint/rule-loader.js +89 -0
  412. package/dist/lint/rule-registry.js +86 -0
  413. package/dist/lint/rule.js +1 -0
  414. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.js +7 -0
  415. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.js +7 -0
  416. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.js +9 -0
  417. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.js +11 -0
  418. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.js +9 -0
  419. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.js +25 -0
  420. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.js +8 -0
  421. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.js +21 -0
  422. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.js +8 -0
  423. package/dist/lint/rules/__fixtures__/comp/comp003/pass/agent-turn.component.js +24 -0
  424. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.js +17 -0
  425. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.js +8 -0
  426. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.js +18 -0
  427. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.js +20 -0
  428. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.js +8 -0
  429. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.js +12 -0
  430. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.js +16 -0
  431. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.js +8 -0
  432. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.js +12 -0
  433. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.js +11 -0
  434. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.js +11 -0
  435. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.js +10 -0
  436. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.js +16 -0
  437. package/dist/lint/rules/comp/comp001-publishes-never-applies.js +69 -0
  438. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.js +84 -0
  439. package/dist/lint/rules/comp/comp003-mutating-no-rollback.js +103 -0
  440. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.js +70 -0
  441. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.js +109 -0
  442. package/dist/lint/rules/comp/comp006-shell-needs-reason.js +49 -0
  443. package/dist/lint/rules/comp/comp007-composition-sprawl.js +64 -0
  444. package/dist/lint/rules/comp/index.js +33 -0
  445. package/dist/lint/rules/comp/support.js +129 -0
  446. package/dist/lint/rules/composite-scope.js +51 -0
  447. package/dist/lint/rules/cor017-composite-name-match.js +93 -0
  448. package/dist/lint/rules/cor018-composite-prefer-lexicon-type.js +136 -0
  449. package/dist/lint/rules/cor021-env-literal-name.js +100 -0
  450. package/dist/lint/rules/cor022-receipt-leaf.js +118 -0
  451. package/dist/lint/rules/cor024-receipt-secret-pointer.js +199 -0
  452. package/dist/lint/rules/declarable-naming-convention.js +62 -0
  453. package/dist/lint/rules/evl001-non-literal-expression.js +66 -0
  454. package/dist/lint/rules/evl002-control-flow-resource.js +69 -0
  455. package/dist/lint/rules/evl003-dynamic-property-access.js +44 -0
  456. package/dist/lint/rules/evl004-spread-non-const.js +94 -0
  457. package/dist/lint/rules/evl005-resource-block-body.js +41 -0
  458. package/dist/lint/rules/evl007-invalid-siblings.js +105 -0
  459. package/dist/lint/rules/evl009-composite-no-constant.js +158 -0
  460. package/dist/lint/rules/evl010-composite-no-transform.js +59 -0
  461. package/dist/lint/rules/evl011-symbolic-in-template.js +106 -0
  462. package/dist/lint/rules/export-required.js +115 -0
  463. package/dist/lint/rules/file-declarable-limit.js +88 -0
  464. package/dist/lint/rules/flat-declarations.js +62 -0
  465. package/dist/lint/rules/index.js +90 -0
  466. package/dist/lint/rules/no-cyclic-declarable-ref.js +138 -0
  467. package/dist/lint/rules/no-redundant-type-import.js +76 -0
  468. package/dist/lint/rules/no-redundant-value-cast.js +41 -0
  469. package/dist/lint/rules/no-string-ref.js +59 -0
  470. package/dist/lint/rules/no-unused-declarable-import.js +75 -0
  471. package/dist/lint/rules/no-unused-declarable.js +142 -0
  472. package/dist/lint/rules/op/index.js +28 -0
  473. package/dist/lint/rules/op/ops012-activity-contract.js +54 -0
  474. package/dist/lint/rules/op/ops013-step-output-ref.js +88 -0
  475. package/dist/lint/rules/op/ops014-converge-rule-refusals.js +114 -0
  476. package/dist/lint/rules/op/ops015-gate-approval.js +45 -0
  477. package/dist/lint/rules/op/support.js +11 -0
  478. package/dist/lint/rules/op/sys010-key-over-plain-http.js +100 -0
  479. package/dist/lint/rules/property-kind.js +56 -0
  480. package/dist/lint/rules/single-concern-file.js +71 -0
  481. package/dist/lint/rules/sys001-no-literal-key.js +60 -0
  482. package/dist/lint/selectors.js +168 -0
  483. package/dist/lint/suppressions.js +129 -0
  484. package/dist/lint/typescript.js +17 -0
  485. package/dist/live-endpoint.js +113 -0
  486. package/dist/live-read-session.js +76 -0
  487. package/dist/lsp/lexicon-providers.js +163 -0
  488. package/dist/lsp/types.js +5 -0
  489. package/dist/managed-fields.js +293 -0
  490. package/dist/mcp/types.js +4 -0
  491. package/dist/notify-verify.js +0 -1
  492. package/dist/notify.js +0 -1
  493. package/dist/notify.schema.json +72 -0
  494. package/dist/observation.js +266 -0
  495. package/dist/okf-read.js +134 -0
  496. package/dist/okf.js +275 -0
  497. package/dist/op/__fixtures__/decide-stub-backend.js +125 -0
  498. package/dist/op/activities/activity-contracts.js +313 -0
  499. package/dist/op/activities/apply.js +582 -0
  500. package/dist/op/activities/build.js +18 -0
  501. package/dist/op/activities/change-coverage.js +40 -0
  502. package/dist/op/activities/change-set.js +64 -0
  503. package/dist/op/activities/converge.js +492 -0
  504. package/dist/op/activities/decide.js +211 -0
  505. package/dist/op/activities/env-teardown.js +110 -0
  506. package/dist/op/activities/factory.js +591 -0
  507. package/dist/op/activities/forge-pull-request.js +82 -0
  508. package/dist/op/activities/gh-host.js +78 -0
  509. package/dist/op/activities/guard-validate.js +165 -0
  510. package/dist/op/activities/http-check.js +40 -0
  511. package/dist/op/activities/index.js +59 -0
  512. package/dist/op/activities/lexicon-upgrade.js +629 -0
  513. package/dist/op/activities/lifecycle.js +109 -0
  514. package/dist/op/activities/pipeline-audit.js +147 -0
  515. package/dist/op/activities/policy.js +26 -0
  516. package/dist/op/activities/predict-behaviour.js +341 -0
  517. package/dist/op/activities/propose-upgrade.js +165 -0
  518. package/dist/op/activities/reconcile.js +997 -0
  519. package/dist/op/activities/shell.js +118 -0
  520. package/dist/op/activities/source-release.js +97 -0
  521. package/dist/op/activities/source-rollback.js +165 -0
  522. package/dist/op/activities/teardown.js +17 -0
  523. package/dist/op/activities/util.js +6 -0
  524. package/dist/op/activities/wait.js +51 -0
  525. package/dist/op/activities/work-evidence.js +35 -0
  526. package/dist/op/activities/workflow-audit.js +133 -0
  527. package/dist/op/activity-contract-registry.js +106 -0
  528. package/dist/op/activity-contract.js +232 -0
  529. package/dist/op/activity-failure.js +31 -0
  530. package/dist/op/activity-profiles.js +129 -0
  531. package/dist/op/activity-registry.js +105 -0
  532. package/dist/op/activity-runtime.js +28 -0
  533. package/dist/op/builders.js +801 -0
  534. package/dist/op/change-signal.js +118 -0
  535. package/dist/op/composites/apply-op.js +151 -0
  536. package/dist/op/composites/behaviour-op.js +65 -0
  537. package/dist/op/composites/converge-op.js +141 -0
  538. package/dist/op/composites/index.js +19 -0
  539. package/dist/op/composites/lexicon-upgrade-op.js +107 -0
  540. package/dist/op/composites/pipeline-audit-op.js +50 -0
  541. package/dist/op/composites/reconcile-op.js +84 -0
  542. package/dist/op/composites/watch-op.js +69 -0
  543. package/dist/op/composites/workflow-audit-op.js +57 -0
  544. package/dist/op/converge-rule.js +205 -0
  545. package/dist/op/cron.js +146 -0
  546. package/dist/op/decide-backend.js +181 -0
  547. package/dist/op/decide-config.js +68 -0
  548. package/dist/op/decide-read-inputs.js +141 -0
  549. package/dist/op/discover.d.ts.map +1 -1
  550. package/dist/op/discover.js +213 -0
  551. package/dist/op/duration.js +21 -0
  552. package/dist/op/emulator-freshness.js +80 -0
  553. package/dist/op/emulator-lifecycle.js +269 -0
  554. package/dist/op/factory.js +83 -0
  555. package/dist/op/gate-approval.js +172 -0
  556. package/dist/op/gate-name.js +86 -0
  557. package/dist/op/gate-plan-context.js +167 -0
  558. package/dist/op/gate-point-run.js +67 -0
  559. package/dist/op/gate-point.js +111 -0
  560. package/dist/op/gate-resume-plan.js +155 -0
  561. package/dist/op/gate-resume.js +31 -0
  562. package/dist/op/gate-review.js +290 -0
  563. package/dist/op/gate-run-locator.js +85 -0
  564. package/dist/op/gate-summary.js +100 -0
  565. package/dist/op/gate-wait.js +56 -0
  566. package/dist/op/gate.js +449 -0
  567. package/dist/op/generate-pipeline.js +124 -0
  568. package/dist/op/index.js +51 -0
  569. package/dist/op/lifecycle-receipt-store.js +45 -0
  570. package/dist/op/local-executor.js +1164 -0
  571. package/dist/op/local-output.js +140 -0
  572. package/dist/op/op-ir.js +317 -0
  573. package/dist/op/op-verb-class.js +131 -0
  574. package/dist/op/op-waves-notify.js +136 -0
  575. package/dist/op/op-waves-run.js +1657 -0
  576. package/dist/op/op-waves.js +409 -0
  577. package/dist/op/operator.js +743 -0
  578. package/dist/op/receipt-store.js +94 -0
  579. package/dist/op/resource.js +23 -0
  580. package/dist/op/run-context.js +28 -0
  581. package/dist/op/run-live.js +256 -0
  582. package/dist/op/runtime.js +21 -0
  583. package/dist/op/runtimes/local.js +195 -0
  584. package/dist/op/source-archive.js +131 -0
  585. package/dist/op/step-output-ref.js +397 -0
  586. package/dist/op/steward-beside.js +169 -0
  587. package/dist/op/steward-points.js +138 -0
  588. package/dist/op/steward-turn.js +59 -0
  589. package/dist/op/steward.js +317 -0
  590. package/dist/op/types.js +25 -0
  591. package/dist/op/work-lease-decl.js +81 -0
  592. package/dist/op/work-lease-run.js +393 -0
  593. package/dist/override-gate.js +284 -0
  594. package/dist/owner-chain.js +74 -0
  595. package/dist/ownership.js +92 -0
  596. package/dist/params.js +61 -0
  597. package/dist/plan-summary.js +711 -0
  598. package/dist/point-decision.js +211 -0
  599. package/dist/pr-forge.js +810 -0
  600. package/dist/pr-loop.js +203 -0
  601. package/dist/project-codegen.js +191 -0
  602. package/dist/project-root.js +74 -0
  603. package/dist/project-validation.js +50 -0
  604. package/dist/provenance.js +157 -0
  605. package/dist/pseudo-parameter.js +40 -0
  606. package/dist/reconcile.js +450 -0
  607. package/dist/resource-attributes.js +33 -0
  608. package/dist/runtime-adapter.js +77 -0
  609. package/dist/runtime.js +66 -0
  610. package/dist/secret-materialization.js +153 -0
  611. package/dist/secret-provenance.js +250 -0
  612. package/dist/serializer-walker.js +112 -0
  613. package/dist/serializer.js +1 -0
  614. package/dist/sort.js +45 -0
  615. package/dist/stack-output.js +115 -0
  616. package/dist/telemetry-attribution.js +149 -0
  617. package/dist/terraform/__fixtures__/build-graph.js +63 -0
  618. package/dist/terraform/adopt-state.js +40 -0
  619. package/dist/terraform/aws-resources.js +384 -0
  620. package/dist/terraform/bridge.js +204 -0
  621. package/dist/terraform/carve-provider.js +155 -0
  622. package/dist/terraform/carve.js +138 -0
  623. package/dist/terraform/data-source-shape.js +57 -0
  624. package/dist/terraform/emit-source.js +36 -0
  625. package/dist/terraform/excise.js +123 -0
  626. package/dist/terraform/graduate.js +128 -0
  627. package/dist/terraform/graph.js +435 -0
  628. package/dist/terraform/hcl2json.js +60 -0
  629. package/dist/terraform/manifest.js +149 -0
  630. package/dist/terraform/parse.js +81 -0
  631. package/dist/terraform/providers/aws.js +146 -0
  632. package/dist/terraform/providers/gcp.js +294 -0
  633. package/dist/terraform/providers/index.js +17 -0
  634. package/dist/terraform/providers/kubernetes.js +253 -0
  635. package/dist/terraform/score.js +151 -0
  636. package/dist/terraform/state.js +67 -0
  637. package/dist/terraform/tier-map.js +74 -0
  638. package/dist/terraform/types.js +13 -0
  639. package/dist/terraform/unified-diff.js +132 -0
  640. package/dist/testing.js +295 -0
  641. package/dist/toml-emit.js +153 -0
  642. package/dist/toml-parse.js +355 -0
  643. package/dist/toml-utils.js +60 -0
  644. package/dist/toml.js +428 -0
  645. package/dist/ts-loader.d.ts +46 -0
  646. package/dist/ts-loader.d.ts.map +1 -0
  647. package/dist/ts-loader.js +103 -0
  648. package/dist/types.js +1 -0
  649. package/dist/utils.js +61 -0
  650. package/dist/validation.js +20 -0
  651. package/dist/vendor/js-yaml-load.js +1662 -0
  652. package/dist/workspace/__fixtures__/contract-repo.js +103 -0
  653. package/dist/workspace/__fixtures__/decide-workspace.js +112 -0
  654. package/dist/workspace/__fixtures__/sessions.js +91 -0
  655. package/dist/workspace/__fixtures__/two-member-workspace.js +34 -0
  656. package/dist/workspace/agent-cli.js +99 -0
  657. package/dist/workspace/agent.schema.json +390 -0
  658. package/dist/workspace/answers-ledger.js +89 -0
  659. package/dist/workspace/box-cli.js +142 -0
  660. package/dist/workspace/box-factory-write.js +196 -0
  661. package/dist/workspace/box-factory-write.schema.json +342 -0
  662. package/dist/workspace/box-factory.js +88 -0
  663. package/dist/workspace/box-intent.js +126 -0
  664. package/dist/workspace/box-isolation.js +169 -0
  665. package/dist/workspace/box-listing-write.schema.json +204 -0
  666. package/dist/workspace/box-listing.js +298 -0
  667. package/dist/workspace/box-publish.js +352 -0
  668. package/dist/workspace/box-publish.schema.json +498 -0
  669. package/dist/workspace/box-services.js +39 -0
  670. package/dist/workspace/broker-protocol.js +359 -0
  671. package/dist/workspace/broker-protocol.schema.json +228 -0
  672. package/dist/workspace/change-set.schema.json +460 -0
  673. package/dist/workspace/changes-cli.js +56 -0
  674. package/dist/workspace/changes.js +446 -0
  675. package/dist/workspace/changes.schema.json +642 -0
  676. package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.js +198 -0
  677. package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.js +155 -0
  678. package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.js +214 -0
  679. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.js +180 -0
  680. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.js +99 -0
  681. package/dist/workspace/chant-migrations/chud-lexicon-exit.js +847 -0
  682. package/dist/workspace/chant-migrations.js +113 -0
  683. package/dist/workspace/check.schema.json +433 -0
  684. package/dist/workspace/checks/box-isolation.js +62 -0
  685. package/dist/workspace/checks/boxes.js +491 -0
  686. package/dist/workspace/checks/diagrams.js +104 -0
  687. package/dist/workspace/checks/generated.js +419 -0
  688. package/dist/workspace/checks/ledgers.js +212 -0
  689. package/dist/workspace/checks/links.js +191 -0
  690. package/dist/workspace/checks/live.js +100 -0
  691. package/dist/workspace/checks/pipelines.js +188 -0
  692. package/dist/workspace/checks/records.js +169 -0
  693. package/dist/workspace/checks.js +426 -0
  694. package/dist/workspace/ci-green-cli.js +125 -0
  695. package/dist/workspace/ci-green-forge.js +83 -0
  696. package/dist/workspace/ci-green-workflow.js +199 -0
  697. package/dist/workspace/ci-green.js +325 -0
  698. package/dist/workspace/ci-last-green.schema.json +158 -0
  699. package/dist/workspace/compose-graph.js +235 -0
  700. package/dist/workspace/compose-reports.js +146 -0
  701. package/dist/workspace/composites.js +264 -0
  702. package/dist/workspace/composites.schema.json +617 -0
  703. package/dist/workspace/conformance/__fixture__/app/package.json +7 -0
  704. package/dist/workspace/conformance/__fixture__/app/src/server.mjs +29 -0
  705. package/dist/workspace/conformance/__fixture__/decisions/decision.kind.mjs +54 -0
  706. package/dist/workspace/conformance/__fixture__/decisions/decision.schema.json +512 -0
  707. package/dist/workspace/conformance/__fixture__/decisions/fix-001-how-the-app-is-deployed.md +40 -0
  708. package/dist/workspace/conformance/__fixture__/delivery/chant.config.ts +7 -0
  709. package/dist/workspace/conformance/__fixture__/delivery/lexicon/index.ts +26 -0
  710. package/dist/workspace/conformance/__fixture__/delivery/package.json +7 -0
  711. package/dist/workspace/conformance/__fixture__/delivery/src/app.component.ts +14 -0
  712. package/dist/workspace/conformance/__fixture__/delivery/src/app.ts +4 -0
  713. package/dist/workspace/conformance/__fixtures__/reference-broker.js +205 -0
  714. package/dist/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
  715. package/dist/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
  716. package/dist/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
  717. package/dist/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
  718. package/dist/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
  719. package/dist/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
  720. package/dist/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
  721. package/dist/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
  722. package/dist/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
  723. package/dist/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
  724. package/dist/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
  725. package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
  726. package/dist/workspace/conformance/broker.js +736 -0
  727. package/dist/workspace/conformance/index.js +673 -0
  728. package/dist/workspace/conformance/vitest.js +108 -0
  729. package/dist/workspace/conformance/writer.js +1080 -0
  730. package/dist/workspace/decide.js +879 -0
  731. package/dist/workspace/decision-points.schema.json +135 -135
  732. package/dist/workspace/declaration-write-cli.js +74 -0
  733. package/dist/workspace/declaration-write.js +238 -0
  734. package/dist/workspace/declaration.js +938 -0
  735. package/dist/workspace/declaration.schema.json +1413 -1413
  736. package/dist/workspace/declared-kinds.js +106 -0
  737. package/dist/workspace/environments.js +164 -0
  738. package/dist/workspace/evidence.schema.json +279 -0
  739. package/dist/workspace/export-cli.js +185 -0
  740. package/dist/workspace/export.js +499 -0
  741. package/dist/workspace/factory-rules.js +175 -0
  742. package/dist/workspace/generated-files.js +92 -0
  743. package/dist/workspace/glob.js +45 -0
  744. package/dist/workspace/graph-cache.js +352 -0
  745. package/dist/workspace/graph-cli.js +348 -0
  746. package/dist/workspace/graph.schema.json +1338 -0
  747. package/dist/workspace/identity-gate-rule.js +75 -0
  748. package/dist/workspace/identity.js +126 -0
  749. package/dist/workspace/import.js +283 -0
  750. package/dist/workspace/init.js +620 -0
  751. package/dist/workspace/intent-cli.js +263 -0
  752. package/dist/workspace/intent-joins.js +201 -0
  753. package/dist/workspace/intent-record.js +352 -0
  754. package/dist/workspace/intent-record.schema.json +864 -0
  755. package/dist/workspace/intent.js +1582 -0
  756. package/dist/workspace/intent.schema.json +2420 -0
  757. package/dist/workspace/json-edit.js +221 -0
  758. package/dist/workspace/jsonc.js +235 -0
  759. package/dist/workspace/kind-readers.js +103 -0
  760. package/dist/workspace/kinds.js +587 -0
  761. package/dist/workspace/lexicon-symbols.js +112 -0
  762. package/dist/workspace/lineage-adopt-cli.js +102 -0
  763. package/dist/workspace/lineage-adopt.js +360 -0
  764. package/dist/workspace/lineage-check.js +282 -0
  765. package/dist/workspace/lineage-cli.js +121 -0
  766. package/dist/workspace/lineage-hash-index.js +284 -0
  767. package/dist/workspace/lineage-init.js +507 -0
  768. package/dist/workspace/lineage-lock.js +387 -0
  769. package/dist/workspace/lineage-merge.js +45 -0
  770. package/dist/workspace/lineage-migrations.d.ts.map +1 -1
  771. package/dist/workspace/lineage-migrations.js +329 -0
  772. package/dist/workspace/lineage-provenance.js +36 -0
  773. package/dist/workspace/lineage-update.js +138 -0
  774. package/dist/workspace/lineage-upgrade-cli.js +131 -0
  775. package/dist/workspace/lineage-upgrade.js +889 -0
  776. package/dist/workspace/lineage-vendor.js +171 -0
  777. package/dist/workspace/lineage-version.js +128 -0
  778. package/dist/workspace/lineage-versions.js +275 -0
  779. package/dist/workspace/links.js +330 -0
  780. package/dist/workspace/ls-generated.js +95 -0
  781. package/dist/workspace/ls.js +277 -0
  782. package/dist/workspace/ls.schema.json +333 -0
  783. package/dist/workspace/member-commands.js +508 -0
  784. package/dist/workspace/member-handles.js +216 -0
  785. package/dist/workspace/member-pipeline.js +258 -0
  786. package/dist/workspace/member-run.js +117 -0
  787. package/dist/workspace/member-write.schema.json +193 -0
  788. package/dist/workspace/nested-graph.js +156 -0
  789. package/dist/workspace/nesting.js +38 -0
  790. package/dist/workspace/patch.js +301 -0
  791. package/dist/workspace/patch.schema.json +321 -0
  792. package/dist/workspace/pin-cli.js +55 -0
  793. package/dist/workspace/pin-integrity.js +100 -0
  794. package/dist/workspace/plan-summary.schema.json +155 -0
  795. package/dist/workspace/point-answer.schema.json +129 -129
  796. package/dist/workspace/points-cli.js +291 -0
  797. package/dist/workspace/points-write.schema.json +660 -0
  798. package/dist/workspace/points.js +521 -0
  799. package/dist/workspace/points.schema.json +916 -0
  800. package/dist/workspace/pr-report.schema.json +108 -0
  801. package/dist/workspace/principal-classes.js +245 -0
  802. package/dist/workspace/reason-codes.js +326 -0
  803. package/dist/workspace/record-assets.js +151 -0
  804. package/dist/workspace/record-decided.js +105 -0
  805. package/dist/workspace/record-sessions.js +96 -0
  806. package/dist/workspace/record-source.js +114 -0
  807. package/dist/workspace/records-amend.schema.json +284 -0
  808. package/dist/workspace/records-checkout.js +76 -0
  809. package/dist/workspace/records-cli.js +707 -0
  810. package/dist/workspace/records-close.js +116 -0
  811. package/dist/workspace/records-close.schema.json +278 -0
  812. package/dist/workspace/records-new.schema.json +202 -0
  813. package/dist/workspace/records-review.schema.json +367 -0
  814. package/dist/workspace/records-since.js +317 -0
  815. package/dist/workspace/records-since.schema.json +218 -0
  816. package/dist/workspace/records-write.js +1229 -0
  817. package/dist/workspace/records.js +1345 -0
  818. package/dist/workspace/records.schema.json +604 -0
  819. package/dist/workspace/reference-kinds/app/package.json +10 -0
  820. package/dist/workspace/reference-kinds/app/workspace-kinds.json +45 -0
  821. package/dist/workspace/returns.js +303 -0
  822. package/dist/workspace/root-refusal.js +75 -0
  823. package/dist/workspace/run-statement.schema.json +622 -0
  824. package/dist/workspace/runs-cli.js +584 -0
  825. package/dist/workspace/runs-write.schema.json +994 -0
  826. package/dist/workspace/runs.js +708 -0
  827. package/dist/workspace/runs.schema.json +1257 -0
  828. package/dist/workspace/runtimes.js +76 -0
  829. package/dist/workspace/session-kinds.js +83 -0
  830. package/dist/workspace/signers.schema.json +206 -0
  831. package/dist/workspace/source-block.js +125 -0
  832. package/dist/workspace/squash.js +177 -0
  833. package/dist/workspace/status-gates.js +162 -0
  834. package/dist/workspace/status-stewards.js +330 -0
  835. package/dist/workspace/status.js +514 -0
  836. package/dist/workspace/status.schema.json +998 -0
  837. package/dist/workspace/steward-index.js +191 -0
  838. package/dist/workspace/symbols.js +188 -0
  839. package/dist/workspace/template-manifest.js +227 -0
  840. package/dist/workspace/template-pins.js +115 -0
  841. package/dist/workspace/trailer-joins.js +65 -0
  842. package/dist/workspace/trailers.js +111 -0
  843. package/dist/workspace/tree.js +136 -0
  844. package/dist/workspace/trust/attestor.js +63 -0
  845. package/dist/workspace/trust/dsse.js +108 -0
  846. package/dist/workspace/trust/evidence-cli.js +175 -0
  847. package/dist/workspace/trust/evidence.js +161 -0
  848. package/dist/workspace/trust/gate-seal.js +226 -0
  849. package/dist/workspace/trust/policy.js +190 -0
  850. package/dist/workspace/trust/provenance.js +180 -0
  851. package/dist/workspace/trust/rotation.js +298 -0
  852. package/dist/workspace/trust/run-commits.js +101 -0
  853. package/dist/workspace/trust/run-statement.js +182 -0
  854. package/dist/workspace/trust/seal.js +272 -0
  855. package/dist/workspace/trust/signers-cli.js +152 -0
  856. package/dist/workspace/trust/ssh-commit.js +178 -0
  857. package/dist/workspace/trust/test-repo.js +118 -0
  858. package/dist/workspace/trust/trust-files.js +193 -0
  859. package/dist/workspace/trust/verify-cli.js +63 -0
  860. package/dist/workspace/trust/verify.js +192 -0
  861. package/dist/workspace/which-chant.js +141 -0
  862. package/dist/workspace/wip-cli.js +95 -0
  863. package/dist/workspace/wip-write.schema.json +504 -0
  864. package/dist/workspace/wip.js +631 -0
  865. package/dist/workspace/wip.schema.json +334 -0
  866. package/dist/workspace/work-cli.js +448 -0
  867. package/dist/workspace/work-evidence.js +122 -0
  868. package/dist/workspace/work-evidence.schema.json +222 -0
  869. package/dist/workspace/work-history.schema.json +421 -0
  870. package/dist/workspace/work-lease.schema.json +246 -0
  871. package/dist/workspace/work-size.js +77 -0
  872. package/dist/workspace/work.js +283 -0
  873. package/dist/workspace/workspace-kinds.schema.json +259 -259
  874. package/dist/workspace/workspace-principals.schema.json +53 -53
  875. package/dist/workspace/write-lock-cli.js +105 -0
  876. package/dist/workspace/write-lock.js +424 -0
  877. package/dist/workspace/write-lock.schema.json +172 -0
  878. package/dist/workspace/write-scope.js +484 -0
  879. package/dist/yaml.js +459 -0
  880. package/package.json +2 -2
  881. package/src/cli/commands/check-lexicon-plugin.ts +2 -0
  882. package/src/cli/commands/lint.ts +3 -0
  883. package/src/cli/commands/migrate.ts +2 -0
  884. package/src/cli/compiled-cli.e2e.test.ts +165 -0
  885. package/src/cli/main.ts +121 -27
  886. package/src/cli/mcp/workspace-tools.ts +1 -1
  887. package/src/codegen/pinned-upgrade.ts +2 -0
  888. package/src/components/discover.ts +2 -0
  889. package/src/components/sandbox/driver.ts +3 -1
  890. package/src/config-import.ts +3 -0
  891. package/src/discovery/fold-import.ts +23 -14
  892. package/src/discovery/import.ts +2 -0
  893. package/src/discovery/sandbox/driver.ts +3 -1
  894. package/src/lexicon-module.ts +3 -0
  895. package/src/lint/config.ts +1 -1
  896. package/src/lint/discover.ts +28 -8
  897. package/src/lint/policy-import.ts +4 -1
  898. package/src/lint/rule-loader.ts +2 -0
  899. package/src/op/discover.ts +3 -0
  900. package/src/ts-loader.test.ts +23 -0
  901. package/src/ts-loader.ts +122 -0
  902. package/src/workspace/chant-migrations/chud-lexicon-exit.ts +1 -1
  903. package/src/workspace/declaration.ts +1 -1
  904. package/src/workspace/kinds.ts +1 -1
  905. package/src/workspace/lineage-migrations.ts +2 -0
  906. package/src/workspace/points.ts +1 -1
  907. package/src/workspace/principal-classes.ts +1 -1
@@ -0,0 +1,152 @@
1
+ /**
2
+ * `chant workspace signers [rotate [--threshold <n>] | sign --key <file>]`
3
+ * (#2553): show the signer history, and propose a new signer set.
4
+ *
5
+ * Rotating is three steps: edit the signers file, run `rotate` to write the
6
+ * rotation file for the next version, and have a threshold of the current
7
+ * signers each run `sign` with their own key. `chant workspace verify` then
8
+ * checks the result against the set at base.
9
+ */
10
+ import { execFileSync } from "node:child_process";
11
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { formatError, formatSuccess } from "../../cli/format.js";
14
+ import { readerVersion } from "../declaration.js";
15
+ import { gitRoot } from "../record-source.js";
16
+ import { parseAllowedSigners, readTrustPolicy } from "./policy.js";
17
+ import { resolveBase } from "./provenance.js";
18
+ import { gitRevisionSource } from "../record-source.js";
19
+ import { distinctHolders, rotationFileSchema, rotationPath, rotationStatement, ROTATION_NAMESPACE, signerHistory, signersDigest, } from "./rotation.js";
20
+ import { verifySshSignature } from "./ssh-commit.js";
21
+ const USAGE = "chant workspace signers [--base <rev>] [--json] | signers rotate [--threshold <n>] | signers sign --key <ssh private key>";
22
+ export const SIGNERS_CONTRACT_VERSION = 1;
23
+ export const SIGNERS_OUTPUT_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/signers/v1/signers.schema.json";
24
+ /** Why `chant workspace signers` prints no history. Each is in `reason-codes.ts` and `signers.schema.json`. */
25
+ export const SIGNERS_ERROR_CODES = ["not-a-git-repository", "revision-unknown", "signers-file-missing"];
26
+ function head() {
27
+ return { $schema: SIGNERS_OUTPUT_SCHEMA_ID, contract: SIGNERS_CONTRACT_VERSION, chant: readerVersion() };
28
+ }
29
+ /** The signer history at `base` as the `--json` document. */
30
+ export function signersDocument(repo, base, signersPath, history) {
31
+ return {
32
+ ...head(),
33
+ base,
34
+ signersPath,
35
+ versions: history.versions.map((v) => ({
36
+ version: v.version,
37
+ commit: v.commit,
38
+ digest: v.version === 0 ? null : v.digest,
39
+ threshold: v.threshold,
40
+ principals: [...new Set(v.signers.map((s) => s.principal))].sort(),
41
+ signedBy: v.signedBy,
42
+ })),
43
+ broken: history.broken ? { commit: history.broken.commit, code: history.broken.code, message: history.broken.reason } : null,
44
+ };
45
+ }
46
+ function fail(message) {
47
+ console.error(formatError({ message, hint: USAGE }));
48
+ return 1;
49
+ }
50
+ export async function runWorkspaceSigners(ctx) {
51
+ const { args } = ctx;
52
+ const sub = args.extraPositional;
53
+ const refuse = (code, message) => {
54
+ if (args.json && !sub)
55
+ console.log(JSON.stringify({ ...head(), error: { code, message } }, null, 2));
56
+ else
57
+ console.error(formatError({ message, hint: USAGE }));
58
+ return 1;
59
+ };
60
+ const repo = gitRoot(process.cwd());
61
+ if (!repo)
62
+ return refuse("not-a-git-repository", "signer history is read from git, and this directory is not in a git repository");
63
+ const base = resolveBase(repo, args.base);
64
+ if (!base.commit)
65
+ return refuse("revision-unknown", base.problem ?? "no base revision");
66
+ // The policy as written at base; its history is checked below, not taken on trust.
67
+ const policy = readTrustPolicy(gitRevisionSource(repo, base.commit), base.commit);
68
+ if (!policy.active)
69
+ return refuse("signers-file-missing", `there is no signers file (${policy.signersPath}) at base ${base.commit.slice(0, 8)}`);
70
+ const history = signerHistory(repo, base.commit, policy.signersPath);
71
+ const latest = history.versions.at(-1);
72
+ if (!sub) {
73
+ if (args.json) {
74
+ console.log(JSON.stringify(signersDocument(repo, base.commit, policy.signersPath, history), null, 2));
75
+ return history.broken ? 1 : 0;
76
+ }
77
+ for (const v of history.versions) {
78
+ if (v.version === 0) {
79
+ console.log(` ${v.commit?.slice(0, 8)} signers file removed`);
80
+ continue;
81
+ }
82
+ const by = v.signedBy.length ? `, signed by ${v.signedBy.join(", ")}` : ", the first version";
83
+ console.log(` ${v.commit?.slice(0, 8)} version ${v.version}: ${new Set(v.signers.map((s) => s.principal)).size} signers, threshold ${v.threshold}${by}`);
84
+ }
85
+ if (history.broken)
86
+ return fail(`the history breaks at ${history.broken.commit?.slice(0, 8)} (${history.broken.code}): ${history.broken.reason}`);
87
+ return 0;
88
+ }
89
+ if (history.broken || !latest || latest.version === 0)
90
+ return fail("the signer history at base is not valid, so there is no version to rotate from");
91
+ const signersFile = join(repo, policy.signersPath);
92
+ const rotationFile = join(repo, rotationPath(policy.signersPath));
93
+ const text = readFileSync(signersFile, "utf-8");
94
+ if (sub === "rotate") {
95
+ const threshold = args.threshold !== undefined ? Number(args.threshold) : latest.threshold;
96
+ if (!Number.isInteger(threshold) || threshold < 1)
97
+ return fail("--threshold takes a whole number of at least 1");
98
+ const holders = distinctHolders(parseAllowedSigners(text).signers);
99
+ if (threshold > holders)
100
+ return fail(`--threshold ${threshold} is more than the ${holders} distinct signers in the new set`);
101
+ const rotation = { schema: 1, version: latest.version + 1, previous: latest.digest, threshold, signatures: [] };
102
+ writeFileSync(rotationFile, JSON.stringify(rotation, null, 2) + "\n");
103
+ console.log(formatSuccess(`wrote ${rotationPath(policy.signersPath)} for version ${rotation.version}; ${latest.threshold} of the version ${latest.version} signers must now run chant workspace signers sign --key <their key>`));
104
+ return 0;
105
+ }
106
+ if (sub === "sign") {
107
+ if (!args.key)
108
+ return fail("--key <ssh private key> is required");
109
+ if (!existsSync(rotationFile))
110
+ return fail(`there is no ${rotationPath(policy.signersPath)}; run chant workspace signers rotate first`);
111
+ let raw;
112
+ try {
113
+ raw = JSON.parse(readFileSync(rotationFile, "utf-8"));
114
+ }
115
+ catch {
116
+ return fail(`${rotationPath(policy.signersPath)} is not JSON`);
117
+ }
118
+ const parsed = rotationFileSchema.safeParse(raw);
119
+ if (!parsed.success)
120
+ return fail(`${rotationPath(policy.signersPath)} is invalid`);
121
+ if (parsed.data.version !== latest.version + 1 || parsed.data.previous !== latest.digest) {
122
+ return fail(`${rotationPath(policy.signersPath)} is not the next version after version ${latest.version} at base; run chant workspace signers rotate again`);
123
+ }
124
+ const rotation = parsed.data;
125
+ const statement = rotationStatement(rotation, signersDigest(text));
126
+ let pub;
127
+ try {
128
+ pub = execFileSync("ssh-keygen", ["-y", "-f", args.key], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).trim().split(/\s+/).slice(0, 2).join(" ");
129
+ }
130
+ catch (err) {
131
+ return fail(`ssh-keygen could not read ${args.key}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
132
+ }
133
+ const me = latest.signers.find((s) => s.key === pub);
134
+ if (!me)
135
+ return fail(`this key is not in version ${latest.version} of the signer set, so its signature would not count`);
136
+ let sig;
137
+ try {
138
+ sig = execFileSync("ssh-keygen", ["-q", "-Y", "sign", "-n", ROTATION_NAMESPACE, "-f", args.key], { input: statement, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
139
+ }
140
+ catch (err) {
141
+ return fail(`ssh-keygen could not sign with ${args.key}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
142
+ }
143
+ const check = verifySshSignature([me], statement, sig, ROTATION_NAMESPACE);
144
+ if (!check.ok)
145
+ return fail(`the signature did not verify: ${check.reason}`);
146
+ rotation.signatures = [...rotation.signatures.filter((s) => s.principal !== me.principal), { principal: me.principal, signature: sig }];
147
+ writeFileSync(rotationFile, JSON.stringify(rotation, null, 2) + "\n");
148
+ console.log(formatSuccess(`signed version ${rotation.version} as ${me.principal} (${rotation.signatures.length} of ${latest.threshold} needed)`));
149
+ return 0;
150
+ }
151
+ return fail(`Unknown signers subcommand: ${sub}`);
152
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * The first attestor: ssh-signed commits, checked against the signers the
3
+ * base policy lists (#2524 D5, ws-001).
4
+ *
5
+ * It does not ask `git verify-commit`. That would read `gpg.ssh.program`,
6
+ * `gpg.ssh.allowedSignersFile` and the rest from git config, which whoever
7
+ * controls the machine can set, and it passes the commit's own date to
8
+ * ssh-keygen as the verification time. Instead it takes the signature and the
9
+ * signed payload out of the commit object itself and hands them to
10
+ * `ssh-keygen -Y verify` with a signers file built from the base policy, in
11
+ * the `git` namespace.
12
+ */
13
+ import { execFileSync, spawnSync } from "node:child_process";
14
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
15
+ import { tmpdir } from "node:os";
16
+ import { join } from "node:path";
17
+ import { renderAllowedSigners } from "./policy.js";
18
+ const NAME = "ssh-commit";
19
+ /**
20
+ * Split a raw commit object. `header` is `gpgsig` in a SHA-1 repository and
21
+ * `gpgsig-sha256` in a SHA-256 one; git removes exactly that header, with its
22
+ * continuation lines, to get the bytes it signed.
23
+ */
24
+ export function splitSignedCommit(raw, header = "gpgsig") {
25
+ const end = raw.indexOf("\n\n");
26
+ const headEnd = end < 0 ? raw.length : end;
27
+ const head = raw.subarray(0, headEnd).toString("latin1").split("\n");
28
+ const kept = [];
29
+ const sig = [];
30
+ let inSig = false;
31
+ for (const line of head) {
32
+ if (inSig && line.startsWith(" ")) {
33
+ sig.push(line.slice(1));
34
+ continue;
35
+ }
36
+ inSig = false;
37
+ if (sig.length === 0 && line.startsWith(`${header} `)) {
38
+ inSig = true;
39
+ sig.push(line.slice(header.length + 1));
40
+ continue;
41
+ }
42
+ kept.push(line);
43
+ }
44
+ const payload = Buffer.concat([Buffer.from(kept.join("\n"), "latin1"), raw.subarray(headEnd)]);
45
+ return { payload, signature: sig.length > 0 ? sig.join("\n") + "\n" : undefined };
46
+ }
47
+ function objectFormat(repo) {
48
+ try {
49
+ return execFileSync("git", ["rev-parse", "--show-object-format"], { cwd: repo, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim();
50
+ }
51
+ catch {
52
+ return "sha1";
53
+ }
54
+ }
55
+ /** Run ssh-keygen; `missing` is true when it is not installed. Shared with the verdict seals (./seal.ts). */
56
+ export function sshKeygen(args, input) {
57
+ const r = spawnSync("ssh-keygen", args, { input, encoding: "buffer", timeout: 30000 });
58
+ const missing = r.error?.code === "ENOENT";
59
+ return { status: r.status, stdout: r.stdout?.toString("utf-8") ?? "", stderr: r.stderr?.toString("utf-8") ?? "", missing };
60
+ }
61
+ const cache = new Map();
62
+ /**
63
+ * Check a detached ssh signature over `payload` in `namespace` against
64
+ * `signers`. Shared with the rotation check (#2553), which signs signer sets
65
+ * in their own namespace so a commit signature can never stand in for one.
66
+ */
67
+ export function verifySshSignature(signers, payload, signature, namespace) {
68
+ if (signers.length === 0)
69
+ return { ok: false, missing: false, reason: "the policy lists no usable signer" };
70
+ const dir = mkdtempSync(join(tmpdir(), "chant-trust-"));
71
+ try {
72
+ const allowed = join(dir, "allowed_signers");
73
+ const sigFile = join(dir, "signature");
74
+ writeFileSync(allowed, renderAllowedSigners(signers));
75
+ writeFileSync(sigFile, signature);
76
+ const found = sshKeygen(["-Y", "find-principals", "-f", allowed, "-s", sigFile]);
77
+ if (found.missing)
78
+ return { ok: false, missing: true, reason: "ssh-keygen is not installed here" };
79
+ const principals = found.status === 0 ? found.stdout.split("\n").map((l) => l.trim()).filter(Boolean) : [];
80
+ if (principals.length === 0)
81
+ return { ok: false, missing: false, reason: "signed by a key the policy at base does not list" };
82
+ for (const principal of principals) {
83
+ const v = sshKeygen(["-Y", "verify", "-f", allowed, "-I", principal, "-n", namespace, "-s", sigFile], payload);
84
+ if (v.status === 0) {
85
+ const key = /key (SHA256:[A-Za-z0-9+/=]+)/.exec(v.stdout + v.stderr)?.[1];
86
+ return { ok: true, principal, ...(key ? { key } : {}) };
87
+ }
88
+ }
89
+ return { ok: false, missing: false, reason: `the signature does not verify in the ${namespace} namespace for a key the policy lists` };
90
+ }
91
+ finally {
92
+ rmSync(dir, { recursive: true, force: true });
93
+ }
94
+ }
95
+ export const sshCommitAttestor = {
96
+ name: NAME,
97
+ attestCommit(ctx, commit) {
98
+ const signers = ctx.policy.signers;
99
+ const memo = `${ctx.repo}\0${commit}\0${renderAllowedSigners(signers)}`;
100
+ const hit = cache.get(memo);
101
+ if (hit)
102
+ return hit;
103
+ const raw = execFileSync("git", ["cat-file", "commit", commit], { cwd: ctx.repo, maxBuffer: 64 * 1024 * 1024 });
104
+ const answer = judgeRaw(raw, objectFormat(ctx.repo) === "sha256" ? "gpgsig-sha256" : "gpgsig", signers);
105
+ cache.set(memo, answer);
106
+ return answer;
107
+ },
108
+ attestRaw(ctx, raw) {
109
+ // A commit from another repository: its object format shows in its tree line.
110
+ const tree = /^tree ([0-9a-f]+)$/m.exec(raw.subarray(0, 200).toString("latin1"))?.[1];
111
+ return judgeRaw(raw, tree?.length === 64 ? "gpgsig-sha256" : "gpgsig", ctx.policy.signers);
112
+ },
113
+ };
114
+ function judgeRaw(raw, header, signers) {
115
+ const { payload, signature } = splitSignedCommit(raw, header);
116
+ if (!signature)
117
+ return { level: "unattested", attestor: NAME, reason: "the commit is not signed" };
118
+ if (!signature.startsWith("-----BEGIN SSH SIGNATURE-----")) {
119
+ const format = signature.startsWith("-----BEGIN PGP SIGNATURE-----") ? "an OpenPGP" : "a non-ssh";
120
+ return { level: "attested-unverifiable-here", attestor: NAME, reason: `the commit carries ${format} signature, which this attestor does not check` };
121
+ }
122
+ const r = verifySshSignature(signers, payload, signature, "git");
123
+ if (r.ok)
124
+ return { level: "attested", attestor: NAME, principal: r.principal, ...(r.key ? { key: r.key } : {}), reason: `signed by ${r.principal}` };
125
+ if (r.missing)
126
+ return { level: "attested-unverifiable-here", attestor: NAME, reason: r.reason };
127
+ return { level: "unattested", attestor: NAME, reason: r.reason };
128
+ }
129
+ /**
130
+ * The public key inside an armored ssh signature (the SSHSIG format), as
131
+ * `<type> <base64>`, or undefined when the text is not one. The key is what
132
+ * made the signature; whether anyone trusts it is a separate question.
133
+ */
134
+ export function sshSignatureKey(signature) {
135
+ const body = signature
136
+ .replace(/-----BEGIN SSH SIGNATURE-----/, "")
137
+ .replace(/-----END SSH SIGNATURE-----/, "")
138
+ .replace(/\s+/g, "");
139
+ let buf;
140
+ try {
141
+ buf = Buffer.from(body, "base64");
142
+ }
143
+ catch {
144
+ return undefined;
145
+ }
146
+ if (buf.length < 14 || buf.subarray(0, 6).toString("latin1") !== "SSHSIG")
147
+ return undefined;
148
+ const len = buf.readUInt32BE(10);
149
+ const blob = buf.subarray(14, 14 + len);
150
+ if (blob.length !== len || len < 4)
151
+ return undefined;
152
+ const typeLen = blob.readUInt32BE(0);
153
+ const type = blob.subarray(4, 4 + typeLen).toString("latin1");
154
+ if (!/^[a-z0-9@.-]+$/.test(type))
155
+ return undefined;
156
+ return `${type} ${blob.toString("base64")}`;
157
+ }
158
+ /**
159
+ * Whether an ssh signature over `payload` in `namespace` is intact, whoever
160
+ * made it (`ssh-keygen -Y check-novalidate`). Returns the key's fingerprint,
161
+ * false when it does not check, or null when ssh-keygen is not installed.
162
+ */
163
+ export function sshSignatureIntact(payload, signature, namespace) {
164
+ const dir = mkdtempSync(join(tmpdir(), "chant-intact-"));
165
+ try {
166
+ const sigFile = join(dir, "signature");
167
+ writeFileSync(sigFile, signature);
168
+ const r = sshKeygen(["-Y", "check-novalidate", "-n", namespace, "-s", sigFile], payload);
169
+ if (r.missing)
170
+ return null;
171
+ if (r.status !== 0)
172
+ return false;
173
+ return /key (SHA256:[A-Za-z0-9+/=]+)/.exec(r.stdout + r.stderr)?.[1] ?? "";
174
+ }
175
+ finally {
176
+ rmSync(dir, { recursive: true, force: true });
177
+ }
178
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Test support for the trust modules: throwaway git repositories whose commits
3
+ * are signed with throwaway ssh keys. Isolated from the user's git config, so a
4
+ * developer's own signing setup never leaks into a test.
5
+ */
6
+ import { execFileSync, spawnSync } from "node:child_process";
7
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { dirname, join } from "node:path";
10
+ import { ROTATION_NAMESPACE, rotationStatement, signersDigest } from "./rotation.js";
11
+ export const hasSshKeygen = spawnSync("ssh-keygen", ["-Y"], { stdio: "ignore" }).error === undefined;
12
+ export class TestRepo {
13
+ constructor(label) {
14
+ this.scratch = mkdtempSync(join(tmpdir(), `chant-2547-${label}-`));
15
+ this.dir = join(this.scratch, "repo");
16
+ this.home = join(this.scratch, "home");
17
+ mkdirSync(this.dir);
18
+ mkdirSync(this.home);
19
+ this.git(["init", "-q", "-b", "main"]);
20
+ }
21
+ env(extra = {}) {
22
+ return {
23
+ PATH: process.env.PATH ?? "",
24
+ HOME: this.home,
25
+ GIT_CONFIG_GLOBAL: join(this.home, "gitconfig"),
26
+ GIT_CONFIG_NOSYSTEM: "1",
27
+ GIT_AUTHOR_NAME: "t",
28
+ GIT_AUTHOR_EMAIL: "t@example.test",
29
+ GIT_COMMITTER_NAME: "t",
30
+ GIT_COMMITTER_EMAIL: "t@example.test",
31
+ ...extra,
32
+ };
33
+ }
34
+ git(args, opts = {}) {
35
+ return execFileSync("git", args, { cwd: this.dir, env: this.env(opts.env), input: opts.input, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
36
+ }
37
+ key(name) {
38
+ const file = join(this.scratch, `key-${name}`);
39
+ execFileSync("ssh-keygen", ["-q", "-t", "ed25519", "-N", "", "-C", name, "-f", file]);
40
+ const pub = readFileSync(`${file}.pub`, "utf-8").trim().split(" ").slice(0, 2).join(" ");
41
+ return { name, file, pub };
42
+ }
43
+ write(path, text) {
44
+ mkdirSync(dirname(join(this.dir, path)), { recursive: true });
45
+ writeFileSync(join(this.dir, path), text);
46
+ }
47
+ /** Stage everything and commit, signed with `key` when given. Returns the commit id. */
48
+ commit(message, key, env = {}) {
49
+ this.git(["add", "-A"]);
50
+ const sign = key ? ["-c", "gpg.format=ssh", "-c", `user.signingkey=${key.file}`, "commit", "-S"] : ["commit", "--no-gpg-sign"];
51
+ this.git([...sign, "-q", "--allow-empty", "-m", message], { env });
52
+ return this.head();
53
+ }
54
+ head() {
55
+ return this.git(["rev-parse", "HEAD"]).trim();
56
+ }
57
+ /**
58
+ * Write a commit object by hand: the current index's tree, `HEAD` as parent,
59
+ * and `signature` spliced in as the gpgsig header. Returns the new commit,
60
+ * which HEAD then points at.
61
+ */
62
+ forgeCommit(message, sign) {
63
+ this.git(["add", "-A"]);
64
+ const tree = this.git(["write-tree"]).trim();
65
+ const parent = this.head();
66
+ const payload = Buffer.from(`tree ${tree}\nparent ${parent}\nauthor t <t@example.test> 1700000000 +0000\ncommitter t <t@example.test> 1700000000 +0000\n\n${message}\n`);
67
+ const sig = sign(payload).trimEnd().split("\n");
68
+ const head = payload.toString("latin1").split("\n\n")[0];
69
+ const body = payload.toString("latin1").slice(head.length);
70
+ const raw = `${head}\ngpgsig ${sig[0]}\n${sig.slice(1).map((l) => ` ${l}`).join("\n")}${body}`;
71
+ const commit = this.git(["hash-object", "-t", "commit", "-w", "--stdin"], { input: Buffer.from(raw, "latin1") }).trim();
72
+ this.git(["update-ref", "HEAD", commit]);
73
+ return commit;
74
+ }
75
+ /** An ssh signature over `payload` in `namespace`, by `key`. */
76
+ sshSign(key, payload, namespace) {
77
+ const f = join(this.scratch, `payload-${Math.random().toString(36).slice(2)}`);
78
+ writeFileSync(f, payload);
79
+ execFileSync("ssh-keygen", ["-q", "-Y", "sign", "-n", namespace, "-f", key.file, f], { stdio: "ignore" });
80
+ return readFileSync(`${f}.sig`, "utf-8");
81
+ }
82
+ cleanup() {
83
+ rmSync(this.scratch, { recursive: true, force: true });
84
+ }
85
+ }
86
+ /**
87
+ * Write `<signers>.rotation.json` for the signers file now in the working
88
+ * tree, as the next version after `previousText`, signed by `by` in the
89
+ * rotation namespace (#2553).
90
+ */
91
+ export function writeRotation(repo, opts) {
92
+ const path = opts.signersPath ?? ".chant/allowed_signers";
93
+ const text = readFileSync(join(repo.dir, path), "utf-8");
94
+ const rotation = { version: opts.version, previous: signersDigest(opts.previousText), threshold: opts.threshold ?? 1 };
95
+ const statement = rotationStatement(rotation, signersDigest(text));
96
+ const signatures = opts.by.map(([principal, key]) => ({ principal, signature: repo.sshSign(key, statement, opts.namespace ?? ROTATION_NAMESPACE) }));
97
+ repo.write(`${path}.rotation.json`, JSON.stringify({ schema: 1, ...rotation, signatures }, null, 2));
98
+ }
99
+ /** A record kind reading `records/*.md`, and its schema, written into `repo`. */
100
+ export function writeRecordKind(repo) {
101
+ repo.write("kinds/note.kind.mjs", `export const recordKind = {
102
+ name: "note",
103
+ location: { dir: "../records", match: "\\\\.md$" },
104
+ format: "markdown-front-matter",
105
+ schema: { id: "urn:test:note:1", path: "note.schema.json" },
106
+ idField: "id",
107
+ stateField: "state",
108
+ states: ["open", "closed"],
109
+ closedStates: ["closed"],
110
+ supersedes: { field: "supersedes", key: "note" },
111
+ };
112
+ `);
113
+ repo.write("kinds/note.schema.json", JSON.stringify({ $id: "urn:test:note:1", type: "object", required: ["id", "state"], properties: { id: { type: "string" }, state: { type: "string" } } }));
114
+ return "kinds/note.kind.mjs";
115
+ }
116
+ export function note(id, body = "") {
117
+ return `---\nid: ${id}\nstate: open\n---\n${body}\n`;
118
+ }
@@ -0,0 +1,193 @@
1
+ /**
2
+ * The trust files' plain readers (#3763): the signers file's parser, and a
3
+ * check of `.chant/trust.json` that says what `./policy.ts`'s zod schema
4
+ * says, so a bundle can read both without zod. `./policy.ts` re-exports the
5
+ * parser; `trust-files.test.ts` holds the check to the schema.
6
+ */
7
+ import { posix } from "node:path";
8
+ /** The trust config, relative to the repository root. Fixed: it is how the signers path is overridden. */
9
+ export const TRUST_CONFIG_PATH = ".chant/trust.json";
10
+ /** Where the signers are when `trust.json` names no other path. */
11
+ export const DEFAULT_SIGNERS_PATH = ".chant/allowed_signers";
12
+ // ── allowed_signers ──────────────────────────────────────────────────────────
13
+ /** Key types ssh-keygen accepts in an allowed_signers line. */
14
+ const KEY_TYPES = new Set([
15
+ "ssh-ed25519",
16
+ "ssh-rsa",
17
+ "ecdsa-sha2-nistp256",
18
+ "ecdsa-sha2-nistp384",
19
+ "ecdsa-sha2-nistp521",
20
+ "sk-ssh-ed25519@openssh.com",
21
+ "sk-ecdsa-sha2-nistp256@openssh.com",
22
+ ]);
23
+ /**
24
+ * Split one line into fields. Double quotes group, so an option such as
25
+ * `namespaces="git,file"` stays one field.
26
+ */
27
+ function fields(line) {
28
+ const out = [];
29
+ let cur = "";
30
+ let quoted = false;
31
+ let any = false;
32
+ for (const ch of line) {
33
+ if (ch === '"') {
34
+ quoted = !quoted;
35
+ cur += ch;
36
+ any = true;
37
+ }
38
+ else if (!quoted && (ch === " " || ch === "\t")) {
39
+ if (any)
40
+ out.push(cur);
41
+ cur = "";
42
+ any = false;
43
+ }
44
+ else {
45
+ cur += ch;
46
+ any = true;
47
+ }
48
+ }
49
+ if (any)
50
+ out.push(cur);
51
+ return out;
52
+ }
53
+ /** `a="x,y",b` as `{ a: "x,y", b: "" }`. */
54
+ function options(field) {
55
+ const opts = new Map();
56
+ let cur = "";
57
+ let quoted = false;
58
+ const flush = () => {
59
+ if (!cur)
60
+ return;
61
+ const eq = cur.indexOf("=");
62
+ const name = (eq < 0 ? cur : cur.slice(0, eq)).toLowerCase();
63
+ const value = eq < 0 ? "" : cur.slice(eq + 1).replace(/^"|"$/g, "");
64
+ opts.set(name, value);
65
+ cur = "";
66
+ };
67
+ for (const ch of field) {
68
+ if (ch === '"')
69
+ quoted = !quoted;
70
+ if (ch === "," && !quoted)
71
+ flush();
72
+ else
73
+ cur += ch;
74
+ }
75
+ flush();
76
+ return opts;
77
+ }
78
+ /**
79
+ * Parse an allowed_signers file, keeping only lines whose meaning does not
80
+ * depend on anything the signer controls.
81
+ *
82
+ * Refused, each with a reason, rather than passed to ssh-keygen:
83
+ *
84
+ * - `valid-after` and `valid-before`. git checks them against the commit's own
85
+ * date, which whoever makes the commit sets. A backdated commit would pass a
86
+ * window its key has left. Revocation is by position in history (#2553),
87
+ * never by date.
88
+ * - `cert-authority`. A certificate's validity is also a date, and a CA key
89
+ * vouches for keys this file never names.
90
+ * - Principal patterns (`*`, `?`, `!`). A signer is named by one exact
91
+ * principal, so role grants can name it.
92
+ */
93
+ export function parseAllowedSigners(text) {
94
+ const signers = [];
95
+ const excluded = [];
96
+ const lines = text.replace(/\r\n?/g, "\n").split("\n");
97
+ for (let i = 0; i < lines.length; i++) {
98
+ const line = i + 1;
99
+ const raw = lines[i].trim();
100
+ if (!raw || raw.startsWith("#"))
101
+ continue;
102
+ const f = fields(raw);
103
+ if (f.length < 3) {
104
+ excluded.push({ line, reason: "expected principals, optional options, a key type and a key" });
105
+ continue;
106
+ }
107
+ const [principals, second] = f;
108
+ const hasOptions = !KEY_TYPES.has(second);
109
+ const type = hasOptions ? f[2] : second;
110
+ const blob = hasOptions ? f[3] : f[2];
111
+ if (!KEY_TYPES.has(type) || !blob || !/^[A-Za-z0-9+/]+={0,2}$/.test(blob)) {
112
+ excluded.push({ line, reason: `no supported public key (${type ?? "none"})` });
113
+ continue;
114
+ }
115
+ const opts = hasOptions ? options(second) : new Map();
116
+ const timed = ["valid-after", "valid-before"].filter((o) => opts.has(o));
117
+ if (timed.length > 0) {
118
+ excluded.push({
119
+ line,
120
+ reason: `${timed.join(" and ")} is checked against the commit's own date, which its author sets; revoke a key by removing it`,
121
+ });
122
+ continue;
123
+ }
124
+ if (opts.has("cert-authority")) {
125
+ excluded.push({ line, reason: "cert-authority keys are not supported: a certificate's validity is a date the signer controls" });
126
+ continue;
127
+ }
128
+ const unknown = [...opts.keys()].filter((o) => o !== "namespaces");
129
+ if (unknown.length > 0) {
130
+ excluded.push({ line, reason: `unknown option ${unknown.join(", ")}` });
131
+ continue;
132
+ }
133
+ const names = principals.replace(/^"|"$/g, "").split(",").filter(Boolean);
134
+ const pattern = names.find((p) => /[*?!]/.test(p));
135
+ if (pattern !== undefined || names.length === 0) {
136
+ excluded.push({ line, reason: `principal ${JSON.stringify(pattern ?? principals)} is a pattern; name one signer exactly` });
137
+ continue;
138
+ }
139
+ for (const principal of names) {
140
+ signers.push({ principal, key: `${type} ${blob}`, namespaces: opts.get("namespaces"), line });
141
+ }
142
+ }
143
+ return { signers, excluded };
144
+ }
145
+ /** The signers as an allowed_signers file ssh-keygen reads, holding only the usable lines. */
146
+ export function renderAllowedSigners(signers) {
147
+ return (signers
148
+ .map((s) => `${JSON.stringify(s.principal)}${s.namespaces !== undefined ? ` namespaces=${JSON.stringify(s.namespaces)}` : ""} ${s.key}`)
149
+ .join("\n") + "\n");
150
+ }
151
+ // ── trust.json, without zod ──────────────────────────────────────────────────
152
+ const isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
153
+ const FULL_COMMIT = /^[0-9a-f]{40}([0-9a-f]{24})?$/;
154
+ const SSH_ED25519 = /^ssh-ed25519 [A-Za-z0-9+/]+={0,2}$/;
155
+ const SSH_KEY = /^(ssh-ed25519|ssh-rsa|ecdsa-sha2-nistp(256|384|521)|sk-ssh-ed25519@openssh\.com|sk-ecdsa-sha2-nistp256@openssh\.com) [A-Za-z0-9+/]+={0,2}$/;
156
+ /** A repository-relative path: no `..`, not absolute, `/` separators. */
157
+ export function isRepoPath(p) {
158
+ return typeof p === "string" && p.length > 0 && !p.startsWith("/") && !p.includes("\\") && posix.normalize(p) === p && !p.split("/").includes("..");
159
+ }
160
+ /** Whether `o` holds only `keys`, as zod's `.strict()` requires. */
161
+ const only = (o, keys) => Object.keys(o).every((k) => keys.includes(k));
162
+ const optional = (v, ok) => v === undefined || ok(v);
163
+ const nonEmpty = (v) => typeof v === "string" && v.length > 0;
164
+ /**
165
+ * What is wrong with a parsed `.chant/trust.json`, one line per field, or an
166
+ * empty list when it is valid. It accepts exactly what `trustConfigSchema`
167
+ * in `./policy.ts` accepts, so a reader without zod treats a file as chant
168
+ * does: an invalid one turns attestation off.
169
+ */
170
+ export function trustConfigProblems(raw) {
171
+ if (!isObject(raw))
172
+ return ["/: expected an object"];
173
+ const problems = [];
174
+ const check = (field, ok, message) => {
175
+ if (!ok)
176
+ problems.push(`${field}: ${message}`);
177
+ };
178
+ check("/", only(raw, ["schema", "signers", "roles", "adopted", "runners", "admitted"]), "unknown key");
179
+ check("schema", raw.schema === 1, "expected 1");
180
+ check("signers", optional(raw.signers, isRepoPath), "a path inside the repository, with / separators and no ..");
181
+ check("roles", optional(raw.roles, (r) => isObject(r) && Object.entries(r).every(([k, v]) => /^[a-z][a-z0-9-]*$/.test(k) && Array.isArray(v) && v.every(nonEmpty))), "role names to lists of principals");
182
+ check("adopted", optional(raw.adopted, (a) => Array.isArray(a) &&
183
+ a.every((e) => isObject(e) && only(e, ["from", "to", "note"]) && optional(e.from, (f) => typeof f === "string" && FULL_COMMIT.test(f)) && typeof e.to === "string" && FULL_COMMIT.test(e.to) && optional(e.note, (n) => typeof n === "string"))), "commit ranges of full commit ids");
184
+ check("runners", optional(raw.runners, (a) => Array.isArray(a) &&
185
+ a.every((e) => isObject(e) && only(e, ["principal", "class", "key"]) && nonEmpty(e.principal) && (e.class === "runner" || e.class === "service") && typeof e.key === "string" && SSH_ED25519.test(e.key))), "runner keys: a principal, a class and an ssh-ed25519 key");
186
+ check("admitted", optional(raw.admitted, (a) => Array.isArray(a) &&
187
+ a.every((e) => isObject(e) && only(e, ["return", "signers", "note"]) &&
188
+ typeof e.return === "string" && /^ret-[0-9a-f]{12}$/.test(e.return) &&
189
+ optional(e.note, (n) => typeof n === "string") &&
190
+ Array.isArray(e.signers) && e.signers.length > 0 &&
191
+ e.signers.every((s) => isObject(s) && only(s, ["principal", "key"]) && nonEmpty(s.principal) && typeof s.key === "string" && SSH_KEY.test(s.key)))), "admitted signers, by return id");
192
+ return problems;
193
+ }