@kungfu-tech/buildchain 4.0.0 → 4.0.1-alpha.10

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 (228) hide show
  1. package/AGENTS.md +13 -5
  2. package/actions/promote-buildchain-ref/README.md +11 -6
  3. package/actions/release-tail/README.md +8 -0
  4. package/architecture/ci-lane-change-budget.json +187 -0
  5. package/architecture/decisions/0002-next-development-transition.md +101 -0
  6. package/architecture/decisions/0003-two-phase-delivery-warrant.md +152 -0
  7. package/architecture/internal-capabilities.json +219 -7
  8. package/architecture/maintainability-policy.json +246 -29
  9. package/architecture/release-tail-contract-inventory.json +5 -2
  10. package/architecture/v3-core-mechanism-inventory.json +91 -0
  11. package/architecture/v4-adopter-delivery-parity.json +32 -5
  12. package/architecture/v4-capability-state-machine-manifest.json +73 -0
  13. package/architecture/v4-compatibility-facts-parity.json +77 -0
  14. package/architecture/v4-delivery-authority-parity.json +250 -0
  15. package/architecture/v4-delivery-warrant-shadow-fixtures.json +41 -9
  16. package/architecture/v4-floating-consumer-policy.json +81 -0
  17. package/architecture/v4-floating-consumer-policy.md +32 -0
  18. package/architecture/v4-next-development-parity.json +192 -0
  19. package/architecture/v4-publication-rehearsal-parity.json +84 -0
  20. package/architecture/v4-release-train-parity.json +1 -0
  21. package/architecture/v4-runtime-ref-resume-authority.json +64 -0
  22. package/architecture/v4-stage-capsule-qualification.json +2 -2
  23. package/architecture/v4-tail-reseal-parity.json +150 -0
  24. package/bin/buildchain.mjs +32 -3
  25. package/bin/internal/adopter-delivery-cli.mjs +70 -0
  26. package/bin/internal/command-registry.mjs +3 -0
  27. package/bin/internal/compatibility-facts-cli.mjs +101 -0
  28. package/bin/internal/trust-release-release-handlers.mjs +5 -0
  29. package/contracts/dev-delivery-authority-v2.schema.json +662 -0
  30. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  31. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  32. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  33. package/contracts/fixtures/v4-adopter-delivery-v1/archive-template.json +19 -0
  34. package/contracts/fixtures/v4-adopter-delivery-v1/bootstrap-positive.json +93 -0
  35. package/contracts/fixtures/v4-adopter-delivery-v1/gate-positive.json +29 -0
  36. package/contracts/fixtures/v4-adopter-delivery-v1/gate-unknown-selector.json +26 -0
  37. package/contracts/fixtures/v4-adopter-delivery-v1/offline-vectors.json +50 -0
  38. package/contracts/fixtures/v4-compatibility-facts-v1/shared.json +1129 -0
  39. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +59 -0
  40. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/artifacts/product.bin +1 -0
  41. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/config/buildchain.toml +5 -0
  42. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/release-activation.json +1 -0
  43. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/signed-channel.json +1 -0
  44. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/evidence/qualification.json +1 -0
  45. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/candidate.json +5 -0
  46. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/release-passport.json +1 -0
  47. package/contracts/fixtures/v4-publication-rehearsal-v1/capsule.json +707 -0
  48. package/contracts/fixtures/v4-publication-rehearsal-v1/offline-vectors.json +27 -0
  49. package/contracts/fixtures/v4-runtime-ref-resume-authority-v1/scenario.json +15 -0
  50. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +229 -0
  51. package/contracts/next-development-request-v1.schema.json +66 -0
  52. package/contracts/next-development-transition-v1.schema.json +292 -0
  53. package/contracts/v4-adopter-delivery-v1.schema.json +81 -0
  54. package/contracts/v4-compatibility-facts-v1.schema.json +230 -0
  55. package/contracts/v4-floating-consumer-policy-receipt-v1.schema.json +107 -0
  56. package/contracts/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  57. package/contracts/v4-runtime-ref-resume-authority-v1.schema.json +235 -0
  58. package/contracts/v4-tail-reseal-v1.schema.json +276 -0
  59. package/dist/site/agent-index.json +5 -0
  60. package/dist/site/artifact-schemas.json +10 -0
  61. package/dist/site/buildchain-contract.json +1562 -44
  62. package/dist/site/buildchain-site.json +684 -42
  63. package/dist/site/capability-registry.json +17 -14
  64. package/dist/site/cli-registry.json +205 -3
  65. package/dist/site/controller-registry.json +62 -6
  66. package/dist/site/kfd-claims.json +551 -22
  67. package/dist/site/kfd-upstream-aggregate.json +1 -1
  68. package/dist/site/manual-registry.json +55 -9
  69. package/dist/site/node-api-registry.json +15247 -8690
  70. package/dist/site/page-registry.json +647 -29
  71. package/dist/site/public-surface-audit.json +876 -55
  72. package/dist/site/publication-authority-registry.json +44 -8
  73. package/dist/site/publication-registry.json +4 -4
  74. package/dist/site/release-provenance.json +26 -0
  75. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +662 -0
  76. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +199 -0
  77. package/dist/site/schemas/v4-adopter-delivery-v1.schema.json +81 -0
  78. package/dist/site/schemas/v4-compatibility-facts-v1.schema.json +230 -0
  79. package/dist/site/schemas/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  80. package/dist/site/site-manifest.json +37 -13
  81. package/dist/site/workflow-registry.json +200 -22
  82. package/docs/MAP.md +10 -2
  83. package/docs/cli-reference.md +404 -13
  84. package/docs/cli.md +8 -0
  85. package/docs/dev-alpha-candidate-patrol.md +8 -0
  86. package/docs/dev-delivery-qualification-landing-adr.md +251 -0
  87. package/docs/dev-delivery-warrant.md +361 -30
  88. package/docs/lifecycle-protocol.md +41 -0
  89. package/docs/next-development-transition.md +118 -0
  90. package/docs/node-api-reference.md +748 -322
  91. package/docs/release-tail-provider-plane.md +30 -0
  92. package/docs/reusable-build-surface.md +41 -0
  93. package/docs/runtime-train-validation.md +10 -0
  94. package/docs/v4-adopter-delivery.md +133 -0
  95. package/docs/v4-compatibility-facts.md +91 -0
  96. package/docs/v4-publication-rehearsal.md +130 -0
  97. package/docs/v4-runtime-ref-resume-authority.md +69 -0
  98. package/docs/v4-tail-reseal.md +73 -0
  99. package/docs/versioning.md +4 -2
  100. package/package.json +36 -6
  101. package/packages/core/adopter-delivery-passport.js +259 -0
  102. package/packages/core/adopter-delivery-vectors.js +158 -0
  103. package/packages/core/adopter-delivery-vectors.json +77 -0
  104. package/packages/core/artifact-signing.js +61 -0
  105. package/packages/core/buildchain-agent-manuals.js +3 -0
  106. package/packages/core/buildchain-compatibility-authority.js +336 -0
  107. package/packages/core/buildchain-compatibility-fact.js +394 -0
  108. package/packages/core/buildchain-compatibility-facts.json +217 -0
  109. package/packages/core/buildchain-compatibility-proof.js +566 -0
  110. package/packages/core/buildchain-config.js +150 -1
  111. package/packages/core/buildchain-contract.js +96 -143
  112. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  113. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  114. package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
  115. package/packages/core/buildchain-publication-authority.js +1 -0
  116. package/packages/core/channel-candidate.js +8 -0
  117. package/packages/core/channel-promotion-baseline.js +55 -0
  118. package/packages/core/ci-lane-change-budget.js +247 -0
  119. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  120. package/packages/core/dev-delivery-authority-candidate.js +270 -0
  121. package/packages/core/dev-delivery-authority-evidence.js +146 -0
  122. package/packages/core/dev-delivery-authority-landing.js +461 -0
  123. package/packages/core/dev-delivery-authority-observation.js +48 -0
  124. package/packages/core/dev-delivery-authority-qualification.js +591 -0
  125. package/packages/core/dev-delivery-authority-settlement.js +213 -0
  126. package/packages/core/dev-delivery-authority-state.js +583 -0
  127. package/packages/core/dev-delivery-candidate-identity.js +13 -0
  128. package/packages/core/dev-delivery-contract-surface.js +76 -0
  129. package/packages/core/dev-delivery-execution-failure.js +133 -0
  130. package/packages/core/dev-delivery-execution-transfer.js +592 -0
  131. package/packages/core/dev-delivery-landing-admission-core.js +119 -0
  132. package/packages/core/dev-delivery-landing-readback.js +598 -0
  133. package/packages/core/dev-delivery-landing-terminal-evidence.js +271 -0
  134. package/packages/core/dev-delivery-landing-testing-port.js +6 -0
  135. package/packages/core/dev-delivery-native-execution.js +110 -0
  136. package/packages/core/dev-delivery-native-proof.js +562 -0
  137. package/packages/core/dev-delivery-process-boundary.js +563 -0
  138. package/packages/core/dev-delivery-proof.js +37 -3
  139. package/packages/core/dev-delivery-provider-attempt.js +127 -0
  140. package/packages/core/dev-delivery-provider-heartbeat.js +382 -0
  141. package/packages/core/dev-delivery-warrant-cancellation.js +1 -0
  142. package/packages/core/dev-delivery-warrant-qualification.js +145 -0
  143. package/packages/core/dev-delivery-warrant-settlement.js +237 -36
  144. package/packages/core/dev-delivery-warrant-state.js +587 -0
  145. package/packages/core/dev-delivery-warrant.js +328 -370
  146. package/packages/core/github-governance-authority.js +1 -0
  147. package/packages/core/index.js +7 -0
  148. package/packages/core/kungfu-temporal-fact.js +557 -0
  149. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  150. package/packages/core/next-development-candidate-reservation.js +186 -0
  151. package/packages/core/next-development-controller.js +728 -0
  152. package/packages/core/next-development-projection.js +287 -0
  153. package/packages/core/next-development-transition.js +738 -0
  154. package/packages/core/paper-agent-entry.js +11 -5
  155. package/packages/core/paper.js +16 -5
  156. package/packages/core/publication-authority.js +5 -5
  157. package/packages/core/published-delivery-authority.js +266 -0
  158. package/packages/core/release-candidate-recovery.js +66 -11
  159. package/packages/core/release-candidate.js +79 -19
  160. package/packages/core/release-passport.js +271 -38
  161. package/packages/core/v4-adopter-delivery-parity.js +3 -3
  162. package/packages/core/v4-adopter-delivery.js +359 -0
  163. package/packages/core/v4-canonical-contracts.js +5 -0
  164. package/packages/core/v4-delivery-warrant-read-candidate.js +10 -3
  165. package/packages/core/v4-floating-consumer-evidence.js +338 -0
  166. package/packages/core/v4-floating-consumer-policy.js +569 -0
  167. package/packages/core/v4-floating-consumer-release-passport.js +153 -0
  168. package/packages/core/v4-publication-rehearsal-capsule.js +468 -0
  169. package/packages/core/v4-publication-rehearsal-provider-bindings.js +212 -0
  170. package/packages/core/v4-publication-rehearsal.js +481 -0
  171. package/packages/core/v4-runtime-ref-resume-authority.js +625 -0
  172. package/packages/core/v4-runtime-selector-persistence.js +228 -0
  173. package/packages/core/v4-tail-reseal-contract.js +26 -0
  174. package/packages/core/v4-tail-reseal-github.js +178 -0
  175. package/packages/core/v4-tail-reseal-receipt.js +225 -0
  176. package/packages/core/v4-tail-reseal.js +594 -0
  177. package/packages/core/workflow-yaml-contract.js +72 -2
  178. package/scripts/audit-publication-control-plane.mjs +31 -31
  179. package/scripts/buildchain-cli-help.mjs +41 -2
  180. package/scripts/check-ci-lane-change-budget.mjs +100 -0
  181. package/scripts/check-inventory.mjs +14 -3
  182. package/scripts/check-v4-floating-consumer-policy-contract.mjs +217 -0
  183. package/scripts/check-v4-public-dogfood-contract.mjs +6 -11
  184. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  185. package/scripts/dev-delivery-authority-command-adapters.mjs +206 -0
  186. package/scripts/dev-delivery-authority-provider.mjs +28 -0
  187. package/scripts/dev-delivery-authority.mjs +490 -0
  188. package/scripts/dev-delivery-native-run.mjs +177 -0
  189. package/scripts/dev-delivery-process-boundary.mjs +260 -0
  190. package/scripts/dev-delivery-proof.mjs +67 -2
  191. package/scripts/dev-delivery-provider-heartbeat.mjs +215 -0
  192. package/scripts/dev-delivery-source-proof-replay.mjs +153 -0
  193. package/scripts/dev-delivery-source-proof-reuse.mjs +547 -0
  194. package/scripts/dev-delivery-two-phase-resume.mjs +345 -0
  195. package/scripts/dev-delivery-two-phase.mjs +573 -0
  196. package/scripts/dev-delivery-warrant-options.mjs +266 -0
  197. package/scripts/dev-delivery-warrant-store.mjs +231 -0
  198. package/scripts/dev-delivery-warrant.mjs +232 -194
  199. package/scripts/dev-pr-auto-merge.mjs +37 -48
  200. package/scripts/dev-pr-delivery-warrant.mjs +216 -2
  201. package/scripts/dev-pr-prequeue-guard.mjs +399 -0
  202. package/scripts/dev-qualification-patrol.mjs +9 -9
  203. package/scripts/dispatch-artifact-signing-authority.mjs +1 -1
  204. package/scripts/ensure-github-release.mjs +3 -3
  205. package/scripts/generate-channel-build-workflow.mjs +3 -0
  206. package/scripts/generate-channel-promotion-workflow.mjs +114 -14
  207. package/scripts/generate-next-development-guidance.mjs +49 -0
  208. package/scripts/generate-release-candidate-passport.mjs +192 -32
  209. package/scripts/generate-site-bundle.mjs +69 -4
  210. package/scripts/init-repo.mjs +26 -4
  211. package/scripts/inspect-artifact-signing-requests.mjs +6 -0
  212. package/scripts/next-development-self-dogfood-harness.mjs +460 -0
  213. package/scripts/next-development-self-dogfood.mjs +597 -0
  214. package/scripts/next-development-transition.mjs +47 -0
  215. package/scripts/npm-publish-transaction.mjs +103 -91
  216. package/scripts/promotion-channel-router.mjs +4 -4
  217. package/scripts/release-candidate-anchor-provenance.mjs +99 -0
  218. package/scripts/release-tail.mjs +51 -3
  219. package/scripts/release-train-self-dogfood.mjs +94 -92
  220. package/scripts/resume-from-candidate-run.mjs +565 -41
  221. package/scripts/seal-artifact-signing-requests.mjs +6 -0
  222. package/scripts/site-capability-metadata.mjs +43 -0
  223. package/scripts/stable-candidate-qualification.mjs +9 -10
  224. package/scripts/v4-consumer-policy.mjs +231 -0
  225. package/scripts/v4-publication-rehearsal-fixture.mjs +144 -0
  226. package/scripts/v4-tail-reseal-macos-rehearsal.mjs +134 -0
  227. package/scripts/v4-tail-reseal.mjs +416 -0
  228. package/templates/native-dev-delivery.yml +143 -0
@@ -0,0 +1,338 @@
1
+ import crypto from "node:crypto";
2
+
3
+ export const V4_FLOATING_CONSUMER_POLICY =
4
+ "kungfu-buildchain-v4-floating-consumer-policy/v1";
5
+ export const V4_FLOATING_CONSUMER_RECEIPT =
6
+ "kungfu-buildchain-v4-floating-consumer-policy-receipt/v1";
7
+ export const V4_FLOATING_CONSUMER_CERTIFICATION =
8
+ "kungfu-buildchain-v4-floating-consumer-certification/v1";
9
+
10
+ const SHA256_ROOT = /^sha256:[0-9a-f]{64}$/u;
11
+ const ALPHA_RECOVERY_BOOTSTRAP = Object.freeze({
12
+ repository: "kungfu-systems/buildchain",
13
+ sourcePath: ".github/workflows/buildchain-ref-promotion-recovery.yml",
14
+ workflow: ".github/workflows/.release-candidate-promote.yml",
15
+ selector: "alpha/v4/v4.0",
16
+ });
17
+
18
+ function stableJson(value) {
19
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
20
+ if (value && typeof value === "object") {
21
+ return `{${Object.keys(value)
22
+ .sort()
23
+ .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`)
24
+ .join(",")}}`;
25
+ }
26
+ return JSON.stringify(value);
27
+ }
28
+
29
+ function documentRoot(value) {
30
+ return `sha256:${crypto
31
+ .createHash("sha256")
32
+ .update(stableJson(value))
33
+ .digest("hex")}`;
34
+ }
35
+
36
+ function normalizeWorkflowPath(value) {
37
+ const text = String(value || "").replace(/^\/+/, "");
38
+ return text.startsWith(".github/workflows/")
39
+ ? text
40
+ : `.github/workflows/${text}`;
41
+ }
42
+
43
+ function checker(failures) {
44
+ return (condition, code, message) => {
45
+ if (!condition) failures.push({ code, message });
46
+ };
47
+ }
48
+
49
+ function verifyIdentity(value, expected, check, label) {
50
+ if (expected.repository)
51
+ check(
52
+ value?.caller?.repository === expected.repository,
53
+ "caller-repository-mismatch",
54
+ `${label} caller repository mismatch`,
55
+ );
56
+ if (expected.sourceSha)
57
+ check(
58
+ value?.caller?.sourceSha === expected.sourceSha.toLowerCase(),
59
+ "caller-source-mismatch",
60
+ `${label} caller source mismatch`,
61
+ );
62
+ if (expected.invokedWorkflow)
63
+ check(
64
+ value?.invocation?.workflow ===
65
+ normalizeWorkflowPath(expected.invokedWorkflow),
66
+ "invoked-workflow-mismatch",
67
+ `${label} workflow mismatch`,
68
+ );
69
+ if (expected.resolvedRuntimeSha)
70
+ check(
71
+ value?.invocation?.resolvedRuntimeSha ===
72
+ expected.resolvedRuntimeSha.toLowerCase(),
73
+ "runtime-sha-mismatch",
74
+ `${label} runtime SHA mismatch`,
75
+ );
76
+ }
77
+
78
+ function verifyAuthorityFields(value, expected, check, label) {
79
+ for (const [field, actual, code, message] of [
80
+ ["policyRoot", value?.policy?.root, "policy-root-mismatch", "policy root"],
81
+ [
82
+ "scannerRoot",
83
+ value?.policy?.scannerRoot,
84
+ "scanner-root-mismatch",
85
+ "scanner root",
86
+ ],
87
+ [
88
+ "stableLockRoot",
89
+ value?.contractLocks?.stable?.root,
90
+ "stable-lock-root-mismatch",
91
+ "stable lock root",
92
+ ],
93
+ [
94
+ "alphaLockRoot",
95
+ value?.contractLocks?.alpha?.root,
96
+ "alpha-lock-root-mismatch",
97
+ "alpha lock root",
98
+ ],
99
+ [
100
+ "stableLockPath",
101
+ value?.contractLocks?.stable?.path,
102
+ "stable-lock-path-mismatch",
103
+ "stable lock path",
104
+ ],
105
+ [
106
+ "alphaLockPath",
107
+ value?.contractLocks?.alpha?.path,
108
+ "alpha-lock-path-mismatch",
109
+ "alpha lock path",
110
+ ],
111
+ ]) {
112
+ if (expected[field])
113
+ check(actual === expected[field], code, `${label} ${message} mismatch`);
114
+ }
115
+ }
116
+
117
+ function verifyFloatingSelector(value, check, label) {
118
+ const bootstrap =
119
+ value?.caller?.repository === ALPHA_RECOVERY_BOOTSTRAP.repository &&
120
+ value?.invocation?.sourcePath === ALPHA_RECOVERY_BOOTSTRAP.sourcePath &&
121
+ value?.invocation?.workflow === ALPHA_RECOVERY_BOOTSTRAP.workflow &&
122
+ value?.invocation?.visibleSelector === ALPHA_RECOVERY_BOOTSTRAP.selector &&
123
+ value?.invocation?.selectorClass === "protected-bootstrap" &&
124
+ value?.invocation?.channel === "alpha";
125
+ check(
126
+ value?.invocation?.selectorClass === "floating" || bootstrap,
127
+ "selector-class-invalid",
128
+ `${label} must bind a floating selector or the bounded protected alpha recovery bootstrap`,
129
+ );
130
+ check(
131
+ ["v4", "v4-alpha"].includes(value?.invocation?.visibleSelector) ||
132
+ bootstrap,
133
+ "selector-invalid",
134
+ `${label} selector must be v4, v4-alpha, or the bounded protected alpha recovery bootstrap`,
135
+ );
136
+ }
137
+
138
+ export function v4FloatingConsumerDocumentRoot(value) {
139
+ return documentRoot(value);
140
+ }
141
+
142
+ export function verifyV4FloatingConsumerPolicyReceipt(options = {}) {
143
+ const { receipt, receiptRoot = "", expectedReceiptRoot = "" } = options;
144
+ const failures = [];
145
+ const check = checker(failures);
146
+ check(
147
+ receipt?.schema === V4_FLOATING_CONSUMER_RECEIPT,
148
+ "receipt-contract-invalid",
149
+ `receipt must use ${V4_FLOATING_CONSUMER_RECEIPT}`,
150
+ );
151
+ check(
152
+ receipt?.status === "passed",
153
+ "receipt-not-passed",
154
+ "policy receipt status must be passed",
155
+ );
156
+ check(
157
+ Array.isArray(receipt?.failures) && receipt.failures.length === 0,
158
+ "receipt-retains-failures",
159
+ "passed receipt must not retain failures",
160
+ );
161
+ const computedRoot = receipt ? documentRoot(receipt) : "";
162
+ check(
163
+ SHA256_ROOT.test(String(receiptRoot || "")),
164
+ "receipt-root-invalid",
165
+ "policy receipt root must be a sha256 root",
166
+ );
167
+ check(
168
+ receiptRoot === computedRoot,
169
+ "receipt-root-mismatch",
170
+ "policy receipt root does not match its content",
171
+ );
172
+ if (expectedReceiptRoot)
173
+ check(
174
+ computedRoot === expectedReceiptRoot,
175
+ "receipt-authority-root-mismatch",
176
+ "policy receipt does not match the independently reconstructed receipt",
177
+ );
178
+ verifyIdentity(receipt, options, check, "policy receipt");
179
+ verifyAuthorityFields(receipt, options, check, "policy receipt");
180
+ verifyFloatingSelector(receipt, check, "policy receipt");
181
+ return { ok: failures.length === 0, failures, receiptRoot: computedRoot };
182
+ }
183
+
184
+ function defaultAuthority(options, receiptRoot) {
185
+ return {
186
+ receiptRoot: options.expectedReceiptRoot || receiptRoot,
187
+ policyRoot: options.policyRoot || "",
188
+ scannerRoot: options.scannerRoot || "",
189
+ contractLocks: {
190
+ stable: {
191
+ path: options.stableLockPath || "",
192
+ root: options.stableLockRoot || "",
193
+ },
194
+ alpha: {
195
+ path: options.alphaLockPath || "",
196
+ root: options.alphaLockRoot || "",
197
+ },
198
+ },
199
+ };
200
+ }
201
+
202
+ export function certifyV4FloatingConsumerPolicyReceipt(options = {}) {
203
+ const verification = verifyV4FloatingConsumerPolicyReceipt(options);
204
+ const certification = {
205
+ schema: V4_FLOATING_CONSUMER_CERTIFICATION,
206
+ status: verification.ok ? "certified" : "rejected",
207
+ receiptRoot: verification.receiptRoot,
208
+ caller: options.receipt?.caller || {},
209
+ invocation: options.receipt?.invocation || {},
210
+ policy: options.receipt?.policy || {},
211
+ contractLocks: options.receipt?.contractLocks || {},
212
+ authority:
213
+ options.authority || defaultAuthority(options, verification.receiptRoot),
214
+ failures: verification.failures,
215
+ };
216
+ return {
217
+ ok: verification.ok,
218
+ verification,
219
+ certification,
220
+ certificationRoot: documentRoot(certification),
221
+ };
222
+ }
223
+
224
+ function verifyCertificationAuthority(certification, expected, check) {
225
+ const authority = certification?.authority;
226
+ for (const [value, code, message] of [
227
+ [
228
+ certification?.policy?.root,
229
+ "policy-root-invalid",
230
+ "certified policy root",
231
+ ],
232
+ [
233
+ certification?.policy?.scannerRoot,
234
+ "scanner-root-invalid",
235
+ "certified scanner root",
236
+ ],
237
+ [
238
+ certification?.contractLocks?.stable?.root,
239
+ "stable-lock-root-invalid",
240
+ "certified stable lock root",
241
+ ],
242
+ [
243
+ certification?.contractLocks?.alpha?.root,
244
+ "alpha-lock-root-invalid",
245
+ "certified alpha lock root",
246
+ ],
247
+ ]) {
248
+ check(
249
+ SHA256_ROOT.test(String(value || "")),
250
+ code,
251
+ `${message} must be a sha256 root`,
252
+ );
253
+ }
254
+ check(
255
+ authority?.receiptRoot === certification?.receiptRoot,
256
+ "certification-authority-receipt-mismatch",
257
+ "certification authority must bind the certified receipt root",
258
+ );
259
+ check(
260
+ authority?.policyRoot === certification?.policy?.root,
261
+ "certification-authority-policy-mismatch",
262
+ "certification authority must bind the certified policy root",
263
+ );
264
+ check(
265
+ authority?.scannerRoot === certification?.policy?.scannerRoot,
266
+ "certification-authority-scanner-mismatch",
267
+ "certification authority must bind the certified scanner root",
268
+ );
269
+ for (const channel of ["stable", "alpha"]) {
270
+ check(
271
+ authority?.contractLocks?.[channel]?.path ===
272
+ certification?.contractLocks?.[channel]?.path &&
273
+ authority?.contractLocks?.[channel]?.root ===
274
+ certification?.contractLocks?.[channel]?.root,
275
+ `certification-authority-${channel}-lock-mismatch`,
276
+ `certification authority must bind the certified ${channel} lock`,
277
+ );
278
+ }
279
+ if (expected.expectedReceiptRoot)
280
+ check(
281
+ certification?.receiptRoot === expected.expectedReceiptRoot,
282
+ "receipt-authority-root-mismatch",
283
+ "certification receipt root does not match external authority",
284
+ );
285
+ }
286
+
287
+ export function verifyV4FloatingConsumerPolicyCertification(options = {}) {
288
+ const { certification, certificationRoot = "" } = options;
289
+ const failures = [];
290
+ const check = checker(failures);
291
+ check(
292
+ certification?.schema === V4_FLOATING_CONSUMER_CERTIFICATION,
293
+ "certification-contract-invalid",
294
+ `certification must use ${V4_FLOATING_CONSUMER_CERTIFICATION}`,
295
+ );
296
+ check(
297
+ certification?.status === "certified",
298
+ "certification-not-certified",
299
+ "certification status must be certified",
300
+ );
301
+ check(
302
+ Array.isArray(certification?.failures) &&
303
+ certification.failures.length === 0,
304
+ "certification-retains-failures",
305
+ "certified evidence must not retain failures",
306
+ );
307
+ const computedRoot = certification ? documentRoot(certification) : "";
308
+ check(
309
+ SHA256_ROOT.test(String(certificationRoot || "")),
310
+ "certification-root-invalid",
311
+ "certification root must be a sha256 root",
312
+ );
313
+ check(
314
+ certificationRoot === computedRoot,
315
+ "certification-root-mismatch",
316
+ "certification root does not match its content",
317
+ );
318
+ if (options.expectedCertificationRoot)
319
+ check(
320
+ certificationRoot === options.expectedCertificationRoot,
321
+ "certification-authority-root-mismatch",
322
+ "certification root does not match the workflow-certified root",
323
+ );
324
+ check(
325
+ SHA256_ROOT.test(String(certification?.receiptRoot || "")),
326
+ "receipt-root-invalid",
327
+ "certification must bind a receipt root",
328
+ );
329
+ verifyIdentity(certification, options, check, "certification");
330
+ verifyAuthorityFields(certification, options, check, "certification");
331
+ verifyCertificationAuthority(certification, options, check);
332
+ verifyFloatingSelector(certification, check, "certification");
333
+ return {
334
+ ok: failures.length === 0,
335
+ failures,
336
+ certificationRoot: computedRoot,
337
+ };
338
+ }