@intentius/chant 0.13.1 → 0.15.0

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 (450) hide show
  1. package/dist/audit/catalog.d.ts +45 -5
  2. package/dist/audit/catalog.d.ts.map +1 -1
  3. package/dist/audit/proof.d.ts +3 -0
  4. package/dist/audit/proof.d.ts.map +1 -1
  5. package/dist/audit/report-model.d.ts +4 -1
  6. package/dist/audit/report-model.d.ts.map +1 -1
  7. package/dist/audit/report.d.ts +3 -0
  8. package/dist/audit/report.d.ts.map +1 -1
  9. package/dist/audit/rules-doc.d.ts +8 -2
  10. package/dist/audit/rules-doc.d.ts.map +1 -1
  11. package/dist/cli/commands/audit.d.ts.map +1 -1
  12. package/dist/cli/commands/doctor.d.ts.map +1 -1
  13. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts +37 -0
  14. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts.map +1 -0
  15. package/dist/cli/commands/lexicon-surface-diff.d.ts +48 -0
  16. package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -0
  17. package/dist/cli/commands/lint.d.ts.map +1 -1
  18. package/dist/cli/commands/pinned-upgrade.d.ts +41 -0
  19. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -0
  20. package/dist/cli/handlers/build.d.ts.map +1 -1
  21. package/dist/cli/handlers/components.d.ts +39 -0
  22. package/dist/cli/handlers/components.d.ts.map +1 -0
  23. package/dist/cli/handlers/dev.d.ts +3 -0
  24. package/dist/cli/handlers/dev.d.ts.map +1 -1
  25. package/dist/cli/handlers/graph.d.ts +4 -2
  26. package/dist/cli/handlers/graph.d.ts.map +1 -1
  27. package/dist/cli/handlers/misc.d.ts.map +1 -1
  28. package/dist/cli/handlers/run.d.ts +49 -0
  29. package/dist/cli/handlers/run.d.ts.map +1 -1
  30. package/dist/cli/main.d.ts.map +1 -1
  31. package/dist/cli/registry.d.ts +35 -0
  32. package/dist/cli/registry.d.ts.map +1 -1
  33. package/dist/codegen/fetch.d.ts +22 -0
  34. package/dist/codegen/fetch.d.ts.map +1 -1
  35. package/dist/codegen/lexicon-regen.d.ts +110 -0
  36. package/dist/codegen/lexicon-regen.d.ts.map +1 -0
  37. package/dist/codegen/pinned-upgrade.d.ts +153 -0
  38. package/dist/codegen/pinned-upgrade.d.ts.map +1 -0
  39. package/dist/codegen/rolling-upgrade.d.ts +138 -0
  40. package/dist/codegen/rolling-upgrade.d.ts.map +1 -0
  41. package/dist/codegen/surface-snapshot.d.ts +173 -0
  42. package/dist/codegen/surface-snapshot.d.ts.map +1 -0
  43. package/dist/codegen/version-bump.d.ts +21 -0
  44. package/dist/codegen/version-bump.d.ts.map +1 -0
  45. package/dist/components/auto-release.d.ts +93 -0
  46. package/dist/components/auto-release.d.ts.map +1 -0
  47. package/dist/components/builders.d.ts +37 -0
  48. package/dist/components/builders.d.ts.map +1 -0
  49. package/dist/components/capability-plugin-loader.d.ts +111 -0
  50. package/dist/components/capability-plugin-loader.d.ts.map +1 -0
  51. package/dist/components/capability-plugin-schema.d.ts +24 -0
  52. package/dist/components/capability-plugin-schema.d.ts.map +1 -0
  53. package/dist/components/capability-plugin.d.ts +85 -0
  54. package/dist/components/capability-plugin.d.ts.map +1 -0
  55. package/dist/components/capability.d.ts +89 -0
  56. package/dist/components/capability.d.ts.map +1 -0
  57. package/dist/components/cli-support.d.ts +204 -0
  58. package/dist/components/cli-support.d.ts.map +1 -0
  59. package/dist/components/component.d.ts +179 -0
  60. package/dist/components/component.d.ts.map +1 -0
  61. package/dist/components/config-defaults.d.ts +41 -0
  62. package/dist/components/config-defaults.d.ts.map +1 -0
  63. package/dist/components/discover.d.ts +60 -0
  64. package/dist/components/discover.d.ts.map +1 -0
  65. package/dist/components/driver-output.d.ts +20 -0
  66. package/dist/components/driver-output.d.ts.map +1 -0
  67. package/dist/components/driver.d.ts +209 -0
  68. package/dist/components/driver.d.ts.map +1 -0
  69. package/dist/components/index.d.ts +22 -0
  70. package/dist/components/index.d.ts.map +1 -0
  71. package/dist/components/manifest-persistence.d.ts +79 -0
  72. package/dist/components/manifest-persistence.d.ts.map +1 -0
  73. package/dist/components/pilots/alb-ecs.pilot.d.ts +27 -0
  74. package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -0
  75. package/dist/components/pilots/dynamodb.pilot.d.ts +22 -0
  76. package/dist/components/pilots/dynamodb.pilot.d.ts.map +1 -0
  77. package/dist/components/pilots/jar-emr.pilot.d.ts +37 -0
  78. package/dist/components/pilots/jar-emr.pilot.d.ts.map +1 -0
  79. package/dist/components/pilots/lambda.pilot.d.ts +35 -0
  80. package/dist/components/pilots/lambda.pilot.d.ts.map +1 -0
  81. package/dist/components/pilots/neo4j-fanout.pilot.d.ts +17 -0
  82. package/dist/components/pilots/neo4j-fanout.pilot.d.ts.map +1 -0
  83. package/dist/components/pilots/project.d.ts +13 -0
  84. package/dist/components/pilots/project.d.ts.map +1 -0
  85. package/dist/components/presets/ecs-fargate.d.ts +59 -0
  86. package/dist/components/presets/ecs-fargate.d.ts.map +1 -0
  87. package/dist/components/presets/index.d.ts +29 -0
  88. package/dist/components/presets/index.d.ts.map +1 -0
  89. package/dist/components/presets/lambda.d.ts +35 -0
  90. package/dist/components/presets/lambda.d.ts.map +1 -0
  91. package/dist/components/presets/single-host-compose.d.ts +43 -0
  92. package/dist/components/presets/single-host-compose.d.ts.map +1 -0
  93. package/dist/components/registry.d.ts +29 -0
  94. package/dist/components/registry.d.ts.map +1 -0
  95. package/dist/components/starter-plugin.d.ts +51 -0
  96. package/dist/components/starter-plugin.d.ts.map +1 -0
  97. package/dist/components/temporal-codegen-loader.d.ts +27 -0
  98. package/dist/components/temporal-codegen-loader.d.ts.map +1 -0
  99. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts +35 -0
  100. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts.map +1 -0
  101. package/dist/components/verbs/__tests__/mock-process-runner.d.ts +45 -0
  102. package/dist/components/verbs/__tests__/mock-process-runner.d.ts.map +1 -0
  103. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts +33 -0
  104. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts.map +1 -0
  105. package/dist/components/verbs/bom-writer.d.ts +155 -0
  106. package/dist/components/verbs/bom-writer.d.ts.map +1 -0
  107. package/dist/components/verbs/build-archive.d.ts +205 -0
  108. package/dist/components/verbs/build-archive.d.ts.map +1 -0
  109. package/dist/components/verbs/build.d.ts +150 -0
  110. package/dist/components/verbs/build.d.ts.map +1 -0
  111. package/dist/components/verbs/cloud-executor.d.ts +88 -0
  112. package/dist/components/verbs/cloud-executor.d.ts.map +1 -0
  113. package/dist/components/verbs/component-bom.d.ts +103 -0
  114. package/dist/components/verbs/component-bom.d.ts.map +1 -0
  115. package/dist/components/verbs/index.d.ts +49 -0
  116. package/dist/components/verbs/index.d.ts.map +1 -0
  117. package/dist/components/verbs/license-policy.d.ts +56 -0
  118. package/dist/components/verbs/license-policy.d.ts.map +1 -0
  119. package/dist/components/verbs/lockfile-sbom-generator.d.ts +81 -0
  120. package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -0
  121. package/dist/components/verbs/process-runner.d.ts +64 -0
  122. package/dist/components/verbs/process-runner.d.ts.map +1 -0
  123. package/dist/components/verbs/reproducibility.d.ts +80 -0
  124. package/dist/components/verbs/reproducibility.d.ts.map +1 -0
  125. package/dist/components/verbs/sbom-generator.d.ts +157 -0
  126. package/dist/components/verbs/sbom-generator.d.ts.map +1 -0
  127. package/dist/components/verbs/sbom.d.ts +79 -0
  128. package/dist/components/verbs/sbom.d.ts.map +1 -0
  129. package/dist/components/verbs/shell.d.ts +35 -0
  130. package/dist/components/verbs/shell.d.ts.map +1 -0
  131. package/dist/components/verbs/sign.d.ts +222 -0
  132. package/dist/components/verbs/sign.d.ts.map +1 -0
  133. package/dist/components/verbs/stub.d.ts +18 -0
  134. package/dist/components/verbs/stub.d.ts.map +1 -0
  135. package/dist/components/verbs/tool-sbom-generator.d.ts +51 -0
  136. package/dist/components/verbs/tool-sbom-generator.d.ts.map +1 -0
  137. package/dist/components/verbs/verify.d.ts +106 -0
  138. package/dist/components/verbs/verify.d.ts.map +1 -0
  139. package/dist/components/verbs/vex.d.ts +65 -0
  140. package/dist/components/verbs/vex.d.ts.map +1 -0
  141. package/dist/components/verbs/vuln-gate.d.ts +91 -0
  142. package/dist/components/verbs/vuln-gate.d.ts.map +1 -0
  143. package/dist/components/verbs/vuln-scan.d.ts +116 -0
  144. package/dist/components/verbs/vuln-scan.d.ts.map +1 -0
  145. package/dist/components/verbs/wait-verify.d.ts +85 -0
  146. package/dist/components/verbs/wait-verify.d.ts.map +1 -0
  147. package/dist/config.d.ts +205 -0
  148. package/dist/config.d.ts.map +1 -1
  149. package/dist/index.d.ts +4 -0
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/lexicon.d.ts +78 -0
  152. package/dist/lexicon.d.ts.map +1 -1
  153. package/dist/lifecycle/build-ledger-store.d.ts +121 -0
  154. package/dist/lifecycle/build-ledger-store.d.ts.map +1 -0
  155. package/dist/lifecycle/build-ledger.d.ts +225 -0
  156. package/dist/lifecycle/build-ledger.d.ts.map +1 -0
  157. package/dist/lifecycle/git.d.ts +84 -0
  158. package/dist/lifecycle/git.d.ts.map +1 -1
  159. package/dist/lifecycle/index.d.ts +5 -0
  160. package/dist/lifecycle/index.d.ts.map +1 -1
  161. package/dist/lifecycle/oras-referrer-lookup.d.ts +41 -0
  162. package/dist/lifecycle/oras-referrer-lookup.d.ts.map +1 -0
  163. package/dist/lifecycle/release-ledger.d.ts +122 -0
  164. package/dist/lifecycle/release-ledger.d.ts.map +1 -0
  165. package/dist/lifecycle/status.d.ts +150 -0
  166. package/dist/lifecycle/status.d.ts.map +1 -0
  167. package/dist/lint/component-checks.d.ts +95 -0
  168. package/dist/lint/component-checks.d.ts.map +1 -0
  169. package/dist/lint/engine.d.ts +23 -0
  170. package/dist/lint/engine.d.ts.map +1 -1
  171. package/dist/lint/presets/strict.json +8 -1
  172. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts +4 -0
  173. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts.map +1 -0
  174. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts +4 -0
  175. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts.map +1 -0
  176. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts +4 -0
  177. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts.map +1 -0
  178. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts +4 -0
  179. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts.map +1 -0
  180. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts +4 -0
  181. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts.map +1 -0
  182. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts +10 -0
  183. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts.map +1 -0
  184. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts +3 -0
  185. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts.map +1 -0
  186. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts +4 -0
  187. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts.map +1 -0
  188. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts +4 -0
  189. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts.map +1 -0
  190. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts +4 -0
  191. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts.map +1 -0
  192. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts +4 -0
  193. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts.map +1 -0
  194. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts +4 -0
  195. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts.map +1 -0
  196. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +4 -0
  197. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -0
  198. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +4 -0
  199. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -0
  200. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts +4 -0
  201. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts.map +1 -0
  202. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts +4 -0
  203. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts.map +1 -0
  204. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts +4 -0
  205. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts.map +1 -0
  206. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts +4 -0
  207. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts.map +1 -0
  208. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts +4 -0
  209. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts.map +1 -0
  210. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts +4 -0
  211. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts.map +1 -0
  212. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts +3 -0
  213. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts.map +1 -0
  214. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts +4 -0
  215. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts.map +1 -0
  216. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts +20 -0
  217. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts.map +1 -0
  218. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts +28 -0
  219. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts.map +1 -0
  220. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +39 -0
  221. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -0
  222. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +37 -0
  223. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +1 -0
  224. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts +43 -0
  225. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts.map +1 -0
  226. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts +22 -0
  227. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts.map +1 -0
  228. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts +33 -0
  229. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts.map +1 -0
  230. package/dist/lint/rules/comp/index.d.ts +18 -0
  231. package/dist/lint/rules/comp/index.d.ts.map +1 -0
  232. package/dist/lint/rules/comp/support.d.ts +71 -0
  233. package/dist/lint/rules/comp/support.d.ts.map +1 -0
  234. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  235. package/dist/op/activity-registry.d.ts +11 -6
  236. package/dist/op/activity-registry.d.ts.map +1 -1
  237. package/dist/op/activity-runtime.d.ts +24 -0
  238. package/dist/op/activity-runtime.d.ts.map +1 -0
  239. package/dist/op/builders.d.ts +56 -0
  240. package/dist/op/builders.d.ts.map +1 -1
  241. package/dist/op/index.d.ts +2 -1
  242. package/dist/op/index.d.ts.map +1 -1
  243. package/dist/ownership.d.ts +20 -14
  244. package/dist/ownership.d.ts.map +1 -1
  245. package/package.json +14 -1
  246. package/src/audit/catalog.test.ts +74 -22
  247. package/src/audit/catalog.ts +74 -471
  248. package/src/audit/proof.ts +4 -2
  249. package/src/audit/report-html.test.ts +14 -7
  250. package/src/audit/report-model.ts +20 -9
  251. package/src/audit/report.test.ts +36 -13
  252. package/src/audit/report.ts +2 -0
  253. package/src/audit/rules-doc.test.ts +8 -6
  254. package/src/audit/rules-doc.ts +13 -5
  255. package/src/cli/commands/audit.ts +23 -18
  256. package/src/cli/commands/component-lint.test.ts +158 -0
  257. package/src/cli/commands/doctor.test.ts +116 -2
  258. package/src/cli/commands/doctor.ts +46 -0
  259. package/src/cli/commands/lexicon-rolling-upgrade.ts +198 -0
  260. package/src/cli/commands/lexicon-surface-diff.test.ts +104 -0
  261. package/src/cli/commands/lexicon-surface-diff.ts +185 -0
  262. package/src/cli/commands/lint.ts +142 -1
  263. package/src/cli/commands/pinned-upgrade.ts +204 -0
  264. package/src/cli/handlers/build.ts +58 -1
  265. package/src/cli/handlers/components.test.ts +504 -0
  266. package/src/cli/handlers/components.ts +404 -0
  267. package/src/cli/handlers/dev.ts +60 -1
  268. package/src/cli/handlers/graph.ts +47 -2
  269. package/src/cli/handlers/misc.ts +45 -1
  270. package/src/cli/handlers/run.test.ts +967 -3
  271. package/src/cli/handlers/run.ts +618 -11
  272. package/src/cli/main.test.ts +66 -0
  273. package/src/cli/main.ts +105 -2
  274. package/src/cli/registry.ts +35 -0
  275. package/src/codegen/fetch.test.ts +84 -3
  276. package/src/codegen/fetch.ts +76 -2
  277. package/src/codegen/lexicon-regen.test.ts +298 -0
  278. package/src/codegen/lexicon-regen.ts +545 -0
  279. package/src/codegen/pinned-upgrade.test.ts +399 -0
  280. package/src/codegen/pinned-upgrade.ts +423 -0
  281. package/src/codegen/rolling-upgrade.test.ts +333 -0
  282. package/src/codegen/rolling-upgrade.ts +320 -0
  283. package/src/codegen/surface-snapshot.test.ts +461 -0
  284. package/src/codegen/surface-snapshot.ts +546 -0
  285. package/src/codegen/version-bump.test.ts +47 -0
  286. package/src/codegen/version-bump.ts +39 -0
  287. package/src/components/README.md +130 -0
  288. package/src/components/SPRAWL-VALIDATION.md +181 -0
  289. package/src/components/__fixtures__/alb-ecs-service.json +51 -0
  290. package/src/components/__fixtures__/dynamodb-infra.json +32 -0
  291. package/src/components/__fixtures__/emr-job-consumer.json +26 -0
  292. package/src/components/__fixtures__/jar-lib-producer.json +16 -0
  293. package/src/components/__fixtures__/lambda-image-processor.json +28 -0
  294. package/src/components/__fixtures__/neo4j-fanout.json +34 -0
  295. package/src/components/__fixtures__/single-host-compose.json +29 -0
  296. package/src/components/auto-release.test.ts +217 -0
  297. package/src/components/auto-release.ts +216 -0
  298. package/src/components/builders.test.ts +45 -0
  299. package/src/components/builders.ts +71 -0
  300. package/src/components/capability-plugin-loader.ts +218 -0
  301. package/src/components/capability-plugin-schema.ts +56 -0
  302. package/src/components/capability-plugin.test.ts +235 -0
  303. package/src/components/capability-plugin.ts +108 -0
  304. package/src/components/capability.ts +117 -0
  305. package/src/components/cli-support.test.ts +579 -0
  306. package/src/components/cli-support.ts +481 -0
  307. package/src/components/component-schema.test.ts +265 -0
  308. package/src/components/component.schema.json +235 -0
  309. package/src/components/component.test.ts +251 -0
  310. package/src/components/component.ts +255 -0
  311. package/src/components/config-defaults.test.ts +263 -0
  312. package/src/components/config-defaults.ts +145 -0
  313. package/src/components/discover.test.ts +352 -0
  314. package/src/components/discover.ts +167 -0
  315. package/src/components/driver-output.ts +71 -0
  316. package/src/components/driver.test.ts +638 -0
  317. package/src/components/driver.ts +690 -0
  318. package/src/components/index.ts +113 -0
  319. package/src/components/manifest-persistence.test.ts +152 -0
  320. package/src/components/manifest-persistence.ts +164 -0
  321. package/src/components/pilots/README.md +33 -0
  322. package/src/components/pilots/alb-ecs.pilot.ts +63 -0
  323. package/src/components/pilots/dynamodb.pilot.ts +59 -0
  324. package/src/components/pilots/jar-emr.pilot.ts +69 -0
  325. package/src/components/pilots/lambda.pilot.ts +55 -0
  326. package/src/components/pilots/neo4j-fanout.pilot.ts +92 -0
  327. package/src/components/pilots/pilots-lint-clean.test.ts +78 -0
  328. package/src/components/pilots/pilots.test.ts +126 -0
  329. package/src/components/pilots/project.ts +13 -0
  330. package/src/components/presets/comp007-reduction.test.ts +122 -0
  331. package/src/components/presets/ecs-fargate.test.ts +84 -0
  332. package/src/components/presets/ecs-fargate.ts +103 -0
  333. package/src/components/presets/index.ts +32 -0
  334. package/src/components/presets/lambda.test.ts +35 -0
  335. package/src/components/presets/lambda.ts +53 -0
  336. package/src/components/presets/single-host-compose.test.ts +65 -0
  337. package/src/components/presets/single-host-compose.ts +64 -0
  338. package/src/components/registry.test.ts +112 -0
  339. package/src/components/registry.ts +37 -0
  340. package/src/components/starter-plugin.ts +105 -0
  341. package/src/components/temporal-codegen-loader.ts +41 -0
  342. package/src/components/verbs/__fixtures__/package-lock.json +45 -0
  343. package/src/components/verbs/__fixtures__/pom.xml +37 -0
  344. package/src/components/verbs/__fixtures__/schemas/cyclonedx-1.5.schema.json +3800 -0
  345. package/src/components/verbs/__fixtures__/schemas/cyclonedx-spdx-license.schema.json +621 -0
  346. package/src/components/verbs/__fixtures__/schemas/jsf-0.82.schema.json +240 -0
  347. package/src/components/verbs/__fixtures__/schemas/spdx-2.3.schema.json +740 -0
  348. package/src/components/verbs/__tests__/mock-cloud-executor.ts +102 -0
  349. package/src/components/verbs/__tests__/mock-process-runner.ts +79 -0
  350. package/src/components/verbs/__tests__/mock-sbom-generator.ts +85 -0
  351. package/src/components/verbs/bom-writer.test.ts +331 -0
  352. package/src/components/verbs/bom-writer.ts +386 -0
  353. package/src/components/verbs/build-archive.test.ts +251 -0
  354. package/src/components/verbs/build-archive.ts +296 -0
  355. package/src/components/verbs/build.test.ts +222 -0
  356. package/src/components/verbs/build.ts +252 -0
  357. package/src/components/verbs/cloud-executor.ts +181 -0
  358. package/src/components/verbs/component-bom.test.ts +219 -0
  359. package/src/components/verbs/component-bom.ts +189 -0
  360. package/src/components/verbs/index.ts +49 -0
  361. package/src/components/verbs/license-policy.ts +115 -0
  362. package/src/components/verbs/lockfile-sbom-generator.test.ts +195 -0
  363. package/src/components/verbs/lockfile-sbom-generator.ts +236 -0
  364. package/src/components/verbs/process-runner.test.ts +79 -0
  365. package/src/components/verbs/process-runner.ts +113 -0
  366. package/src/components/verbs/reproducibility.test.ts +24 -0
  367. package/src/components/verbs/reproducibility.ts +100 -0
  368. package/src/components/verbs/sbom-generator.test.ts +96 -0
  369. package/src/components/verbs/sbom-generator.ts +209 -0
  370. package/src/components/verbs/sbom.test.ts +184 -0
  371. package/src/components/verbs/sbom.ts +152 -0
  372. package/src/components/verbs/shell.test.ts +36 -0
  373. package/src/components/verbs/shell.ts +51 -0
  374. package/src/components/verbs/sign.test.ts +210 -0
  375. package/src/components/verbs/sign.ts +350 -0
  376. package/src/components/verbs/stub.ts +34 -0
  377. package/src/components/verbs/tool-sbom-generator.test.ts +194 -0
  378. package/src/components/verbs/tool-sbom-generator.ts +192 -0
  379. package/src/components/verbs/verify.test.ts +159 -0
  380. package/src/components/verbs/verify.ts +179 -0
  381. package/src/components/verbs/vex.ts +182 -0
  382. package/src/components/verbs/vuln-gate.test.ts +201 -0
  383. package/src/components/verbs/vuln-gate.ts +170 -0
  384. package/src/components/verbs/vuln-scan.test.ts +145 -0
  385. package/src/components/verbs/vuln-scan.ts +266 -0
  386. package/src/components/verbs/wait-verify.test.ts +111 -0
  387. package/src/components/verbs/wait-verify.ts +171 -0
  388. package/src/config.test.ts +74 -1
  389. package/src/config.ts +219 -0
  390. package/src/index.ts +32 -0
  391. package/src/lexicon.ts +88 -0
  392. package/src/lifecycle/build-ledger-store.test.ts +217 -0
  393. package/src/lifecycle/build-ledger-store.ts +165 -0
  394. package/src/lifecycle/build-ledger.test.ts +349 -0
  395. package/src/lifecycle/build-ledger.ts +305 -0
  396. package/src/lifecycle/git.test.ts +118 -0
  397. package/src/lifecycle/git.ts +149 -14
  398. package/src/lifecycle/index.ts +5 -0
  399. package/src/lifecycle/oras-referrer-lookup.test.ts +116 -0
  400. package/src/lifecycle/oras-referrer-lookup.ts +110 -0
  401. package/src/lifecycle/release-ledger.test.ts +209 -0
  402. package/src/lifecycle/release-ledger.ts +185 -0
  403. package/src/lifecycle/status.test.ts +330 -0
  404. package/src/lifecycle/status.ts +278 -0
  405. package/src/lint/component-checks.ts +148 -0
  406. package/src/lint/config.test.ts +21 -0
  407. package/src/lint/engine.ts +11 -2
  408. package/src/lint/presets/relaxed.json +8 -1
  409. package/src/lint/presets/strict.json +8 -1
  410. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.ts +9 -0
  411. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.ts +9 -0
  412. package/src/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.ts +11 -0
  413. package/src/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.ts +13 -0
  414. package/src/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.ts +11 -0
  415. package/src/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.ts +27 -0
  416. package/src/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.ts +10 -0
  417. package/src/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.ts +23 -0
  418. package/src/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.ts +10 -0
  419. package/src/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.ts +19 -0
  420. package/src/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.ts +10 -0
  421. package/src/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.ts +20 -0
  422. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +23 -0
  423. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +10 -0
  424. package/src/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.ts +14 -0
  425. package/src/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.ts +18 -0
  426. package/src/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.ts +10 -0
  427. package/src/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.ts +14 -0
  428. package/src/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.ts +13 -0
  429. package/src/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.ts +13 -0
  430. package/src/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.ts +12 -0
  431. package/src/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.ts +18 -0
  432. package/src/lint/rules/comp/comp.test.ts +378 -0
  433. package/src/lint/rules/comp/comp001-publishes-never-applies.ts +78 -0
  434. package/src/lint/rules/comp/comp002-dangling-wiring-ref.ts +94 -0
  435. package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +115 -0
  436. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +66 -0
  437. package/src/lint/rules/comp/comp005-capability-kind-is-noun.ts +113 -0
  438. package/src/lint/rules/comp/comp006-shell-needs-reason.ts +55 -0
  439. package/src/lint/rules/comp/comp007-composition-sprawl.ts +71 -0
  440. package/src/lint/rules/comp/index.ts +37 -0
  441. package/src/lint/rules/comp/support.ts +173 -0
  442. package/src/lsp/lexicon-providers.test.ts +55 -0
  443. package/src/lsp/lexicon-providers.ts +13 -3
  444. package/src/op/activity-registry.test.ts +38 -0
  445. package/src/op/activity-registry.ts +31 -12
  446. package/src/op/activity-runtime.ts +73 -0
  447. package/src/op/builders.ts +92 -0
  448. package/src/op/index.ts +3 -1
  449. package/src/ownership.test.ts +24 -26
  450. package/src/ownership.ts +26 -38
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Tests `sign`/`attest-provenance` (#622, ./sign.ts) against a
3
+ * `MockProcessRunner` (./__tests__/mock-process-runner.ts) — no live
4
+ * `cosign`, no real Rekor/Fulcio network call, ever. Asserts the constructed
5
+ * keyless `cosign sign`/`cosign attest` invocations, the digest-only guard,
6
+ * the opt-in key-based override, and graceful `cosign`-absent handling.
7
+ */
8
+
9
+ import { describe, expect, it } from "vitest";
10
+ import {
11
+ buildAttestArgs,
12
+ buildProvenanceStatement,
13
+ buildSignArgs,
14
+ createAttestProvenanceCapability,
15
+ createSignCapability,
16
+ SignTargetNotDigestError,
17
+ } from "./sign";
18
+ import { ToolNotAvailableError } from "./process-runner";
19
+ import { createMockProcessRunner } from "./__tests__/mock-process-runner";
20
+
21
+ const ctx = { env: "prod", component: "search-service" };
22
+ const DIGEST_REF =
23
+ "123.dkr.ecr.us-east-1.amazonaws.com/search@sha256:" + "a".repeat(64);
24
+ const TAG_REF = "123.dkr.ecr.us-east-1.amazonaws.com/search:latest";
25
+
26
+ describe("sign — keyless by default (#622)", () => {
27
+ it("builds a keyless cosign sign invocation with no --key flag", () => {
28
+ const cmd = buildSignArgs({ imageRef: DIGEST_REF });
29
+ expect(cmd).toBe(`cosign sign --yes '${DIGEST_REF}'`);
30
+ expect(cmd).not.toContain("--key");
31
+ });
32
+
33
+ it("runs cosign sign against the digest and reports method: keyless", async () => {
34
+ const mock = createMockProcessRunner();
35
+ const capability = createSignCapability(mock.runner);
36
+
37
+ const output = await capability.run(ctx, { imageRef: DIGEST_REF });
38
+
39
+ expect(output).toEqual({ imageRef: DIGEST_REF, signed: true, method: "keyless" });
40
+ const signCall = mock.calls.find((c) => c.command.startsWith("cosign sign"))!;
41
+ expect(signCall.command).toContain(DIGEST_REF);
42
+ expect(signCall.command).not.toContain("--key");
43
+ });
44
+
45
+ it("passes through explicit OIDC issuer/client-id/token overrides", () => {
46
+ const cmd = buildSignArgs({
47
+ imageRef: DIGEST_REF,
48
+ keyless: { identityToken: "tok", oidcIssuer: "https://issuer.example", oidcClientId: "sigstore" },
49
+ });
50
+ expect(cmd).toContain("--identity-token 'tok'");
51
+ expect(cmd).toContain("--oidc-issuer 'https://issuer.example'");
52
+ expect(cmd).toContain("--oidc-client-id 'sigstore'");
53
+ });
54
+
55
+ it("attaches annotations via -a k=v flags", () => {
56
+ const cmd = buildSignArgs({ imageRef: DIGEST_REF, annotations: { build: "123", branch: "main" } });
57
+ expect(cmd).toContain("-a 'build=123'");
58
+ expect(cmd).toContain("-a 'branch=main'");
59
+ });
60
+
61
+ it("refuses to sign a mutable tag reference — never a tag, only a digest", async () => {
62
+ const mock = createMockProcessRunner();
63
+ const capability = createSignCapability(mock.runner);
64
+
65
+ await expect(capability.run(ctx, { imageRef: TAG_REF })).rejects.toThrow(SignTargetNotDigestError);
66
+ // Refuses before ever shelling out — no cosign call attempted at all.
67
+ expect(mock.calls).toHaveLength(0);
68
+ });
69
+
70
+ it("switches to key-based signing only when input.key is explicitly supplied (opt-in, not default)", async () => {
71
+ const mock = createMockProcessRunner();
72
+ const capability = createSignCapability(mock.runner);
73
+
74
+ const output = await capability.run(ctx, {
75
+ imageRef: DIGEST_REF,
76
+ key: { key: "awskms://alias/my-signing-key" },
77
+ });
78
+
79
+ expect(output.method).toBe("key");
80
+ const signCall = mock.calls.find((c) => c.command.startsWith("cosign sign"))!;
81
+ expect(signCall.command).toContain("--key 'awskms://alias/my-signing-key'");
82
+ expect(signCall.command).not.toContain("--oidc-issuer");
83
+ });
84
+
85
+ it("throws ToolNotAvailableError when cosign is absent, rather than silently skipping the signature", async () => {
86
+ const mock = createMockProcessRunner({ tools: { cosign: false } });
87
+ const capability = createSignCapability(mock.runner);
88
+
89
+ await expect(capability.run(ctx, { imageRef: DIGEST_REF })).rejects.toThrow(ToolNotAvailableError);
90
+ });
91
+
92
+ it("declares no rollback — an already-signed, content-addressed image's signature is immutable evidence", () => {
93
+ const capability = createSignCapability(createMockProcessRunner().runner);
94
+ expect(capability.rollback).toBeUndefined();
95
+ });
96
+ });
97
+
98
+ describe("buildProvenanceStatement — SLSA in-toto statement from #614 provenance material", () => {
99
+ it("builds a subject/predicate from the digest ref and ProvenanceLink", () => {
100
+ const statement = buildProvenanceStatement({
101
+ imageRef: DIGEST_REF,
102
+ provenance: { sourceRef: "abc123def", artifactDigest: DIGEST_REF.split("@")[1]! },
103
+ builderId: "https://github.com/actions/runner",
104
+ });
105
+
106
+ expect(statement._type).toBe("https://in-toto.io/Statement/v1");
107
+ expect(statement.predicateType).toBe("https://slsa.dev/provenance/v1");
108
+ expect(statement.subject).toEqual([
109
+ { name: DIGEST_REF, digest: { sha256: "a".repeat(64) } },
110
+ ]);
111
+ expect(statement.predicate.buildDefinition.externalParameters).toEqual({ sourceRef: "abc123def" });
112
+ expect(statement.predicate.runDetails.builder.id).toBe("https://github.com/actions/runner");
113
+ expect(statement.predicate.runDetails.metadata?.finishedOn).toBeDefined();
114
+ });
115
+
116
+ it("throws when imageRef has no digest", () => {
117
+ expect(() =>
118
+ buildProvenanceStatement({
119
+ imageRef: TAG_REF,
120
+ provenance: { sourceRef: "abc", artifactDigest: "sha256:x" },
121
+ builderId: "builder",
122
+ }),
123
+ ).toThrow(SignTargetNotDigestError);
124
+ });
125
+ });
126
+
127
+ describe("attest-provenance — keyless cosign attest (#622)", () => {
128
+ it("builds a keyless cosign attest invocation with the slsaprovenance1 type and no --key", () => {
129
+ const cmd = buildAttestArgs({
130
+ imageRef: DIGEST_REF,
131
+ provenance: { sourceRef: "abc123", artifactDigest: "sha256:x" },
132
+ builderId: "builder",
133
+ }, "/tmp/scratch.json");
134
+
135
+ expect(cmd).toContain("cosign attest --yes --type slsaprovenance1 --predicate '/tmp/scratch.json'");
136
+ expect(cmd).toContain(DIGEST_REF);
137
+ expect(cmd).not.toContain("--key");
138
+ });
139
+
140
+ it("signs+attaches the SLSA provenance statement via cosign attest, keyless by default", async () => {
141
+ const mock = createMockProcessRunner();
142
+ const capability = createAttestProvenanceCapability(mock.runner);
143
+
144
+ const output = await capability.run(ctx, {
145
+ imageRef: DIGEST_REF,
146
+ provenance: { sourceRef: "abc123def", artifactDigest: DIGEST_REF.split("@")[1]! },
147
+ builderId: "https://github.com/actions/runner",
148
+ });
149
+
150
+ expect(output.attested).toBe(true);
151
+ expect(output.method).toBe("keyless");
152
+ expect(output.statement.predicateType).toBe("https://slsa.dev/provenance/v1");
153
+
154
+ const attestCall = mock.calls.find((c) => c.command.startsWith("cosign attest"))!;
155
+ expect(attestCall.command).toContain("--type slsaprovenance1");
156
+ expect(attestCall.command).toContain(DIGEST_REF);
157
+ expect(attestCall.command).not.toContain("--key");
158
+
159
+ // The predicate file is written to a scratch path before cosign reads it.
160
+ expect(mock.calls.some((c) => c.command.includes("chant-provenance-attest"))).toBe(true);
161
+ });
162
+
163
+ it("uses key-based attestation only when explicitly configured", async () => {
164
+ const mock = createMockProcessRunner();
165
+ const capability = createAttestProvenanceCapability(mock.runner);
166
+
167
+ const output = await capability.run(ctx, {
168
+ imageRef: DIGEST_REF,
169
+ provenance: { sourceRef: "abc123def", artifactDigest: DIGEST_REF.split("@")[1]! },
170
+ builderId: "builder",
171
+ key: { key: "cosign.key" },
172
+ });
173
+
174
+ expect(output.method).toBe("key");
175
+ const attestCall = mock.calls.find((c) => c.command.startsWith("cosign attest"))!;
176
+ expect(attestCall.command).toContain("--key 'cosign.key'");
177
+ });
178
+
179
+ it("refuses a tag-only imageRef before ever shelling out", async () => {
180
+ const mock = createMockProcessRunner();
181
+ const capability = createAttestProvenanceCapability(mock.runner);
182
+
183
+ await expect(
184
+ capability.run(ctx, {
185
+ imageRef: TAG_REF,
186
+ provenance: { sourceRef: "abc", artifactDigest: "sha256:x" },
187
+ builderId: "builder",
188
+ }),
189
+ ).rejects.toThrow(SignTargetNotDigestError);
190
+ expect(mock.calls).toHaveLength(0);
191
+ });
192
+
193
+ it("throws ToolNotAvailableError when cosign is absent", async () => {
194
+ const mock = createMockProcessRunner({ tools: { cosign: false } });
195
+ const capability = createAttestProvenanceCapability(mock.runner);
196
+
197
+ await expect(
198
+ capability.run(ctx, {
199
+ imageRef: DIGEST_REF,
200
+ provenance: { sourceRef: "abc", artifactDigest: DIGEST_REF.split("@")[1]! },
201
+ builderId: "builder",
202
+ }),
203
+ ).rejects.toThrow(ToolNotAvailableError);
204
+ });
205
+
206
+ it("declares no rollback — an attached attestation is immutable evidence", () => {
207
+ const capability = createAttestProvenanceCapability(createMockProcessRunner().runner);
208
+ expect(capability.rollback).toBeUndefined();
209
+ });
210
+ });
@@ -0,0 +1,350 @@
1
+ /**
2
+ * `sign` capability — keyless cosign signing + SLSA provenance attestation
3
+ * (#622, epic #551 follow-up to #610's referrer-attach path and #614's
4
+ * reproducibility/provenance material). The companion gate is
5
+ * `./verify.ts`'s `verify` capability.
6
+ *
7
+ * **Beginner footgun #1 neutralized: sign the digest, never a tag.** `input`
8
+ * requires an already-resolved `sha256:` image reference (typically wired
9
+ * from a prior publish step, `"@Publish.uri"`, which is itself
10
+ * `repo@sha256:...` — see ./publish.ts) — never a bare tag. A tag is mutable;
11
+ * signing one says nothing about which bytes were actually signed by the
12
+ * time someone pulls it. `assertDigestRef` below throws before ever shelling
13
+ * out if a caller passes a tag-only reference.
14
+ *
15
+ * **Beginner footgun #2 neutralized: keyless by default.** Sign via cosign's
16
+ * keyless flow (a short-lived Fulcio cert bound to an OIDC identity, logged
17
+ * to the public Rekor transparency log) — `cosign sign --yes <ref>` with no
18
+ * `--key`. There is no private key file for a first-timer to generate, lose,
19
+ * leak, or forget to rotate. Key-based signing (`input.key`) is an opt-in
20
+ * override for teams with an existing KMS/file-based key policy, never the
21
+ * default — see `buildSignArgs`/`buildAttestArgs` below: `--key` is added
22
+ * only when `input.key` is explicitly supplied, and it is the *only* thing
23
+ * that changes about the invocation (still by digest, still attached the
24
+ * same way).
25
+ *
26
+ * **SLSA provenance.** `attestProvenance` builds an in-toto
27
+ * `https://slsa.dev/provenance/v1` statement from the same
28
+ * `ProvenanceLink`/`ArtifactReproducibility` material #614's
29
+ * ./reproducibility.ts already records per build-archive entry (source ref,
30
+ * artifact digest) plus a builder id and timestamp, then signs+attaches it
31
+ * via `cosign attest` (keyless by the same default). This reuses #614's
32
+ * provenance model rather than inventing a second one — the in-toto
33
+ * statement's `predicate.buildDefinition.resolvedDependencies` /
34
+ * `.internalParameters` are populated from the same source-ref/digest link a
35
+ * build archive entry already carries.
36
+ *
37
+ * Both `sign` and `attestProvenance` shell out to `cosign` through the
38
+ * injectable `ProcessRunner` (./process-runner.ts) — mirroring
39
+ * ./tool-sbom-generator.ts and ./publish.ts's referrer-attach step exactly:
40
+ * `requireTool` throws `ToolNotAvailableError` with an actionable message if
41
+ * `cosign` is absent, and no test here ever spawns a real process or talks
42
+ * to Rekor/Fulcio.
43
+ */
44
+
45
+ import type { Capability } from "../capability";
46
+ import { defaultProcessRunner, q, requireTool, type ProcessRunner } from "./process-runner";
47
+ import type { ProvenanceLink } from "./reproducibility";
48
+
49
+ // ── shared: digest-only reference guard ─────────────────────────────────────
50
+
51
+ /**
52
+ * Thrown when a `sign`/`attest` input's image reference has no `@sha256:...`
53
+ * digest — refusing to sign a mutable tag (beginner footgun #1) rather than
54
+ * silently signing whatever the tag happens to resolve to right now.
55
+ */
56
+ export class SignTargetNotDigestError extends Error {
57
+ constructor(
58
+ public readonly ref: string,
59
+ public readonly verb: "sign" | "attest",
60
+ ) {
61
+ super(
62
+ `${verb} "${ref}": expected a digest reference ("repo@sha256:...", e.g. from a prior publish step's "@Publish.uri") — ` +
63
+ `signing a mutable tag would not pin which bytes were signed. Pass the digest-qualified reference instead.`,
64
+ );
65
+ this.name = "SignTargetNotDigestError";
66
+ }
67
+ }
68
+
69
+ /** True if `ref` carries an `@sha256:<hex>` digest — the only form `sign`/`attest` accept. */
70
+ function isDigestRef(ref: string): boolean {
71
+ return /@sha256:[0-9a-f]{64}$/i.test(ref);
72
+ }
73
+
74
+ /** Throw `SignTargetNotDigestError` unless `ref` is digest-qualified. */
75
+ function assertDigestRef(ref: string, verb: "sign" | "attest"): void {
76
+ if (!isDigestRef(ref)) throw new SignTargetNotDigestError(ref, verb);
77
+ }
78
+
79
+ // ── keyless identity config (shared by sign + attest + verify) ─────────────
80
+
81
+ /**
82
+ * cosign keyless signing config. Keyless is the default story this whole
83
+ * module encodes — every field here is optional because `cosign sign --yes`
84
+ * with no flags at all already does the right thing in CI (ambient OIDC from
85
+ * the CI provider's own token, e.g. GitHub Actions' `id-token: write`).
86
+ * `identityToken`/`oidcIssuer`/`oidcClientId` are the explicit overrides for
87
+ * environments without ambient OIDC detection.
88
+ */
89
+ export interface KeylessSigningConfig {
90
+ /** Explicit OIDC identity token, when the environment has no ambient CI OIDC cosign can auto-detect. */
91
+ identityToken?: string;
92
+ /** OIDC issuer URL override (`cosign sign --oidc-issuer`). */
93
+ oidcIssuer?: string;
94
+ /** OIDC client id override (`cosign sign --oidc-client-id`). */
95
+ oidcClientId?: string;
96
+ /** Fulcio URL override, for a private Sigstore instance. */
97
+ fulcioUrl?: string;
98
+ /** Rekor URL override, for a private transparency log. */
99
+ rekorUrl?: string;
100
+ }
101
+
102
+ /**
103
+ * Key-based signing override config — opt-in, never the default (see this
104
+ * module's doc comment). Supplying `input.key` on `sign`/`attestProvenance`
105
+ * switches the invocation to `cosign sign --key <key>` instead of the keyless
106
+ * flow; every other part of the invocation (digest-only target, referrer
107
+ * attach) is unchanged.
108
+ */
109
+ export interface KeyBasedSigningConfig {
110
+ /** Key reference cosign accepts: a local path, `kms://...`, `k8s://...`, `azurekms://...`, `awskms://...`, etc. An encrypted key file's password is not accepted here — `ProcessRunner.run` (./process-runner.ts) has no env-var passthrough today, and interpolating a secret into the shell command string would leak it into process listings/logs; supply an unencrypted key reference (e.g. a KMS URI) or export `COSIGN_PASSWORD` in the calling process's own environment instead. */
111
+ key: string;
112
+ }
113
+
114
+ /** Append the shared keyless/key-based signing flags to a cosign argv, mutating `args` in place. Shared by `buildSignArgs` and `buildAttestArgs` so both stay in lockstep. */
115
+ function appendSigningFlags(
116
+ args: string[],
117
+ opts: { keyless?: KeylessSigningConfig; key?: KeyBasedSigningConfig },
118
+ ): void {
119
+ if (opts.key) {
120
+ args.push("--key", q(opts.key.key));
121
+ return;
122
+ }
123
+ // Keyless (default): no --key at all — cosign's own keyless flow (Fulcio + Rekor).
124
+ const k = opts.keyless;
125
+ if (k?.identityToken) args.push("--identity-token", q(k.identityToken));
126
+ if (k?.oidcIssuer) args.push("--oidc-issuer", q(k.oidcIssuer));
127
+ if (k?.oidcClientId) args.push("--oidc-client-id", q(k.oidcClientId));
128
+ if (k?.fulcioUrl) args.push("--fulcio-url", q(k.fulcioUrl));
129
+ if (k?.rekorUrl) args.push("--rekor-url", q(k.rekorUrl));
130
+ }
131
+
132
+ // ── sign ─────────────────────────────────────────────────────────────────────
133
+
134
+ export interface SignInput {
135
+ /** Digest-qualified image reference to sign, e.g. `"123.dkr.ecr.us-east-1.amazonaws.com/search@sha256:abc..."` — typically wired from a prior publish step's `"@Publish.uri"`. Never a bare tag; see `SignTargetNotDigestError`. */
136
+ imageRef: string;
137
+ /** Keyless signing config (OIDC identity + Rekor/Fulcio overrides). Default: cosign's own ambient keyless detection, no explicit config needed. Ignored when `key` is supplied. */
138
+ keyless?: KeylessSigningConfig;
139
+ /** Opt-in key-based override — supply to sign with a private/KMS key instead of the keyless default. Not the default; see this module's doc comment. */
140
+ key?: KeyBasedSigningConfig;
141
+ /** Annotations to attach to the signature (`cosign sign -a k=v`), e.g. build metadata. */
142
+ annotations?: Record<string, string>;
143
+ }
144
+
145
+ export interface SignOutput {
146
+ /** The digest-qualified reference that was signed — echoed back for downstream wiring (e.g. into `attestProvenance`/`verify`). */
147
+ imageRef: string;
148
+ /** True once `cosign sign` completed without error. */
149
+ signed: true;
150
+ /** `"keyless"` or `"key"`, reflecting which flow actually ran. */
151
+ method: "keyless" | "key";
152
+ }
153
+
154
+ /** Build the `cosign sign` argv (as a shell command string) for `input` — factored out so tests can assert on the exact invocation without needing a full mock run. */
155
+ export function buildSignArgs(input: SignInput): string {
156
+ const args = ["cosign", "sign", "--yes"];
157
+ appendSigningFlags(args, { keyless: input.keyless, key: input.key });
158
+ for (const [k, v] of Object.entries(input.annotations ?? {})) {
159
+ args.push("-a", q(`${k}=${v}`));
160
+ }
161
+ args.push(q(input.imageRef));
162
+ return args.join(" ");
163
+ }
164
+
165
+ /**
166
+ * Sign an artifact by digest via keyless cosign (default) or an opt-in
167
+ * key-based override, and attach the signature as an OCI referrer on that
168
+ * digest — `cosign sign` itself performs the attach (cosign's signatures are
169
+ * always stored as registry referrers/the legacy tag convention; no separate
170
+ * `oras attach` step is needed the way SBOM/BOM referrer attach in
171
+ * ./publish.ts requires one, since cosign natively pushes to the registry).
172
+ * Refuses to run at all against a non-digest reference (`SignTargetNotDigestError`)
173
+ * — sign is never invoked for a tag, by construction, before any process is spawned.
174
+ *
175
+ * No rollback: an already-signed, content-addressed image's signature is
176
+ * immutable evidence sitting in the registry — nothing to compensate, the
177
+ * same opt-out `publish-image`/`generate-sbom` already take for
178
+ * no-mutable-remote-state operations.
179
+ */
180
+ export function createSignCapability(
181
+ processRunner: ProcessRunner = defaultProcessRunner(),
182
+ ): Capability<SignInput, SignOutput> {
183
+ return {
184
+ kind: "sign",
185
+ async run(_ctx, input) {
186
+ assertDigestRef(input.imageRef, "sign");
187
+ await requireTool(processRunner, "cosign", `sign ${input.imageRef}`);
188
+ await processRunner.run(buildSignArgs(input));
189
+ return { imageRef: input.imageRef, signed: true, method: input.key ? "key" : "keyless" };
190
+ },
191
+ };
192
+ }
193
+
194
+ /** Default `sign` capability, backed by the real `ProcessRunner`. */
195
+ export const signCapability: Capability<SignInput, SignOutput> = createSignCapability();
196
+
197
+ // ── SLSA provenance attestation (attest-provenance) ─────────────────────────
198
+
199
+ /** Minimal in-toto `https://slsa.dev/provenance/v1` predicate — the fields this module can honestly populate from #614's `ProvenanceLink` material, not a full SLSA Level 3+ builder identity/hermeticity claim. */
200
+ export interface SlsaProvenancePredicate {
201
+ buildDefinition: {
202
+ buildType: string;
203
+ externalParameters: Record<string, unknown>;
204
+ internalParameters?: Record<string, unknown>;
205
+ resolvedDependencies?: Array<{ uri: string; digest?: Record<string, string> }>;
206
+ };
207
+ runDetails: {
208
+ builder: { id: string };
209
+ metadata?: {
210
+ invocationId?: string;
211
+ startedOn?: string;
212
+ finishedOn?: string;
213
+ };
214
+ };
215
+ }
216
+
217
+ /** The full in-toto statement wrapping the SLSA predicate — what `cosign attest` signs+attaches. */
218
+ export interface InTotoProvenanceStatement {
219
+ _type: "https://in-toto.io/Statement/v1";
220
+ predicateType: "https://slsa.dev/provenance/v1";
221
+ subject: Array<{ name: string; digest: { sha256: string } }>;
222
+ predicate: SlsaProvenancePredicate;
223
+ }
224
+
225
+ export interface BuildProvenanceStatementInput {
226
+ /** The digest-qualified artifact reference this provenance describes (subject). */
227
+ imageRef: string;
228
+ /** Source -> output link, reused from #614 (./reproducibility.ts) rather than re-deriving a second source-of-truth for "what commit produced this." */
229
+ provenance: ProvenanceLink;
230
+ /** Builder identity URI, e.g. a CI run URL or `"https://github.com/actions/runner"`. */
231
+ builderId: string;
232
+ /** Build type identifier (an arbitrary URI naming the recipe kind, e.g. `"https://chant.dev/build-archive/v1"`). Defaults to a chant-generic build type. */
233
+ buildType?: string;
234
+ /** ISO-8601 timestamp of the build's completion. Defaults to `new Date().toISOString()`. */
235
+ finishedOn?: string;
236
+ /** CI invocation/run id, when available (e.g. a GitHub Actions run id). */
237
+ invocationId?: string;
238
+ }
239
+
240
+ const DEFAULT_BUILD_TYPE = "https://chant.dev/build-archive/v1";
241
+
242
+ /** Extract the bare `sha256:...` digest out of a digest-qualified reference (`repo@sha256:...`). */
243
+ function digestOf(ref: string): string {
244
+ const match = /sha256:([0-9a-f]{64})$/i.exec(ref);
245
+ if (!match) throw new SignTargetNotDigestError(ref, "attest");
246
+ return match[1]!;
247
+ }
248
+
249
+ /**
250
+ * Build an in-toto SLSA provenance statement for `input.imageRef`, reusing
251
+ * #614's `ProvenanceLink` (source ref -> artifact digest) as the statement's
252
+ * `resolvedDependencies`/`internalParameters` material — the honest subset
253
+ * chant can actually attest to (which source commit, which builder, when),
254
+ * matching ./reproducibility.ts's "honesty over convenience" stance rather
255
+ * than fabricating a stronger provenance claim than the build system backs.
256
+ */
257
+ export function buildProvenanceStatement(input: BuildProvenanceStatementInput): InTotoProvenanceStatement {
258
+ const digest = digestOf(input.imageRef);
259
+ return {
260
+ _type: "https://in-toto.io/Statement/v1",
261
+ predicateType: "https://slsa.dev/provenance/v1",
262
+ subject: [{ name: input.imageRef, digest: { sha256: digest } }],
263
+ predicate: {
264
+ buildDefinition: {
265
+ buildType: input.buildType ?? DEFAULT_BUILD_TYPE,
266
+ externalParameters: { sourceRef: input.provenance.sourceRef },
267
+ internalParameters: { artifactDigest: input.provenance.artifactDigest },
268
+ resolvedDependencies: [{ uri: input.provenance.sourceRef, digest: { sha256: digest } }],
269
+ },
270
+ runDetails: {
271
+ builder: { id: input.builderId },
272
+ metadata: {
273
+ ...(input.invocationId ? { invocationId: input.invocationId } : {}),
274
+ finishedOn: input.finishedOn ?? new Date().toISOString(),
275
+ },
276
+ },
277
+ },
278
+ };
279
+ }
280
+
281
+ export interface AttestProvenanceInput extends BuildProvenanceStatementInput {
282
+ /** Keyless signing config, same shape/default as `SignInput.keyless`. */
283
+ keyless?: KeylessSigningConfig;
284
+ /** Opt-in key-based override, same shape/default as `SignInput.key`. */
285
+ key?: KeyBasedSigningConfig;
286
+ }
287
+
288
+ export interface AttestProvenanceOutput {
289
+ /** The digest-qualified reference the provenance was attested for. */
290
+ imageRef: string;
291
+ /** The in-toto statement that was signed+attached (returned for inspection/logging/tests). */
292
+ statement: InTotoProvenanceStatement;
293
+ /** True once `cosign attest` completed without error. */
294
+ attested: true;
295
+ /** `"keyless"` or `"key"`, reflecting which flow actually ran. */
296
+ method: "keyless" | "key";
297
+ }
298
+
299
+ /**
300
+ * Build the `cosign attest` argv (as a shell command string) for a
301
+ * predicate-type/payload pair. Factored out (like `buildSignArgs`) so tests
302
+ * can assert on the exact invocation. `--predicate` reads from a scratch
303
+ * file path (`cosign attest` does not accept the payload on stdin any more
304
+ * reliably than `oras attach` does — see ./publish.ts's `attachOneReferrer`
305
+ * for the same scratch-file convention) — the caller passes the path already
306
+ * written.
307
+ */
308
+ export function buildAttestArgs(
309
+ input: AttestProvenanceInput,
310
+ predicatePath: string,
311
+ ): string {
312
+ const args = ["cosign", "attest", "--yes", "--type", "slsaprovenance1", "--predicate", q(predicatePath)];
313
+ appendSigningFlags(args, { keyless: input.keyless, key: input.key });
314
+ args.push(q(input.imageRef));
315
+ return args.join(" ");
316
+ }
317
+
318
+ /**
319
+ * Build an in-toto SLSA provenance statement for a digest-qualified artifact
320
+ * (reusing #614's `ProvenanceLink` material) and sign+attach it via keyless
321
+ * `cosign attest` (default) or an opt-in key-based override — attached as a
322
+ * referrer alongside the signature (`sign`) and SBOM (`generate-sbom`) on
323
+ * the same digest. Refuses a non-digest `imageRef` the same way `sign` does.
324
+ *
325
+ * No rollback: same reasoning as `sign` — an attached, content-addressed
326
+ * attestation is immutable evidence, nothing to compensate.
327
+ */
328
+ export function createAttestProvenanceCapability(
329
+ processRunner: ProcessRunner = defaultProcessRunner(),
330
+ ): Capability<AttestProvenanceInput, AttestProvenanceOutput> {
331
+ return {
332
+ kind: "attest-provenance",
333
+ async run(_ctx, input) {
334
+ assertDigestRef(input.imageRef, "attest");
335
+ await requireTool(processRunner, "cosign", `attest SLSA provenance for ${input.imageRef}`);
336
+
337
+ const statement = buildProvenanceStatement(input);
338
+ const scratchFile = `/tmp/chant-provenance-attest/${digestOf(input.imageRef)}-${Date.now()}.json`;
339
+ await processRunner.run(`mkdir -p ${q("/tmp/chant-provenance-attest")}`);
340
+ await processRunner.run(`printf '%s' ${q(JSON.stringify(statement))} > ${q(scratchFile)}`);
341
+ await processRunner.run(buildAttestArgs(input, scratchFile));
342
+
343
+ return { imageRef: input.imageRef, statement, attested: true, method: input.key ? "key" : "keyless" };
344
+ },
345
+ };
346
+ }
347
+
348
+ /** Default `attest-provenance` capability, backed by the real `ProcessRunner`. */
349
+ export const attestProvenanceCapability: Capability<AttestProvenanceInput, AttestProvenanceOutput> =
350
+ createAttestProvenanceCapability();
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Shared helper for building typed capability stubs.
3
+ *
4
+ * A stub is fully typed (`kind`, `In`, `Out`) so compositions can wire
5
+ * output -> input and lint can check the graph, but `run`/`rollback` throw
6
+ * `CapabilityNotImplementedError` — no cloud calls, no side effects. Cloud
7
+ * implementations land in a later phase (epic #551).
8
+ */
9
+
10
+ import type { Capability } from "../capability";
11
+ import { CapabilityNotImplementedError } from "../capability";
12
+
13
+ /**
14
+ * Build a stub `Capability<In, Out>` for `kind`. `supportsRollback` also
15
+ * attaches a `rollback` that throws the same error, so compositions can
16
+ * already reference `rollback` in typed code ahead of the real implementation.
17
+ */
18
+ export function stubCapability<In, Out>(
19
+ kind: string,
20
+ opts?: { rollback?: boolean },
21
+ ): Capability<In, Out> {
22
+ const capability: Capability<In, Out> = {
23
+ kind,
24
+ async run(): Promise<Out> {
25
+ throw new CapabilityNotImplementedError(kind);
26
+ },
27
+ };
28
+ if (opts?.rollback) {
29
+ capability.rollback = async (): Promise<void> => {
30
+ throw new CapabilityNotImplementedError(kind);
31
+ };
32
+ }
33
+ return capability;
34
+ }