@kungfu-tech/buildchain 4.1.0-alpha.0 → 4.1.0-alpha.2

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 (295) hide show
  1. package/AGENTS.md +30 -41
  2. package/CONTRIBUTING.md +6 -7
  3. package/architecture/action-taxonomy.json +5 -21
  4. package/architecture/agent-change-map.md +74 -56
  5. package/architecture/build-orchestration.json +8 -1
  6. package/architecture/ci-lane-change-budget.json +179 -69
  7. package/architecture/floating-consumer-policy.json +7 -17
  8. package/architecture/internal-capabilities.json +58 -72
  9. package/architecture/maintainability-debt.json +138 -52
  10. package/architecture/maintainability-policy.json +6 -15
  11. package/architecture/promotion-job-topology.json +39 -20
  12. package/architecture/release-topology.json +26 -37
  13. package/architecture/runtime-entry.json +26 -0
  14. package/architecture/runtime-resume-lineage.json +23 -0
  15. package/architecture/stage-capsule-qualification.json +2 -2
  16. package/architecture/universal-workflow-bootstrap.json +10 -25
  17. package/architecture/universal-workflow-capability-policy.json +61 -0
  18. package/architecture/universal-workflow-fault-campaign.json +18 -24
  19. package/architecture/workflow-taxonomy.json +0 -11
  20. package/contracts/fixtures/{v4-runtime-ref-resume-authority-v1 → runtime-resume-lineage-v2}/scenario.json +2 -3
  21. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +2 -2
  22. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  23. package/contracts/promotion-invocation-v1.schema.json +0 -44
  24. package/contracts/promotion-request-v1.schema.json +0 -39
  25. package/contracts/runtime-resume-lineage-v2.schema.json +182 -0
  26. package/dist/site/buildchain-contract.json +472 -361
  27. package/dist/site/buildchain-site.json +99 -99
  28. package/dist/site/capability-registry.json +3 -3
  29. package/dist/site/cli-registry.json +4 -4
  30. package/dist/site/controller-registry.json +94 -78
  31. package/dist/site/kfd-claims.json +224 -343
  32. package/dist/site/kfd-upstream-aggregate.json +1 -1
  33. package/dist/site/manual-registry.json +15 -15
  34. package/dist/site/node-api-registry.json +239 -354
  35. package/dist/site/page-registry.json +80 -80
  36. package/dist/site/public-surface-audit.json +203 -254
  37. package/dist/site/publication-authority-registry.json +1 -24
  38. package/dist/site/publication-registry.json +4 -4
  39. package/dist/site/release-provenance.json +1 -1
  40. package/dist/site/site-manifest.json +19 -19
  41. package/dist/site/workflow-registry.json +197 -357
  42. package/docs/MAP.md +3 -3
  43. package/docs/auditable-demo.md +4 -4
  44. package/docs/cli-reference.md +2 -2
  45. package/docs/code-organization.md +5 -4
  46. package/docs/controller-evidence.md +2 -2
  47. package/docs/dev-alpha-candidate-patrol.md +5 -5
  48. package/docs/dev-delivery-warrant.md +14 -24
  49. package/docs/engineering-housekeeper.md +3 -3
  50. package/docs/github-artifact-attestation.md +9 -12
  51. package/docs/github-governance-authority.md +4 -4
  52. package/docs/node-api-reference.md +153 -167
  53. package/docs/publication-artifacts.md +3 -4
  54. package/docs/publication-authority.md +2 -2
  55. package/docs/release-candidate.md +21 -27
  56. package/docs/release-governance.md +10 -10
  57. package/docs/release-promotion-request.md +11 -18
  58. package/docs/release-propagation.md +5 -6
  59. package/docs/release-tail-provider-plane.md +2 -3
  60. package/docs/reusable-build-surface.md +13 -7
  61. package/docs/runtime-entry.md +122 -0
  62. package/docs/runtime-train-validation.md +30 -41
  63. package/docs/v4-publication-rehearsal.md +5 -5
  64. package/docs/v4-stage-capsule.md +9 -10
  65. package/docs/web-surface-deployments.md +16 -20
  66. package/docs/workflow-catalog.md +0 -1
  67. package/package.json +6 -6
  68. package/packages/core/adoption/commands/init-repo.mjs +2 -2
  69. package/packages/core/adoption/cross-platform-adopter-qualification.js +2 -13
  70. package/packages/core/adoption/qualification/actions.js +3 -5
  71. package/packages/core/adoption/qualification/admission.js +2 -3
  72. package/packages/core/build/artifact/attestation.js +0 -1
  73. package/packages/core/build/artifact/contracts.js +1 -4
  74. package/packages/core/build/artifact/store.js +6 -5
  75. package/packages/core/build/artifact-signing.js +4 -10
  76. package/packages/core/build/binary/actions.js +15 -9
  77. package/packages/core/build/binary-publication-dispatch.js +2 -6
  78. package/packages/core/build/demo/action-context.js +2 -11
  79. package/packages/core/build/demo/binary-action.js +8 -10
  80. package/packages/core/build/gate/controller.js +0 -2
  81. package/packages/core/build/github-attestation/action.js +2 -7
  82. package/packages/core/build/github-attestation/admission.js +0 -8
  83. package/packages/core/build/github-attestation/transaction.js +1 -2
  84. package/packages/core/build/lifecycle/stage-action.js +2 -0
  85. package/packages/core/build/lifecycle/stage.js +6 -3
  86. package/packages/core/build/macos-credential-island/dmg-assembly.js +0 -2
  87. package/packages/core/build/macos-credential-island/lib.js +2 -6
  88. package/packages/core/build/plan/action-context.js +0 -7
  89. package/packages/core/build/plan/action.js +7 -11
  90. package/packages/core/build/plan/admission.js +6 -73
  91. package/packages/core/build/plan/configuration.js +1 -1
  92. package/packages/core/build/plan/environment.js +1 -1
  93. package/packages/core/build/plan/identity.js +1 -5
  94. package/packages/core/build/plan/resolve.js +7 -1
  95. package/packages/core/build/recovery/checkpoint.js +158 -0
  96. package/packages/core/build/recovery/transaction.js +51 -0
  97. package/packages/core/build/signing/authority-actions.js +2 -11
  98. package/packages/core/build/signing/control.js +0 -5
  99. package/packages/core/build/signing/controller-transaction.js +0 -1
  100. package/packages/core/build/signing/delegation.js +2 -4
  101. package/packages/core/build/signing/dispatch.js +10 -56
  102. package/packages/core/build/signing/intake.js +0 -4
  103. package/packages/core/build/signing/prepare.js +1 -1
  104. package/packages/core/build/signing/request.js +3 -8
  105. package/packages/core/build/source/checkout-action.js +6 -10
  106. package/packages/core/build/source/controller.js +1 -4
  107. package/packages/core/build/source/lifecycle.js +3 -13
  108. package/packages/core/build/stage-capsule/actions.js +3 -13
  109. package/packages/core/build/stage-capsule/campaign/resume.js +10 -5
  110. package/packages/core/build/stage-capsule/rehearsal/verify.js +3 -4
  111. package/packages/core/build/stage-capsule-resume-planner.js +0 -1
  112. package/packages/core/build/summary/aggregation.js +5 -5
  113. package/packages/core/build/summary/finalization.js +1 -1
  114. package/packages/core/build/verification/actions.js +3 -12
  115. package/packages/core/build/verification/runner.js +22 -20
  116. package/packages/core/consumer/floating-consumer-evidence.js +3 -21
  117. package/packages/core/consumer/floating-consumer-policy.js +2 -93
  118. package/packages/core/consumer/floating-consumer-release-passport.js +1 -34
  119. package/packages/core/consumer/policy-admission.js +1 -3
  120. package/packages/core/contracts/buildchain-contract.js +12 -146
  121. package/packages/core/contracts/workflow-yaml-contract.js +11 -1
  122. package/packages/core/dev-delivery/candidate/admission.js +3 -4
  123. package/packages/core/dev-delivery/candidate/coordinates.js +0 -8
  124. package/packages/core/dev-delivery/commands/dev-delivery-request.sh +5 -13
  125. package/packages/core/dev-delivery/commands/dev-delivery-source-proof-reuse.mjs +0 -3
  126. package/packages/core/dev-delivery/dev-delivery-contract-surface.js +4 -52
  127. package/packages/core/dev-delivery/dev-delivery-execution-transfer.js +2 -15
  128. package/packages/core/dev-delivery/native/action-context.js +4 -32
  129. package/packages/core/dev-delivery/native/provider-boundary.js +0 -2
  130. package/packages/core/dev-delivery/native/transactions.js +1 -2
  131. package/packages/core/dev-delivery/queue/reconciliation-action.js +6 -10
  132. package/packages/core/dev-delivery/source-proof/predicates.js +0 -6
  133. package/packages/core/dev-delivery/source-proof/reuse.js +0 -2
  134. package/packages/core/dev-delivery/source-proof/seal.js +0 -2
  135. package/packages/core/governance/alpha-candidate/action.js +1 -10
  136. package/packages/core/governance/audit/actions.js +1 -3
  137. package/packages/core/governance/audit/collection.js +1 -3
  138. package/packages/core/governance/audit/identity.js +3 -31
  139. package/packages/core/governance/audit/transactions.js +2 -4
  140. package/packages/core/governance/buildchain-publication-authority.js +0 -1
  141. package/packages/core/governance/commands/audit-github-governance.mjs +3 -2
  142. package/packages/core/governance/github-governance-authority.js +0 -5
  143. package/packages/core/governance/receipt-admission.js +0 -15
  144. package/packages/core/index.js +1 -1
  145. package/packages/core/observability/controller/identity.js +4 -5
  146. package/packages/core/observability/controller-evidence.js +5 -10
  147. package/packages/core/paper/commands/paper.mjs +6 -6
  148. package/packages/core/paper/operations/plans.js +2 -2
  149. package/packages/core/paper/operations/provisioning-validation.js +1 -1
  150. package/packages/core/paper/operations/scaffold-workflows.js +29 -12
  151. package/packages/core/paper/operations/scaffold.js +97 -69
  152. package/packages/core/paper/paper-agent-entry.js +0 -11
  153. package/packages/core/paper/paper-runtime-channels.js +21 -66
  154. package/packages/core/paper/paper-scaffold-content.js +1 -1
  155. package/packages/core/paper/paper.js +9 -5
  156. package/packages/core/paper/publication/candidate.js +0 -9
  157. package/packages/core/paper/publication-controller.js +2 -4
  158. package/packages/core/providers/github/artifact-attestation.js +1 -1
  159. package/packages/core/publication/authority/actions.js +9 -8
  160. package/packages/core/publication/authority/admission.js +0 -11
  161. package/packages/core/publication/authority/assembly.js +2 -7
  162. package/packages/core/publication/authority/control-plane.js +2 -2
  163. package/packages/core/publication/authority/governance.js +2 -9
  164. package/packages/core/publication/authority/request.js +7 -2
  165. package/packages/core/publication/authority/verification.js +3 -18
  166. package/packages/core/publication/binary/action.js +5 -7
  167. package/packages/core/publication/candidate/qualification-action.js +1 -6
  168. package/packages/core/publication/candidate/stage-capsules.js +1 -1
  169. package/packages/core/publication/npm/preview-action.js +9 -15
  170. package/packages/core/publication/oci/preview-actions.js +1 -10
  171. package/packages/core/publication/publication-artifact-candidate.js +2 -2
  172. package/packages/core/publication/publication-authority.js +2 -2
  173. package/packages/core/publication/publication-rehearsal-projection.js +3 -3
  174. package/packages/core/publication/settlement/actions.js +2 -11
  175. package/packages/core/release/binary/coordinates-action.js +0 -13
  176. package/packages/core/release/binary/coordinates.js +2 -19
  177. package/packages/core/release/commands/promotion-channel-router.mjs +12 -56
  178. package/packages/core/release/commands/resume-from-candidate-run.mjs +2 -3
  179. package/packages/core/release/dev-alpha-active-release-train.js +0 -5
  180. package/packages/core/release/line/action.js +2 -13
  181. package/packages/core/release/next-development/actions.js +2 -5
  182. package/packages/core/release/passport/consumer-validation.js +1 -28
  183. package/packages/core/release/promote-candidate/development-source.js +7 -8
  184. package/packages/core/release/promotion/actions.js +7 -38
  185. package/packages/core/release/promotion/admission.js +3 -50
  186. package/packages/core/release/promotion/candidate.js +2 -4
  187. package/packages/core/release/promotion/channel.js +13 -101
  188. package/packages/core/release/promotion/qualification-action.js +2 -13
  189. package/packages/core/release/promotion/routing.js +16 -81
  190. package/packages/core/release/promotion/selection.js +1 -9
  191. package/packages/core/release/promotion-request.js +1 -40
  192. package/packages/core/release/qualification/actions.js +0 -8
  193. package/packages/core/release/qualification/public-build.js +1 -1
  194. package/packages/core/release/recovery/candidate.js +15 -21
  195. package/packages/core/release/recovery/capsules.js +2 -10
  196. package/packages/core/release/recovery/lineage.js +305 -0
  197. package/packages/core/release/recovery/provenance.js +1 -2
  198. package/packages/core/release/recovery/publication.js +4 -14
  199. package/packages/core/release/recovery/readback.js +19 -32
  200. package/packages/core/release/recovery/runtime.js +4 -95
  201. package/packages/core/release/release-candidate-recovery.js +4 -9
  202. package/packages/core/release/release-candidate.js +2 -5
  203. package/packages/core/release/reseal/actions.js +3 -22
  204. package/packages/core/release/reseal/admission.js +0 -2
  205. package/packages/core/release/reseal/finalize-platform.js +0 -2
  206. package/packages/core/release/tail-reseal-github.js +1 -2
  207. package/packages/core/release/tail-reseal-receipt.js +0 -1
  208. package/packages/core/release/tail-reseal.js +2 -20
  209. package/packages/core/release/version-state.js +16 -13
  210. package/packages/core/runtime/buildchain-domain.wasm +0 -0
  211. package/packages/core/runtime/checkout-identity.js +0 -13
  212. package/packages/core/runtime/domain-wasm-artifact.js +2 -2
  213. package/packages/core/runtime/entry/actions.js +121 -0
  214. package/packages/core/runtime/entry/activation.js +86 -0
  215. package/packages/core/runtime/entry/github.js +55 -0
  216. package/packages/core/runtime/entry/recovery.js +37 -0
  217. package/packages/core/runtime/entry/selection.js +110 -0
  218. package/packages/core/web/controller.js +1 -1
  219. package/packages/core/web/publication-admission-action.js +1 -8
  220. package/packages/core/web/web-surface-publication-candidate.js +2 -5
  221. package/packages/core/workflow/admission/actions.js +6 -26
  222. package/packages/core/workflow/admission/recovery.js +3 -43
  223. package/packages/core/workflow/admission/transactions.js +8 -24
  224. package/packages/core/workflow/commands/buildchain-cli-help.mjs +1 -1
  225. package/packages/core/workflow/commands/universal-workflow-engine.mjs +2 -7
  226. package/packages/core/workflow/dogfood/actions.js +0 -17
  227. package/packages/core/workflow/engine/action.js +0 -5
  228. package/packages/core/workflow/engine/conformance.js +1 -1
  229. package/packages/core/workflow/engine/execution.js +2 -6
  230. package/packages/core/workflow/engine/identity.js +1 -6
  231. package/packages/core/workflow/engine/release-environment.js +11 -35
  232. package/packages/core/workflow/engine/release-promotion.js +2 -2
  233. package/packages/core/workflow/settlement/actions.js +0 -12
  234. package/packages/core/workflow/universal-self-dogfood.js +2 -16
  235. package/packages/core/workflow/universal-workflow-bootstrap.js +16 -241
  236. package/packages/core/workflow/workflow-taxonomy.mjs +2 -2
  237. package/scripts/check-dev-delivery-actions.mjs +17 -8
  238. package/scripts/check-floating-consumer-policy-contract.mjs +6 -6
  239. package/scripts/check-inventory.mjs +1 -10
  240. package/scripts/check-public-dogfood-contract.mjs +34 -21
  241. package/scripts/check-release-topology.mjs +2 -6
  242. package/scripts/check-runtime-entry.mjs +133 -0
  243. package/scripts/check-universal-workflow-bootstrap.mjs +45 -281
  244. package/scripts/check-workflows.sh +0 -7
  245. package/scripts/generate-bootstrap-admission.mjs +1 -1
  246. package/scripts/generate-channel-promotion-workflow.mjs +4 -4
  247. package/scripts/inventory/binary.mjs +4 -4
  248. package/scripts/inventory/promotion.mjs +5 -3
  249. package/scripts/runtime-source-boundaries.mjs +70 -0
  250. package/scripts/site-capability-metadata.mjs +2 -2
  251. package/scripts/workflow-action-graph.mjs +5 -18
  252. package/scripts/workflow-self-reference.mjs +20 -0
  253. package/templates/native-dev-delivery.yml +4 -4
  254. package/templates/universal-buildchain-bootstrap.yml +12 -2
  255. package/architecture/runtime-ref-resume-authority.json +0 -64
  256. package/architecture/universal-workflow-train-admission.json +0 -76
  257. package/contracts/v4-runtime-ref-resume-authority-v1.schema.json +0 -235
  258. package/docs/v4-runtime-ref-resume-authority.md +0 -69
  259. package/packages/core/consumer/channel-selection.js +0 -211
  260. package/packages/core/consumer/commands/buildchain-channel-router.mjs +0 -81
  261. package/packages/core/consumer/invocation-selector.js +0 -4
  262. package/packages/core/consumer/runtime-ref-resume-authority.js +0 -621
  263. package/packages/core/consumer/workflow-definition-authority.js +0 -64
  264. package/packages/core/contracts/runtime-contract-action.js +0 -48
  265. package/packages/core/release/commands/promotion-identity-resolver.mjs +0 -77
  266. package/packages/core/release/commands/verify-promotion-router-binding.sh +0 -36
  267. package/packages/core/release/promotion/identities.js +0 -56
  268. package/packages/core/release/runtime-override-authorization.js +0 -242
  269. package/packages/core/runtime/commands/runtime-ref-core.mjs +0 -171
  270. package/packages/core/runtime/provider-closure.js +0 -60
  271. package/packages/core/runtime/runtime-selection-action.js +0 -34
  272. package/packages/core/runtime/runtime-selection.js +0 -136
  273. package/packages/core/runtime/workflow-runtime.js +0 -11
  274. package/packages/core/workflow/admission/review.js +0 -188
  275. package/packages/core/workflow/commands/universal-workflow-backflow.mjs +0 -26
  276. package/packages/core/workflow/installation.js +0 -33
  277. package/packages/core/workflow/settlement/backflow.js +0 -187
  278. package/scripts/generate-bootstrap-recovery.mjs +0 -94
  279. package/templates/bootstrap-recovery/actions/build/source/admit/action.yml +0 -17
  280. package/templates/bootstrap-recovery/actions/build/source/admit/dist/index.js +0 -63
  281. package/templates/bootstrap-recovery/actions/runtime/dependencies/install/action.yml +0 -18
  282. package/templates/bootstrap-recovery/actions/runtime/dependencies/install/dist/index.js +0 -63
  283. package/templates/bootstrap-recovery/actions/runtime/environment/prepare/action.yml +0 -21
  284. package/templates/bootstrap-recovery/actions/workflow/admission/inspect/action.yml +0 -27
  285. package/templates/bootstrap-recovery/actions/workflow/admission/inspect/dist/index.js +0 -64
  286. package/templates/bootstrap-recovery/actions/workflow/admission/review/action.yml +0 -15
  287. package/templates/bootstrap-recovery/actions/workflow/admission/review/dist/index.js +0 -65
  288. package/templates/bootstrap-recovery/actions/workflow/recovery/admit/action.yml +0 -47
  289. package/templates/bootstrap-recovery/actions/workflow/recovery/execute/action.yml +0 -48
  290. package/templates/bootstrap-recovery/actions/workflow/recovery/settle/action.yml +0 -54
  291. package/templates/bootstrap-recovery/actions/workflow/settlement/seal/action.yml +0 -17
  292. package/templates/bootstrap-recovery/actions/workflow/settlement/seal/dist/index.js +0 -65
  293. package/templates/bootstrap-recovery/manifest.json +0 -68
  294. package/templates/bootstrap-recovery/package.json +0 -9
  295. package/templates/universal-buildchain-bootstrap-recovery.yml +0 -115
@@ -1,34 +0,0 @@
1
- import { context, getOctokit } from "@actions/github";
2
- import { selectRuntime } from "./runtime-selection.js";
3
-
4
- export async function runtimeSelectionAction(core) {
5
- const request = {
6
- purpose: core.getInput("purpose", { required: true }),
7
- repository: core.getInput("repository", { required: true }),
8
- requestedRef: core.getInput("ref"),
9
- workflowSha: core.getInput("workflow-sha", { required: true }),
10
- workflowRef: core.getInput("workflow-ref"),
11
- };
12
- const result = await selectRuntime(request, {
13
- context,
14
- github: getOctokit(core.getInput("token", { required: true })),
15
- });
16
- for (const [name, value] of Object.entries(result))
17
- core.setOutput(name, value);
18
- if (request.purpose === "web")
19
- await core.summary
20
- .addHeading("Buildchain runtime")
21
- .addCodeBlock(
22
- JSON.stringify(
23
- {
24
- workflow: request.workflowRef,
25
- definition: request.workflowSha,
26
- ...result,
27
- },
28
- null,
29
- 2,
30
- ),
31
- "json",
32
- )
33
- .write();
34
- }
@@ -1,136 +0,0 @@
1
- import { repositoryActorPermission } from "../providers/github-permission.js";
2
- const exactSha = /^[0-9a-f]{40}$/iu;
3
- const train = /^train\/v4\/v4\.\d+\/[A-Za-z0-9._/-]+$/u;
4
- const channel = /^v4(?:-alpha)?$/u;
5
-
6
- export function classifyRuntime(ref) {
7
- if (/^v4(?:\.\d+\.\d+)?$/u.test(ref)) return "stable";
8
- if (/^v4-alpha$|^v4\.\d+\.\d+-alpha\.\d+$/u.test(ref)) return "alpha";
9
- if (exactSha.test(ref)) return "exact-sha";
10
- if (train.test(ref)) return "train";
11
- return "development";
12
- }
13
-
14
- function runtimeAdmission({
15
- purpose,
16
- repository,
17
- requestedRef = "",
18
- workflowSha,
19
- workflowRef = "",
20
- }) {
21
- if (!["publication", "web", "gate"].includes(purpose))
22
- throw new Error("Unknown runtime admission purpose");
23
- repository = String(repository || "").trim();
24
- if (!/^[\w.-]+\/[\w.-]+$/u.test(repository))
25
- throw new Error("Invalid Buildchain repository");
26
- const definition = String(workflowSha || "").toLowerCase();
27
- if (!exactSha.test(definition))
28
- throw new Error("Runtime requires the exact defining workflow SHA");
29
- const requested = String(requestedRef)
30
- .trim()
31
- .replace(/^refs\/heads\//u, "");
32
- const sameRepository = workflowRef.startsWith(
33
- `${repository}/.github/workflows/`,
34
- );
35
- if (!requested && purpose !== "gate" && !sameRepository)
36
- throw new Error(
37
- "Default runtime must belong to the defining workflow repository",
38
- );
39
- const sameDefinition = requested.toLowerCase() === definition;
40
- // These are different existing authority contracts: Web accepts an explicit
41
- // same-definition selection only for a closed release PR or trusted dispatch.
42
- const implicitDefinition =
43
- purpose === "gate"
44
- ? sameDefinition
45
- : purpose === "publication" && sameRepository && sameDefinition;
46
- const override = Boolean(
47
- requested && !channel.test(requested) && !implicitDefinition,
48
- );
49
- const decision =
50
- requested && channel.test(requested)
51
- ? "official-channel"
52
- : "workflow-definition";
53
- return {
54
- purpose,
55
- repository,
56
- workflowRef,
57
- definition,
58
- requested,
59
- sameRepository,
60
- sameDefinition,
61
- override,
62
- decision,
63
- };
64
- }
65
- async function authorizeRuntimeOverride(
66
- { purpose, requested, sameRepository, sameDefinition },
67
- { github, context },
68
- ) {
69
- if (!exactSha.test(requested) && !train.test(requested))
70
- throw new Error(
71
- "Runtime override must be a current v4 train or exact SHA; current channel selectors are v4 and v4-alpha",
72
- );
73
- const closedRelease =
74
- purpose === "web" &&
75
- sameRepository &&
76
- sameDefinition &&
77
- context.eventName === "pull_request" &&
78
- context.payload?.action === "closed";
79
- if (!closedRelease) {
80
- if (context.eventName !== "workflow_dispatch")
81
- throw new Error("Runtime override requires trusted workflow_dispatch");
82
- const permission = await repositoryActorPermission(
83
- { ...context.repo, actor: context.actor },
84
- github,
85
- );
86
- if (!["admin", "maintain", "write"].includes(permission))
87
- throw new Error("Runtime override requires write permission");
88
- }
89
- return closedRelease
90
- ? "closed-release-pr-shell-runtime"
91
- : "override-accepted";
92
- }
93
- export async function selectRuntime(request, { github, context }) {
94
- const admitted = runtimeAdmission(request);
95
- const { purpose, repository, workflowRef, definition, requested, override } =
96
- admitted;
97
- const decision = override
98
- ? await authorizeRuntimeOverride(admitted, { github, context })
99
- : admitted.decision;
100
- const selected = requested || definition;
101
- const fullRef =
102
- purpose === "web" && train.test(selected)
103
- ? `refs/heads/${selected}`
104
- : selected;
105
- const [owner, repo] = repository.split("/");
106
- const sha = exactSha.test(selected)
107
- ? selected.toLowerCase()
108
- : (await github.rest.repos.getCommit({ owner, repo, ref: fullRef })).data
109
- .sha;
110
- if (!exactSha.test(sha || ""))
111
- throw new Error("Runtime did not resolve to an exact commit");
112
- const coordinate = {
113
- "runtime-ref": selected,
114
- "runtime-sha": sha.toLowerCase(),
115
- };
116
- if (purpose === "gate") return coordinate;
117
- const result = {
118
- ...coordinate,
119
- "runtime-class": classifyRuntime(
120
- requested ||
121
- workflowRef
122
- .split("@")
123
- .at(-1)
124
- .replace(/^refs\/(?:heads|tags)\//u, ""),
125
- ),
126
- "runtime-override": String(override),
127
- "runtime-trust-decision": decision,
128
- };
129
- if (purpose === "web")
130
- Object.assign(result, {
131
- "runtime-full-ref": fullRef,
132
- "workflow-shell-ref": definition,
133
- "rollback-ref": definition,
134
- });
135
- return result;
136
- }
@@ -1,11 +0,0 @@
1
- export function exactWorkflowRuntime(value) {
2
- if (!/^[0-9a-f]{40}$/iu.test(value || ""))
3
- throw new Error("Called workflow requires an exact commit SHA");
4
- return value.toLowerCase();
5
- }
6
- export function exactWorkflowRuntimeAction(core) {
7
- core.setOutput(
8
- "sha",
9
- exactWorkflowRuntime(core.getInput("workflow-sha", { required: true })),
10
- );
11
- }
@@ -1,188 +0,0 @@
1
- import { workflowInstallationRoot } from "../installation.js";
2
- import path from "node:path";
3
- import fs from "node:fs";
4
- import { command, requireValue } from "../../runtime/action-process.mjs";
5
-
6
- function exactTime(value) {
7
- const time = new Date(value);
8
- requireValue(Number.isFinite(time.getTime()), "Review timestamp is invalid");
9
- return time.toISOString();
10
- }
11
- export function bootstrapVersionLine(
12
- runtimeRoot = workflowInstallationRoot(import.meta.url),
13
- ) {
14
- const version = JSON.parse(
15
- fs.readFileSync(path.join(runtimeRoot, "package.json"), "utf8"),
16
- ).version;
17
- const match = /^(\d+)\.(\d+)\.\d+(?:-[0-9A-Za-z.-]+)?$/u.exec(version);
18
- requireValue(
19
- match,
20
- "Bootstrap package version must declare its release line",
21
- );
22
- return {
23
- development: `dev/v${match[1]}/v${match[1]}.${match[2]}`,
24
- alpha: `alpha/v${match[1]}/v${match[1]}.${match[2]}`,
25
- };
26
- }
27
- export function reviewedCandidateEvidence({
28
- request,
29
- pr,
30
- reviews,
31
- checks,
32
- commit,
33
- line,
34
- observedAt,
35
- }) {
36
- const candidate = request.candidate;
37
- const matches =
38
- pr.head?.repo?.full_name === candidate.repository &&
39
- pr.number === candidate.reviewPullRequest;
40
- let kind;
41
- if (
42
- matches &&
43
- pr.head.sha === candidate.expectedSha &&
44
- pr.base?.ref === line.development
45
- )
46
- kind = "reviewed-head";
47
- else if (
48
- matches &&
49
- request.mode === "alpha" &&
50
- pr.merged === true &&
51
- pr.merge_commit_sha === candidate.expectedSha &&
52
- pr.base?.ref === line.alpha
53
- )
54
- kind = "protected-alpha-merge";
55
- requireValue(kind, "review does not bind the exact candidate runtime");
56
- const reviewedSha = pr.head.sha.toLowerCase();
57
- const latestReviews = new Map();
58
- for (const review of [...reviews].sort(
59
- (a, b) =>
60
- Date.parse(exactTime(a.submitted_at)) -
61
- Date.parse(exactTime(b.submitted_at)),
62
- )) {
63
- if (["APPROVED", "CHANGES_REQUESTED", "DISMISSED"].includes(review.state))
64
- latestReviews.set(review.user?.login?.toLowerCase(), review);
65
- }
66
- const latestChecks = new Map();
67
- for (const check of [...checks].sort((a, b) => (a.id || 0) - (b.id || 0))) {
68
- if (check.head_sha)
69
- requireValue(
70
- check.head_sha === candidate.expectedSha,
71
- "Check belongs to a different candidate",
72
- );
73
- latestChecks.set(check.name, check);
74
- }
75
- reviews = [...latestReviews.values()];
76
- checks = [...latestChecks.values()];
77
- requireValue(
78
- reviews.some(
79
- (review) =>
80
- review.state === "APPROVED" &&
81
- review.commit_id === reviewedSha &&
82
- review.user?.login?.toLowerCase() === "kungfu-origin",
83
- ),
84
- "Exact candidate requires independent kungfu-origin approval",
85
- );
86
- requireValue(
87
- checks.some(
88
- (check) =>
89
- check.name === "check" &&
90
- check.status === "completed" &&
91
- check.conclusion === "success",
92
- ),
93
- "Exact candidate requires successful check",
94
- );
95
- return {
96
- repository: candidate.repository,
97
- pullRequest: candidate.reviewPullRequest,
98
- headSha: reviewedSha,
99
- baseRef: pr.base.ref,
100
- approvals: reviews
101
- .filter(
102
- (review) =>
103
- review.state === "APPROVED" && review.commit_id === reviewedSha,
104
- )
105
- .map((review) => ({
106
- reviewer: review.user.login.toLowerCase(),
107
- commitSha: review.commit_id,
108
- submittedAt: exactTime(review.submitted_at),
109
- })),
110
- checks: checks
111
- .filter((check) => check.status === "completed" && check.conclusion)
112
- .map(({ name, status, conclusion }) => ({
113
- name,
114
- status,
115
- conclusion,
116
- commitSha: candidate.expectedSha,
117
- })),
118
- runtimeBinding: {
119
- kind,
120
- runtimeSha: candidate.expectedSha,
121
- parentShas: commit.parents.map(({ sha }) => sha.toLowerCase()),
122
- mergedAt:
123
- kind === "protected-alpha-merge" ? exactTime(pr.merged_at) : null,
124
- },
125
- observedAt: exactTime(observedAt),
126
- };
127
- }
128
- export function readCandidateReview(
129
- { request, workspace, runtimeRoot, candidateRoot, token },
130
- execute = command,
131
- ) {
132
- if (!token)
133
- throw new Error("Candidate review requires an explicit read credential");
134
- const { repository, expectedSha, reviewPullRequest } = request.candidate;
135
- const observed = execute("git", ["-C", candidateRoot, "rev-parse", "HEAD"], {
136
- stdio: ["ignore", "pipe", "inherit"],
137
- })
138
- .trim()
139
- .toLowerCase();
140
- requireValue(
141
- observed === expectedSha,
142
- "Candidate checkout does not match its expected SHA",
143
- );
144
- const api = (endpoint, paginate = false) =>
145
- JSON.parse(
146
- execute(
147
- "gh",
148
- [
149
- "api",
150
- ...(paginate ? ["--paginate", "--slurp"] : []),
151
- "-H",
152
- "Accept: application/vnd.github+json",
153
- `repos/${repository}/${endpoint}`,
154
- ],
155
- {
156
- stdio: ["ignore", "pipe", "inherit"],
157
- env: { ...process.env, GH_TOKEN: token },
158
- },
159
- ),
160
- );
161
- const pr = api(`pulls/${reviewPullRequest}`);
162
- const reviews = api(`pulls/${reviewPullRequest}/reviews`, true).flat();
163
- const checks = api(
164
- `commits/${expectedSha}/check-runs?per_page=100`,
165
- true,
166
- ).flatMap((page) => page.check_runs);
167
- const commit = api(`git/commits/${expectedSha}`);
168
- fs.mkdirSync(path.join(workspace, ".buildchain"), { recursive: true });
169
- for (const [name, value] of Object.entries({
170
- pr,
171
- reviews,
172
- checks,
173
- "runtime-commit": commit,
174
- }))
175
- fs.writeFileSync(
176
- path.join(workspace, `.buildchain/${name}.json`),
177
- JSON.stringify(value) + "\n",
178
- );
179
- return reviewedCandidateEvidence({
180
- request,
181
- pr,
182
- reviews,
183
- checks,
184
- commit,
185
- line: bootstrapVersionLine(runtimeRoot),
186
- observedAt: new Date().toISOString(),
187
- });
188
- }
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env node
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import { upsertUniversalBackflow } from "../settlement/backflow.js";
5
- const fail = message => { throw new Error(message); };
6
- async function main() {
7
- const request = JSON.parse(
8
- process.env.BUILDCHAIN_UNIVERSAL_REQUEST_JSON ||
9
- fail("request is required"),
10
- );
11
- const receipt = JSON.parse(
12
- process.env.BUILDCHAIN_UNIVERSAL_TERMINAL_RECEIPT_JSON ||
13
- fail("terminal receipt is required"),
14
- );
15
- const result = await upsertUniversalBackflow({
16
- request,
17
- receipt,
18
- token: process.env.GH_TOKEN || process.env.GITHUB_TOKEN,
19
- });
20
- process.stdout.write(`${JSON.stringify(result)}\n`);
21
- }
22
-
23
- const isMain =
24
- process.argv[1] &&
25
- fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
26
- if (isMain) await main();
@@ -1,33 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import { installationRoot } from "../runtime/installation-root.js";
5
-
6
- // A consumer-owned recovery package carries only trusted admission and settlement
7
- // actions. Locating it never gives those bytes candidate execution authority.
8
- export function workflowInstallationRoot(entryUrl) {
9
- let directory = path.dirname(fs.realpathSync(fileURLToPath(entryUrl)));
10
- for (;;) {
11
- const manifestPath = path.join(directory, "package.json");
12
- if (fs.existsSync(manifestPath)) {
13
- const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
14
- if (manifest.name === "@kungfu-tech/buildchain")
15
- return installationRoot(entryUrl);
16
- if (manifest.name === "buildchain-consumer-recovery") {
17
- const distribution = JSON.parse(
18
- fs.readFileSync(path.join(directory, "manifest.json"), "utf8"),
19
- );
20
- if (
21
- distribution.schema !==
22
- "buildchain.bootstrap-recovery-distribution/v1"
23
- )
24
- throw new Error("Unsupported consumer recovery distribution");
25
- return directory;
26
- }
27
- }
28
- const parent = path.dirname(directory);
29
- if (parent === directory)
30
- throw new Error("Workflow action is outside a declared distribution");
31
- directory = parent;
32
- }
33
- }
@@ -1,187 +0,0 @@
1
- import crypto from "node:crypto";
2
- import {
3
- validateUniversalWorkflowRequest,
4
- universalWorkflowRequestRoot,
5
- } from "../universal-workflow-bootstrap.js";
6
- const SHA = /^[0-9a-f]{40}$/u;
7
- const ROOT = /^sha256:[0-9a-f]{64}$/u;
8
-
9
- function fail(message) {
10
- throw new Error(message);
11
- }
12
-
13
- function canonical(value) {
14
- if (Array.isArray(value)) return value.map(canonical);
15
- if (value && typeof value === "object")
16
- return Object.fromEntries(
17
- Object.keys(value)
18
- .sort((left, right) => Buffer.from(left).compare(Buffer.from(right)))
19
- .map((key) => [key, canonical(value[key])]),
20
- );
21
- return value;
22
- }
23
-
24
- function contentRoot(domain, value) {
25
- const hash = crypto.createHash("sha256");
26
- hash.update(domain, "utf8");
27
- hash.update(Buffer.from([0]));
28
- hash.update(`${JSON.stringify(canonical(value))}\n`, "utf8");
29
- return `sha256:${hash.digest("hex")}`;
30
- }
31
-
32
- function validateTerminalReceipt(value, request) {
33
- if (
34
- value?.schema !==
35
- "kungfu-buildchain-v4-universal-workflow-terminal-receipt/v1" ||
36
- value.status !== "succeeded" ||
37
- value.runtime?.repository !== request.candidate.repository ||
38
- value.runtime?.sha !== request.candidate.expectedSha ||
39
- value.requestRoot !== universalWorkflowRequestRoot(request) ||
40
- !SHA.test(value.runtime?.sha || "") ||
41
- !ROOT.test(value.receiptRoot || "")
42
- )
43
- fail(
44
- "successful exact-candidate terminal receipt is required for backflow",
45
- );
46
- return value;
47
- }
48
-
49
- export function createUniversalBackflowPlan({
50
- request: requestValue,
51
- receipt,
52
- }) {
53
- const request = validateUniversalWorkflowRequest(requestValue);
54
- if (request.mode !== "train") fail("only Train delivery can create backflow");
55
- if (request.capability.id !== "release-candidate-promote")
56
- fail("only a release-candidate-promote delivery can create backflow");
57
- if (request.payload?.inputs?.["dry-run"] !== false)
58
- fail("only a non-dry-run release delivery can create backflow");
59
- const terminal = validateTerminalReceipt(receipt, request);
60
- const marker = `<!-- buildchain-universal-backflow:${request.candidate.expectedSha} -->`;
61
- const binding = {
62
- schema: "kungfu-buildchain-v4-universal-workflow-backflow/v1",
63
- repository: request.candidate.repository,
64
- pullRequest: request.candidate.reviewPullRequest,
65
- baseRef: "dev/v4/v4.1",
66
- trainSha: request.candidate.expectedSha,
67
- consumerRepository: request.consumer.repository,
68
- consumerSha: request.consumer.sourceSha,
69
- requestRoot: terminal.requestRoot,
70
- terminalReceiptRoot: terminal.receiptRoot,
71
- };
72
- const backflowRoot = contentRoot("universal-workflow-backflow", binding);
73
- return {
74
- ...binding,
75
- marker,
76
- backflowRoot,
77
- body: [
78
- marker,
79
- "## Universal Train backflow",
80
- "",
81
- `- Train SHA: \`${binding.trainSha}\``,
82
- `- Consumer: \`${binding.consumerRepository}@${binding.consumerSha}\``,
83
- `- Request root: \`${binding.requestRoot}\``,
84
- `- Terminal receipt root: \`${binding.terminalReceiptRoot}\``,
85
- `- Backflow root: \`${backflowRoot}\``,
86
- "",
87
- "This receipt binds a successful consumer delivery to the protected Train-to-dev backflow PR; it does not designate the Train candidate as a Buildchain release.",
88
- ].join("\n"),
89
- };
90
- }
91
-
92
- function githubHeaders(token) {
93
- return {
94
- accept: "application/vnd.github+json",
95
- authorization: `Bearer ${token}`,
96
- "content-type": "application/json",
97
- "user-agent": "buildchain-universal-backflow",
98
- "x-github-api-version": "2022-11-28",
99
- };
100
- }
101
-
102
- async function githubJson({ path, method = "GET", token, body, fetchImpl }) {
103
- const api = String(
104
- process.env.GITHUB_API_URL || "https://api.github.com",
105
- ).replace(/\/+$/u, "");
106
- const response = await fetchImpl(`${api}${path}`, {
107
- method,
108
- headers: githubHeaders(token),
109
- body: body === undefined ? undefined : JSON.stringify(body),
110
- });
111
- const text = await response.text();
112
- const value = text ? JSON.parse(text) : {};
113
- if (!response.ok)
114
- fail(
115
- `GitHub API ${method} ${path} failed with ${response.status}: ${value.message || text}`,
116
- );
117
- return value;
118
- }
119
-
120
- export async function upsertUniversalBackflow({
121
- request,
122
- receipt,
123
- token,
124
- fetchImpl = globalThis.fetch,
125
- }) {
126
- const admitted = validateUniversalWorkflowRequest(request);
127
- if (
128
- admitted.mode !== "train" ||
129
- admitted.capability.id !== "release-candidate-promote" ||
130
- admitted.payload?.inputs?.["dry-run"] !== false
131
- ) {
132
- return {
133
- schema: "kungfu-buildchain-v4-universal-workflow-backflow-result/v1",
134
- action: "skipped",
135
- reason: "not-a-successful-non-dry-run-release-delivery",
136
- backflowRoot: "",
137
- };
138
- }
139
- if (!token) fail("GH_TOKEN is required for protected backflow");
140
- if (typeof fetchImpl !== "function") fail("fetch is required for backflow");
141
- const plan = createUniversalBackflowPlan({ request: admitted, receipt });
142
- const encodedRepository = plan.repository;
143
- const pull = await githubJson({
144
- path: `/repos/${encodedRepository}/pulls/${plan.pullRequest}`,
145
- token,
146
- fetchImpl,
147
- });
148
- if (
149
- pull.state !== "open" ||
150
- pull.base?.ref !== plan.baseRef ||
151
- pull.head?.repo?.full_name !== plan.repository ||
152
- pull.head?.sha !== plan.trainSha
153
- )
154
- fail("backflow PR no longer binds the exact admitted Train candidate");
155
- const comments = await githubJson({
156
- path: `/repos/${encodedRepository}/issues/${plan.pullRequest}/comments?per_page=100`,
157
- token,
158
- fetchImpl,
159
- });
160
- const existing = comments.find((comment) =>
161
- String(comment.body || "").includes(plan.marker),
162
- );
163
- const comment = existing
164
- ? await githubJson({
165
- path: `/repos/${encodedRepository}/issues/comments/${existing.id}`,
166
- method: "PATCH",
167
- token,
168
- body: { body: plan.body },
169
- fetchImpl,
170
- })
171
- : await githubJson({
172
- path: `/repos/${encodedRepository}/issues/${plan.pullRequest}/comments`,
173
- method: "POST",
174
- token,
175
- body: { body: plan.body },
176
- fetchImpl,
177
- });
178
- return {
179
- schema: "kungfu-buildchain-v4-universal-workflow-backflow-result/v1",
180
- action: existing ? "updated" : "created",
181
- pullRequest: plan.pullRequest,
182
- trainSha: plan.trainSha,
183
- terminalReceiptRoot: plan.terminalReceiptRoot,
184
- backflowRoot: plan.backflowRoot,
185
- commentUrl: comment.html_url,
186
- };
187
- }