@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
@@ -11,7 +11,7 @@ const DEFAULT_ROOT = path.resolve(
11
11
  );
12
12
  const CALLER_PATH = ".github/workflows/self-build-public-consumer-dogfood.yml";
13
13
  const REUSABLE_PATH = ".github/workflows/public-build-stage-capsule-canary.yml";
14
- export const PUBLIC_DOGFOOD_ALPHA_REF = "v4-alpha";
14
+ export const PUBLIC_DOGFOOD_ENTRY_REF = "v4";
15
15
  const PRIVATE_CONSUMER = ["buildchain", "self", "dogfood"].join("-");
16
16
  const PRIVATE_SHADOW = ["kungfu", "shadow"].join("-");
17
17
 
@@ -21,6 +21,11 @@ export function expectedPublicDogfoodWorkflow(validationRef) {
21
21
  on:
22
22
  pull_request:
23
23
  workflow_dispatch:
24
+ inputs:
25
+ runtime-ref:
26
+ description: Transient runtime selected by the public entry.
27
+ type: string
28
+ default: ""
24
29
 
25
30
  permissions:
26
31
  contents: read
@@ -29,6 +34,7 @@ jobs:
29
34
  dogfood:
30
35
  uses: kungfu-systems/buildchain/.github/workflows/public-build-stage-capsule-canary.yml@${validationRef}
31
36
  with:
37
+ runtime-ref: \${{ inputs.runtime-ref }}
32
38
  consumer: buildchain
33
39
  node-version: "24"
34
40
  go-version: "1.25.x"
@@ -83,7 +89,7 @@ function assertReusableWorkflow(root) {
83
89
  const nodePath = `actions/build/stage-capsule/${CANARY_NODES[phase]}`;
84
90
  const call = workflow.jobs?.[phase]?.steps?.at(-1);
85
91
  if (
86
- call?.uses !== `./.buildchain/workflow-shell/${nodePath}` ||
92
+ call?.uses !== `./.buildchain/runtime/${nodePath}` ||
87
93
  call.with?.["workflow-sha"] !== "${{ job.workflow_sha }}" ||
88
94
  call.with?.["request-json"] !== "${{ toJSON(inputs) }}"
89
95
  )
@@ -94,18 +100,19 @@ function assertReusableWorkflow(root) {
94
100
  });
95
101
  const qualification = YAML.parse(nodes[1]);
96
102
  const steps = qualification.runs.steps;
97
- const prepare = steps.findIndex((step) => step.id === "buildchain-runtime");
98
103
  const consumerNode = steps.findIndex((step) =>
99
104
  step.uses?.startsWith("actions/setup-node@"),
100
105
  );
101
- if (
102
- prepare < 0 ||
103
- prepare >= consumerNode ||
104
- steps[prepare].uses !==
105
- "./.buildchain/workflow-shell/actions/runtime/environment/prepare"
106
- )
106
+ const jobSteps = workflow.jobs.qualify.steps;
107
+ const prepare = jobSteps.findIndex(
108
+ (step) => step.uses === "$/actions/runtime/environment/prepare",
109
+ );
110
+ const node = jobSteps.findIndex((step) =>
111
+ step.uses?.endsWith("/stage-capsule/qualify"),
112
+ );
113
+ if (prepare < 0 || prepare >= node || consumerNode < 0)
107
114
  fail(
108
- "Canary must bind the Buildchain runtime before selecting the consumer Node version",
115
+ "Canary must prepare its selected runtime before the consumer toolchain",
109
116
  );
110
117
  if (
111
118
  steps[consumerNode].with?.["node-version"] !==
@@ -118,7 +125,7 @@ function assertReusableWorkflow(root) {
118
125
  "./.buildchain/runtime/actions/build/stage-capsule/qualify-consumer",
119
126
  );
120
127
  if (
121
- campaign?.with?.["workflow-sha"] !== "${{ steps.runtime.outputs.sha }}" ||
128
+ campaign?.with?.["workflow-sha"] !== "${{ env.BUILDCHAIN_RUNTIME_SHA }}" ||
122
129
  campaign?.with?.["request-json"] !== "${{ inputs.request-json }}" ||
123
130
  campaign?.with?.platform !== "${{ fromJSON(inputs.matrix-json).platform }}"
124
131
  )
@@ -235,9 +242,9 @@ function assertProtectedVerify(root) {
235
242
  const parsed = YAML.parse(verify);
236
243
  const nodePath = "actions/build/verification/repository/action.yml";
237
244
  if (
238
- parsed.jobs.check.needs !== "stage-capsule-checkpoints" ||
245
+ ![parsed.jobs.check.needs].flat().includes("stage-capsule-checkpoints") ||
239
246
  parsed.jobs.check.steps.at(-1).uses !==
240
- `./.buildchain/workflow-shell/${nodePath.replace(/\/action.yml$/, "")}`
247
+ `./.buildchain/runtime/${nodePath.replace(/\/action.yml$/, "")}`
241
248
  )
242
249
  fail(
243
250
  "Verify must bind the protected check node after Stage Capsule checkpoints",
@@ -245,7 +252,10 @@ function assertProtectedVerify(root) {
245
252
  const implementation = read(root, nodePath);
246
253
  const steps = YAML.parse(implementation).runs.steps;
247
254
  const qualify = steps.find((step) => step.id === "source-verification");
248
- if (qualify?.uses !== "./actions/build/verification/qualify-source")
255
+ if (
256
+ qualify?.uses !==
257
+ "./.buildchain/runtime/actions/build/verification/qualify-source"
258
+ )
249
259
  fail("Verify is missing its owned source qualification action");
250
260
  const transaction = read(root, "packages/core/build/verification/source.js");
251
261
  for (const required of [
@@ -271,10 +281,13 @@ function assertArchitecture(root) {
271
281
  );
272
282
  const dogfood = architecture.publicConsumerDogfood;
273
283
  const validationRef = dogfood?.validationRef;
274
- if (validationRef !== PUBLIC_DOGFOOD_ALPHA_REF)
275
- fail("architecture validationRef must use the floating v4-alpha channel");
284
+ if (validationRef !== PUBLIC_DOGFOOD_ENTRY_REF)
285
+ fail("architecture validationRef must use the public v4 entry");
276
286
  const caller = read(root, CALLER_PATH);
277
- if (caller !== expectedPublicDogfoodWorkflow(validationRef))
287
+ if (
288
+ JSON.stringify(YAML.parse(caller)) !==
289
+ JSON.stringify(YAML.parse(expectedPublicDogfoodWorkflow(validationRef)))
290
+ )
278
291
  fail(`${CALLER_PATH} must remain the exact thin public consumer caller`);
279
292
  if (JSON.stringify(architecture.campaign?.consumers) !== '["buildchain"]')
280
293
  fail(
@@ -285,7 +298,7 @@ function assertArchitecture(root) {
285
298
  dogfood.callerWorkflow !== CALLER_PATH ||
286
299
  dogfood.reusableWorkflow !==
287
300
  "kungfu-systems/buildchain/.github/workflows/public-build-stage-capsule-canary.yml" ||
288
- dogfood.runtimeBinding !== "job.workflow_sha" ||
301
+ dogfood.runtimeBinding !== "entry-selected-runtime" ||
289
302
  dogfood.consumerSourceBinding !== "github.sha" ||
290
303
  JSON.stringify(dogfood.executableStages) !==
291
304
  '["install","build","verify"]' ||
@@ -351,9 +364,9 @@ function assertPolicySources(root) {
351
364
  const agents = read(root, "AGENTS.md");
352
365
  for (const invariant of [
353
366
  "same public reusable-workflow contract as every other consumer",
354
- "No agent may add or restore a relative/self reusable-workflow call",
355
- "never solve recursion with an internal exception",
356
- "scripts/check-public-dogfood-contract.mjs",
367
+ "No repository-specific runtime selection or recovery exception",
368
+ "Normal self workflows",
369
+ "central entry resolves it once",
357
370
  "source-persisted exact commit SHA",
358
371
  "v4-alpha",
359
372
  ])
@@ -150,11 +150,7 @@ export function discoverReleaseAuthorityClosure() {
150
150
  [".js", ".mjs", ".cjs"],
151
151
  /(?:release-tail-provider-(?:adapters|plane)|create(?:GitHubReleaseAssets|SignedStaticChannel|SiteReleaseActivation|ReleasedEvidence)Adapter)/u,
152
152
  );
153
- const runtimeSelectors = matchingProductionFiles(
154
- [".github/workflows", "scripts", "packages/core"],
155
- [".yml", ".yaml", ".js", ".mjs", ".cjs"],
156
- /(?:promotion-runtime-sha|resume-buildchain-runtime-sha|BUILDCHAIN_(?:CURRENT_RUNTIME_SHA|RUNTIME_REF|RESUME_CANDIDATE_RUN_ID)|authorizeRuntimeSelection|scanRuntimeSelectorPersistence|release-candidate-adapter)/u,
157
- );
153
+ const runtimeSelectors = productionFiles("packages/core/runtime/entry", [".js"]).sort();
158
154
  const terminalProjections = matchingProductionFiles(
159
155
  [".github/workflows", "actions", "packages/core", "scripts"],
160
156
  [".yml", ".yaml", ".js", ".mjs", ".cjs"],
@@ -560,7 +556,7 @@ export function checkReleaseTopology() {
560
556
  );
561
557
  assert.deepEqual(
562
558
  publisher.jobs.map((job) => job.split("|", 1)[0]),
563
- ["apply", "qualify", "settle"],
559
+ ["apply", "execution-runtime", "qualify", "settle"],
564
560
  );
565
561
  }
566
562
  return actual;
@@ -0,0 +1,133 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import YAML from "yaml";
4
+ import { fileURLToPath } from "node:url";
5
+ import { auditRuntimeSourceBoundaries } from "./runtime-source-boundaries.mjs";
6
+
7
+ const prepare = "actions/runtime/environment/prepare/action.yml";
8
+ const preparation = "$/actions/runtime/environment/prepare";
9
+ const entryActions = new Set([
10
+ "$/actions/runtime/selection/resolve",
11
+ preparation,
12
+ "$/actions/runtime/environment/activate",
13
+ ]);
14
+ function yamlFiles(root, directory) {
15
+ return fs
16
+ .readdirSync(path.join(root, directory), { withFileTypes: true })
17
+ .flatMap((entry) => {
18
+ const file = `${directory}/${entry.name}`;
19
+ if (entry.isDirectory())
20
+ return ["node_modules", "dist"].includes(entry.name)
21
+ ? []
22
+ : yamlFiles(root, file);
23
+ return /\.ya?ml$/u.test(file) ? [file] : [];
24
+ });
25
+ }
26
+ function auditCheckout(step, { file, at, prepared }, issues) {
27
+ if (!step.uses?.startsWith("actions/checkout")) return 0;
28
+ const directory = step.with?.path || ".";
29
+ const acquired =
30
+ /^\.buildchain\/(?:runtime|workflow-shell|bootstrap|attester-runtime|authority-runtime|policy-runtime|release-tail-runtime)$/u.test(
31
+ directory,
32
+ );
33
+ if (acquired && (file !== prepare || directory !== ".buildchain/runtime"))
34
+ issues.push(`${at}: execution code acquisition belongs only to ${prepare}`);
35
+ if (prepared && directory === ".")
36
+ issues.push(`${at}: source checkout erases the prepared runtime`);
37
+ if (
38
+ file !== prepare &&
39
+ /(?:runtime[-_.]sha|job\.workflow_sha|BUILDCHAIN_RUNTIME_SHA)/u.test(
40
+ JSON.stringify(step.with || {}),
41
+ )
42
+ )
43
+ issues.push(`${at}: source checkout must not select execution code`);
44
+ return Number(acquired);
45
+ }
46
+ function auditAction(step, { file, at, prepared }, issues) {
47
+ const uses = step.uses || "";
48
+ if (uses.startsWith("$/") && !entryActions.has(uses))
49
+ issues.push(`${at}: business code must load from the selected runtime`);
50
+ if (
51
+ uses.startsWith("./actions/") ||
52
+ /^\.\/\.buildchain\/(?!runtime\/).*\/actions\//u.test(uses)
53
+ )
54
+ issues.push(`${at}: noncanonical business action location`);
55
+ if (
56
+ file.startsWith(".github/workflows/") &&
57
+ uses.startsWith("./.buildchain/runtime/actions/") &&
58
+ !prepared
59
+ )
60
+ issues.push(`${at}: business action runs before preparation`);
61
+ if (file.startsWith("actions/") && uses === preparation)
62
+ issues.push(`${at}: business composites cannot prepare a second runtime`);
63
+ }
64
+ function auditBusinessAcquisition(root, directory, issues) {
65
+ const absolute = path.join(root, directory);
66
+ if (!fs.existsSync(absolute)) return;
67
+ for (const entry of fs.readdirSync(absolute, { withFileTypes: true })) {
68
+ const file = `${directory}/${entry.name}`;
69
+ if (entry.isDirectory()) {
70
+ if (!["node_modules", "dist"].includes(entry.name))
71
+ auditBusinessAcquisition(root, file, issues);
72
+ continue;
73
+ }
74
+ if (
75
+ !/\.(?:[cm]?js|sh|py|ps1)$/u.test(file) ||
76
+ file.startsWith("packages/core/runtime/entry/")
77
+ )
78
+ continue;
79
+ const source = fs.readFileSync(path.join(root, file), "utf8");
80
+ if (/\.[cm]?js$/u.test(file))
81
+ issues.push(...auditRuntimeSourceBoundaries(source, file));
82
+ const runtime =
83
+ /\.buildchain\/(?:runtime|workflow-shell|promotion-router)|BUILDCHAIN_RUNTIME_(?:ROOT|SHA)/u.test(
84
+ source,
85
+ );
86
+ const acquisition =
87
+ /["'](?:clone|checkout)["']|git\s+(?:clone|checkout)/u.test(source);
88
+ if (runtime && acquisition)
89
+ issues.push(`${file}: business code cannot acquire an execution runtime`);
90
+ }
91
+ }
92
+ export function auditRuntimeEntry(root) {
93
+ const issues = [];
94
+ const files = [
95
+ ...yamlFiles(root, "actions"),
96
+ ...yamlFiles(root, ".github/workflows"),
97
+ ];
98
+ auditBusinessAcquisition(root, "packages/core", issues);
99
+ let acquisitions = 0;
100
+ for (const file of files) {
101
+ const doc = YAML.parse(fs.readFileSync(path.join(root, file), "utf8"));
102
+ for (const [job, node] of Object.entries(
103
+ doc.jobs || { action: doc.runs },
104
+ )) {
105
+ let preparations = 0;
106
+ for (const step of node?.steps || []) {
107
+ if (step.uses === preparation) preparations++;
108
+ const context = {
109
+ file,
110
+ at: `${file}:${job}:${step.id || step.name || step.uses}`,
111
+ prepared: preparations > 0,
112
+ };
113
+ auditAction(step, context, issues);
114
+ acquisitions += auditCheckout(step, context, issues);
115
+ }
116
+ if (preparations > 1)
117
+ issues.push(`${file}:${job}: runtime is prepared more than once`);
118
+ }
119
+ }
120
+ if (acquisitions !== 1)
121
+ issues.push(
122
+ `Expected exactly one execution-code acquisition owner; found ${acquisitions}`,
123
+ );
124
+ return { files: files.length, acquisitions, issues };
125
+ }
126
+ if (
127
+ process.argv[1] &&
128
+ path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
129
+ ) {
130
+ const result = auditRuntimeEntry(path.resolve(import.meta.dirname, ".."));
131
+ console.log(JSON.stringify(result));
132
+ if (result.issues.length) process.exitCode = 1;
133
+ }
@@ -1,288 +1,52 @@
1
1
  import assert from "node:assert/strict";
2
- import YAML from "yaml";
3
-
4
- import crypto from "node:crypto";
5
2
  import fs from "node:fs";
6
3
  import path from "node:path";
7
- import { execFileSync } from "node:child_process";
8
- import { fileURLToPath } from "node:url";
9
-
10
- const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
11
- const contract = JSON.parse(
12
- fs.readFileSync(
13
- path.join(root, "architecture/universal-workflow-bootstrap.json"),
14
- "utf8",
15
- ),
16
- );
17
- const admissionPolicy = JSON.parse(
18
- fs.readFileSync(
19
- path.join(root, "architecture/universal-workflow-train-admission.json"),
20
- "utf8",
21
- ),
22
- );
23
- const admissionObservedAt = Date.now();
24
- assert.ok(
25
- admissionObservedAt >= Date.parse(admissionPolicy.validFrom) &&
26
- admissionObservedAt < Date.parse(admissionPolicy.expiresAt),
27
- `release admission policy is outside its validity window (${admissionPolicy.validFrom} to ${admissionPolicy.expiresAt}); renew it through protected review before publishing`,
28
- );
29
- const fileRoot = (relative) =>
30
- `sha256:${crypto
31
- .createHash("sha256")
32
- .update(fs.readFileSync(path.join(root, relative)))
33
- .digest("hex")}`;
34
-
35
- const workflowRoot = path.join(root, ".github/workflows");
36
- const discovered = fs
37
- .readdirSync(workflowRoot)
38
- .filter((name) => /\.ya?ml$/u.test(name))
39
- .map((name) => ({
40
- path: `.github/workflows/${name}`,
41
- text: fs.readFileSync(path.join(workflowRoot, name), "utf8"),
42
- }))
43
- .filter((entry) => /(?:^|\n)\s*workflow_call:\s*(?:\n|$)/u.test(entry.text))
44
- .map((entry) => entry.path)
45
- .sort();
46
-
47
- assert.equal(
48
- contract.schema,
49
- "kungfu-buildchain-v4-universal-workflow-bootstrap/v1",
50
- );
51
- assert.deepEqual(
52
- contract.inventoryWorkflows,
53
- [...new Set(contract.inventoryWorkflows)].sort(),
54
- "inventoried public workflows must be sorted and duplicate-free",
55
- );
56
- assert.deepEqual(
57
- contract.inventoryWorkflows,
58
- discovered,
59
- "every active public workflow_call surface must be inventoried",
60
- );
61
- for (const relative of contract.inventoryWorkflows)
62
- assert.ok(
63
- fs.statSync(path.join(root, relative)).isFile(),
64
- `inventoried workflow is unavailable: ${relative}`,
65
- );
66
- assert.deepEqual(
67
- contract.bootstrapGovernedWorkflows,
68
- [...new Set(contract.bootstrapGovernedWorkflows)].sort(),
69
- "Bootstrap-governed workflows must be sorted and duplicate-free",
70
- );
71
- assert.equal(
72
- Object.hasOwn(contract, "migration"),
73
- false,
74
- "no historical facade regeneration authority",
75
- );
76
- assert.equal(
77
- Object.hasOwn(contract, "retiredWorkflowSurfaces"),
78
- false,
79
- "retired workflows must be absent",
80
- );
81
- const activeWorkflows = contract.inventoryWorkflows;
82
- assert.deepEqual(contract.bootstrapGovernedWorkflows, [
83
- contract.bootstrap.publicWorkflow,
84
- ]);
85
- assert.deepEqual(
86
- contract.directCapabilityWorkflows,
87
- discovered.filter(
88
- (relative) =>
89
- relative !== contract.bootstrap.publicWorkflow &&
90
- relative !== contract.bootstrap.consumerRecoveryWorkflow,
91
- ),
92
- );
93
- for (const relative of contract.directCapabilityWorkflows) {
94
- assert.doesNotMatch(
95
- fs.readFileSync(path.join(root, relative), "utf8"),
96
- /universal-request-json|universal-bootstrap:/u,
97
- `${relative}: use the independent Bootstrap API instead of a dual execution path`,
98
- );
99
- }
100
- assert.deepEqual(contract.configurationGovernedWorkflows, [
101
- ".github/workflows/.build.yml",
102
- ".github/workflows/build.yml",
103
- ]);
104
- for (const relative of contract.configurationGovernedWorkflows) {
105
- const source = fs.readFileSync(path.join(root, relative), "utf8");
106
- const inputBlock = source
107
- .split(" inputs:\n")[1]
108
- .split(" secrets:\n")[0];
109
- assert.deepEqual(
110
- [...inputBlock.matchAll(/^ ([a-z0-9-]+):$/gmu)].map(
111
- (match) => match[1],
112
- ),
113
- ["config-path"],
114
- );
115
- assert.doesNotMatch(source, /universal-request-json/u);
116
- }
117
- for (const relative of contract.bootstrapGovernedWorkflows) {
118
- assert.ok(
119
- contract.inventoryWorkflows.includes(relative),
120
- `Bootstrap-governed workflow is outside the inventory: ${relative}`,
121
- );
122
- const source = fs.readFileSync(path.join(root, relative), "utf8");
123
- assert.ok(
124
- relative === contract.bootstrap.publicWorkflow ||
125
- /uses:\s+(?:\.\/)?\.github\/workflows\/public-ops-bootstrap\.yml/u.test(
126
- source,
127
- ) ||
128
- /uses:\s+kungfu-systems\/buildchain\/\.github\/workflows\/public-ops-bootstrap\.yml@/u.test(
129
- source,
130
- ),
131
- `workflow is declared governed without a Bootstrap edge: ${relative}`,
132
- );
133
- }
4
+ import crypto from "node:crypto";
5
+ import YAML from "yaml";
6
+ import { auditRuntimeEntry } from "./check-runtime-entry.mjs";
134
7
 
135
- assert.deepEqual(contract.complexityBudget, {
136
- bootstrapAbis: 1,
137
- requestEnvelopes: 1,
138
- candidateResolvers: 1,
139
- candidateEngines: 1,
140
- terminalReceiptAuthorities: 1,
141
- perWorkflowBootstrapImplementations: 0,
142
- buildchainOnlySelfReleasePaths: 0,
143
- perIncidentConsumerEdits: 0,
144
- });
145
- assert.equal(contract.bootstrap.discoveryRefExecutionAuthority, false);
146
- assert.equal(contract.bootstrap.exactShaExecutionAuthority, true);
147
- assert.equal(contract.bootstrap.consumerSourceMutationPerIncident, false);
148
- assert.equal(contract.bootstrap.buildchainReleasePromotionPerIncident, false);
149
- assert.equal(contract.bootstrap.selfDogfoodUsesPublicContract, true);
150
- assert.equal(contract.bootstrap.recoveryDependsOnPublishedBuildchain, false);
151
- assert.equal(
152
- contract.bootstrap.reviewRuntimeBinding,
153
- "reviewed-head-or-protected-alpha-merge-to-exact-runtime",
154
- );
155
- assert.deepEqual(
156
- contract.capabilityAdapters.map(({ id }) => id).sort(),
157
- [...admissionPolicy.allowedCapabilities].sort(),
158
- "every admitted capability must have one real candidate adapter",
159
- );
160
- for (const adapter of contract.capabilityAdapters) {
161
- assert.match(adapter.execution, /^exact-candidate-/u);
162
- assert.ok(adapter.payloadSchema.endsWith("/v1"));
8
+ const root = path.resolve(import.meta.dirname, "..");
9
+ const read = file => fs.readFileSync(path.join(root, file), "utf8");
10
+ const json = file => JSON.parse(read(file));
11
+ const parse = file => YAML.parse(read(file));
12
+ const contract = json("architecture/universal-workflow-bootstrap.json");
13
+ const policy = json("architecture/universal-workflow-capability-policy.json");
14
+ const files = fs.readdirSync(path.join(root, ".github/workflows")).filter(f => /\.ya?ml$/u.test(f)).map(f => `.github/workflows/${f}`);
15
+ const reusable = files.filter(f => parse(f).on?.workflow_call).sort();
16
+ assert.deepEqual(contract.inventoryWorkflows, reusable, "Every reusable API must have an owner");
17
+ assert.deepEqual([...contract.directCapabilityWorkflows, ...contract.bootstrapGovernedWorkflows].sort(), reusable, "Capabilities and bootstrap must partition the APIs");
18
+ assert.equal(contract.bootstrap.runtimeEntry, "architecture/runtime-entry.json");
19
+ assert.equal(contract.bootstrap.runtimeRecovery, "same-public-entry-with-transient-runtime");
20
+ assert.equal(contract.bootstrap.entryRecovery, "upgrade-public-entry-and-full-rerun");
21
+ assert.deepEqual(auditRuntimeEntry(root).issues, []);
22
+ for (const retired of ["templates/bootstrap-recovery", "templates/universal-buildchain-bootstrap-recovery.yml", ".github/workflows/public-ops-bootstrap-recovery.yml"])
23
+ assert.equal(fs.existsSync(path.join(root, retired)), false, `Copied recovery code must remain retired: ${retired}`);
24
+ assert.deepEqual(contract.capabilityAdapters.map(a => a.id).sort(), [...policy.allowedCapabilities].sort());
25
+ assert.ok(!policy.allowedCapabilities.includes("workflow-contract"), "Validation alone is not capability execution");
26
+ const now = Date.now();
27
+ assert.ok(now >= Date.parse(policy.validFrom) && now < Date.parse(policy.expiresAt), "Capability admission policy requires protected renewal");
28
+ assert.deepEqual(policy.contractRoots, contract.bootstrap.admissionPolicySources.map(f => `sha256:${crypto.createHash("sha256").update(read(f)).digest("hex")}`).sort());
29
+ const workflow = parse(contract.bootstrap.publicWorkflow);
30
+ assert.deepEqual(Object.keys(workflow.jobs), ["execution-runtime", "admit", "execute", "settle"]);
31
+ for (const phase of ["admit", "execute", "settle"]) {
32
+ const job = workflow.jobs[phase];
33
+ assert.ok(job.needs.includes("execution-runtime"));
34
+ assert.ok(job.steps.some(s => s.uses === `./.buildchain/runtime/actions/workflow/bootstrap/${phase}`));
35
+ assert.ok(job.steps.every(s => s.uses && !s.run && !s.shell));
163
36
  }
164
- assert.ok(!admissionPolicy.allowedCapabilities.includes("workflow-contract"));
165
- assert.deepEqual(
166
- admissionPolicy.contractRoots,
167
- contract.bootstrap.admissionPolicySources.map(fileRoot).sort(),
168
- );
169
- assert.doesNotMatch(
170
- fs.readFileSync(
171
- path.join(root, contract.bootstrap.candidateEnginePath),
172
- "utf8",
173
- ),
174
- /request\.capability\.id\s*===\s*["']workflow-contract["']/u,
175
- "contract-only validation must not be admitted as successful execution",
176
- );
177
- const bootstrapSource = fs.readFileSync(
178
- path.join(root, contract.bootstrap.publicWorkflow),
179
- "utf8",
180
- );
181
- assert.doesNotMatch(
182
- bootstrapSource,
183
- /admission-policy-json:/u,
184
- "callers must not supply their own admission authority",
185
- );
186
- assert.doesNotMatch(bootstrapSource, /^ permissions:/mu);
187
- const parse = (relative) =>
188
- YAML.parse(fs.readFileSync(path.join(root, relative), "utf8"));
189
- const bootstrap = YAML.parse(bootstrapSource);
190
- assert.deepEqual(bootstrap.jobs.settle.needs, ["admit", "execute"]);
191
- const execute = parse("actions/workflow/bootstrap/execute/action.yml");
192
- const executor = execute.runs.steps.find((step) => step.id === "execute");
193
- assert.equal(
194
- executor.with["mutation-token"],
195
- "${{ inputs.secrets-buildchain-promotion-token }}",
196
- );
37
+ assert.ok(workflow.jobs.execute.needs.includes("admit"));
38
+ assert.ok(workflow.jobs.settle.needs.includes("execute"));
39
+ const executor = parse("actions/workflow/bootstrap/execute/action.yml").runs.steps.find(s => s.id === "execute");
40
+ assert.equal(executor.with["mutation-token"], "${{ inputs.secrets-buildchain-promotion-token }}");
197
41
  assert.equal(executor.with.token, "${{ github.token }}");
198
- const recovery = parse(contract.bootstrap.consumerRecoveryTemplate);
199
- assert.deepEqual(Object.keys(recovery.jobs), [
200
- "recovery-admit",
201
- "recovery-execute",
202
- "recovery-settle",
203
- ]);
204
- assert.equal(recovery.jobs["recovery-execute"].needs, "recovery-admit");
205
- assert.equal(recovery.jobs["recovery-execute"].permissions.contents, "write");
206
- assert.equal(
207
- recovery.on.workflow_call.outputs["result-json"].value,
208
- "${{ jobs.recovery-execute.outputs.result-json }}",
209
- );
210
- for (const [id, job] of Object.entries(recovery.jobs)) {
211
- assert.ok(
212
- job.steps.length <= 3,
213
- `${id}: recovery workflow contains implementation details`,
214
- );
215
- const node = job.steps.find((step) => step.id === "node");
216
- assert.equal(
217
- node.uses,
218
- `./.buildchain/workflow-shell/.buildchain/bootstrap-recovery/actions/workflow/recovery/${id.replace("recovery-", "")}`,
219
- );
220
- for (const step of job.steps) {
221
- assert.equal(
222
- Object.hasOwn(step, "run"),
223
- false,
224
- "Recovery workflow must dispatch owned nodes",
225
- );
226
- assert.ok(
227
- !step.uses?.startsWith("kungfu-systems/buildchain/"),
228
- "Recovery cannot depend on published Buildchain",
229
- );
230
- }
231
- }
232
- const recoveryAdmit = parse("actions/workflow/recovery/admit/action.yml").runs
233
- .steps;
234
- const reviewIndex = recoveryAdmit.findIndex((step) =>
235
- /independent review/.test(step.name || ""),
236
- );
237
- const installationIndex = recoveryAdmit.findIndex((step) =>
238
- step.uses?.endsWith("actions/runtime/environment/prepare"),
239
- );
240
- const admissionIndex = recoveryAdmit.findIndex((step) => step.id === "admit");
241
- assert.ok(
242
- reviewIndex >= 0 &&
243
- installationIndex > reviewIndex &&
244
- admissionIndex > installationIndex,
245
- "No candidate dependency or code may execute before independent review",
246
- );
247
- execFileSync(
248
- process.execPath,
249
- [path.join(root, "scripts/generate-bootstrap-recovery.mjs"), "--check"],
250
- { cwd: root, stdio: "pipe" },
251
- );
252
- const primaryTemplate = parse(contract.bootstrap.consumerTemplate);
253
- assert.ok(
254
- Object.values(primaryTemplate.jobs).some(
255
- (job) =>
256
- job.uses ===
257
- "kungfu-systems/buildchain/.github/workflows/public-ops-bootstrap.yml@v4",
258
- ),
259
- );
260
- const selfDogfood = parse(contract.bootstrap.selfDogfoodWorkflow);
261
- for (const channel of ["conformance", "alpha", "stable"]) {
262
- assert.equal(
263
- selfDogfood.jobs[`primary-${channel}`].uses,
264
- "./.github/workflows/public-ops-bootstrap.yml",
265
- );
266
- assert.equal(
267
- selfDogfood.jobs[`recovery-${channel}`].uses,
268
- "./.github/workflows/public-ops-bootstrap-recovery.yml",
269
- );
42
+ assert.doesNotMatch(read(contract.bootstrap.publicWorkflow), /admission-policy-json:/u);
43
+ const template = parse(contract.bootstrap.consumerTemplate);
44
+ assert.equal(template.jobs.bootstrap.uses, "kungfu-systems/buildchain/.github/workflows/public-ops-bootstrap.yml@v4");
45
+ assert.equal(template.jobs.bootstrap.with["runtime-ref"], "${{ inputs.runtime-ref }}");
46
+ const dogfood = parse(contract.bootstrap.selfDogfoodWorkflow);
47
+ for (const channel of ["conformance", "alpha", "stable"]) for (const mode of ["primary", "recovery"]) {
48
+ const job = dogfood.jobs[`${mode}-${channel}`];
49
+ assert.equal(job.uses, "kungfu-systems/buildchain/.github/workflows/public-ops-bootstrap.yml@v4");
50
+ assert.equal(job.with["runtime-ref"], mode === "primary" ? "${{ inputs.runtime-ref }}" : "${{ inputs.recovery-runtime-ref }}");
270
51
  }
271
-
272
- console.log(
273
- JSON.stringify({
274
- ok: true,
275
- schema: contract.schema,
276
- publicWorkflowCount: discovered.length,
277
- activePublicWorkflowCount: activeWorkflows.length,
278
- inventoriedWorkflowCount: contract.inventoryWorkflows.length,
279
- inventoryCoveragePercent: 100,
280
- governedWorkflowCount: contract.bootstrapGovernedWorkflows.length,
281
- governedCoveragePercent: Number(
282
- (
283
- (contract.bootstrapGovernedWorkflows.length / activeWorkflows.length) *
284
- 100
285
- ).toFixed(2),
286
- ),
287
- }),
288
- );
52
+ console.log(JSON.stringify({ ok: true, reusableWorkflowCount: reusable.length, runtimeAcquisitionOwners: 1 }));
@@ -1,11 +1,4 @@
1
1
  #!/bin/bash
2
2
  set -euo pipefail
3
3
 
4
- if command -v actionlint >/dev/null 2>&1; then
5
- find .github/workflows -maxdepth 1 -name '*.yml' -print0 | xargs -0 actionlint -color=false
6
- else
7
- find .github/workflows -maxdepth 1 -name '*.yml' -print0 | \
8
- xargs -0 go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 -color=false
9
- fi
10
-
11
4
  node scripts/check-dev-delivery-actions.mjs
@@ -13,7 +13,7 @@ const contract = JSON.parse(
13
13
  );
14
14
  const target = path.join(
15
15
  root,
16
- "architecture/universal-workflow-train-admission.json",
16
+ "architecture/universal-workflow-capability-policy.json",
17
17
  );
18
18
  const policy = JSON.parse(fs.readFileSync(target, "utf8"));
19
19
  policy.contractRoots = contract.bootstrap.admissionPolicySources