@kungfu-tech/buildchain 4.0.1-alpha.2 → 4.0.1-alpha.21

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 (203) hide show
  1. package/actions/release-tail/README.md +8 -0
  2. package/architecture/ci-lane-change-budget.json +187 -0
  3. package/architecture/decisions/0002-next-development-transition.md +101 -0
  4. package/architecture/decisions/0003-two-phase-delivery-warrant.md +152 -0
  5. package/architecture/internal-capabilities.json +211 -8
  6. package/architecture/maintainability-policy.json +113 -28
  7. package/architecture/release-tail-contract-inventory.json +5 -2
  8. package/architecture/v3-core-mechanism-inventory.json +91 -0
  9. package/architecture/v4-adopter-delivery-parity.json +32 -5
  10. package/architecture/v4-capability-state-machine-manifest.json +73 -0
  11. package/architecture/v4-compatibility-facts-parity.json +77 -0
  12. package/architecture/v4-delivery-authority-parity.json +250 -0
  13. package/architecture/v4-delivery-warrant-shadow-fixtures.json +41 -9
  14. package/architecture/v4-floating-consumer-policy.json +6 -0
  15. package/architecture/v4-next-development-parity.json +192 -0
  16. package/architecture/v4-publication-rehearsal-parity.json +84 -0
  17. package/architecture/v4-release-train-parity.json +1 -0
  18. package/architecture/v4-tail-reseal-parity.json +150 -0
  19. package/bin/buildchain.mjs +32 -3
  20. package/bin/internal/adopter-delivery-cli.mjs +70 -0
  21. package/bin/internal/command-registry.mjs +3 -0
  22. package/bin/internal/compatibility-facts-cli.mjs +101 -0
  23. package/contracts/dev-delivery-authority-v2.schema.json +662 -0
  24. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  25. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  26. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  27. package/contracts/fixtures/v4-adopter-delivery-v1/archive-template.json +19 -0
  28. package/contracts/fixtures/v4-adopter-delivery-v1/bootstrap-positive.json +93 -0
  29. package/contracts/fixtures/v4-adopter-delivery-v1/gate-positive.json +29 -0
  30. package/contracts/fixtures/v4-adopter-delivery-v1/gate-unknown-selector.json +26 -0
  31. package/contracts/fixtures/v4-adopter-delivery-v1/offline-vectors.json +50 -0
  32. package/contracts/fixtures/v4-compatibility-facts-v1/shared.json +1129 -0
  33. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +7 -1
  34. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/artifacts/product.bin +1 -0
  35. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/config/buildchain.toml +5 -0
  36. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/release-activation.json +1 -0
  37. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/signed-channel.json +1 -0
  38. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/evidence/qualification.json +1 -0
  39. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/candidate.json +5 -0
  40. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/release-passport.json +1 -0
  41. package/contracts/fixtures/v4-publication-rehearsal-v1/capsule.json +707 -0
  42. package/contracts/fixtures/v4-publication-rehearsal-v1/offline-vectors.json +27 -0
  43. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +229 -0
  44. package/contracts/next-development-request-v1.schema.json +66 -0
  45. package/contracts/next-development-transition-v1.schema.json +292 -0
  46. package/contracts/v4-adopter-delivery-v1.schema.json +81 -0
  47. package/contracts/v4-compatibility-facts-v1.schema.json +230 -0
  48. package/contracts/v4-floating-consumer-policy-receipt-v1.schema.json +4 -2
  49. package/contracts/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  50. package/contracts/v4-tail-reseal-v1.schema.json +276 -0
  51. package/dist/site/agent-index.json +5 -0
  52. package/dist/site/artifact-schemas.json +10 -0
  53. package/dist/site/buildchain-contract.json +1475 -27
  54. package/dist/site/buildchain-site.json +627 -31
  55. package/dist/site/capability-registry.json +17 -14
  56. package/dist/site/cli-registry.json +205 -3
  57. package/dist/site/kfd-claims.json +490 -16
  58. package/dist/site/kfd-upstream-aggregate.json +1 -1
  59. package/dist/site/manual-registry.json +52 -6
  60. package/dist/site/node-api-registry.json +14736 -8851
  61. package/dist/site/page-registry.json +593 -21
  62. package/dist/site/public-surface-audit.json +837 -48
  63. package/dist/site/publication-authority-registry.json +44 -8
  64. package/dist/site/publication-registry.json +4 -4
  65. package/dist/site/release-provenance.json +24 -0
  66. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +662 -0
  67. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +199 -0
  68. package/dist/site/schemas/v4-adopter-delivery-v1.schema.json +81 -0
  69. package/dist/site/schemas/v4-compatibility-facts-v1.schema.json +230 -0
  70. package/dist/site/schemas/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  71. package/dist/site/site-manifest.json +34 -10
  72. package/dist/site/workflow-registry.json +160 -10
  73. package/docs/MAP.md +8 -2
  74. package/docs/cli-reference.md +404 -13
  75. package/docs/cli.md +8 -0
  76. package/docs/dev-alpha-candidate-patrol.md +8 -0
  77. package/docs/dev-delivery-qualification-landing-adr.md +251 -0
  78. package/docs/dev-delivery-warrant.md +351 -38
  79. package/docs/next-development-transition.md +118 -0
  80. package/docs/node-api-reference.md +646 -293
  81. package/docs/release-tail-provider-plane.md +30 -0
  82. package/docs/v4-adopter-delivery.md +133 -0
  83. package/docs/v4-compatibility-facts.md +91 -0
  84. package/docs/v4-publication-rehearsal.md +130 -0
  85. package/docs/v4-tail-reseal.md +73 -0
  86. package/docs/versioning.md +4 -3
  87. package/package.json +34 -6
  88. package/packages/core/adopter-delivery-passport.js +259 -0
  89. package/packages/core/adopter-delivery-vectors.js +158 -0
  90. package/packages/core/adopter-delivery-vectors.json +77 -0
  91. package/packages/core/buildchain-agent-manuals.js +3 -0
  92. package/packages/core/buildchain-compatibility-authority.js +336 -0
  93. package/packages/core/buildchain-compatibility-fact.js +394 -0
  94. package/packages/core/buildchain-compatibility-facts.json +217 -0
  95. package/packages/core/buildchain-compatibility-proof.js +566 -0
  96. package/packages/core/buildchain-config.js +84 -0
  97. package/packages/core/buildchain-contract.js +96 -143
  98. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  99. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  100. package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
  101. package/packages/core/buildchain-publication-authority.js +1 -0
  102. package/packages/core/channel-candidate.js +8 -0
  103. package/packages/core/channel-promotion-baseline.js +55 -0
  104. package/packages/core/ci-lane-change-budget.js +247 -0
  105. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  106. package/packages/core/dev-delivery-authority-candidate.js +270 -0
  107. package/packages/core/dev-delivery-authority-evidence.js +146 -0
  108. package/packages/core/dev-delivery-authority-landing.js +461 -0
  109. package/packages/core/dev-delivery-authority-observation.js +48 -0
  110. package/packages/core/dev-delivery-authority-qualification.js +591 -0
  111. package/packages/core/dev-delivery-authority-settlement.js +213 -0
  112. package/packages/core/dev-delivery-authority-state.js +583 -0
  113. package/packages/core/dev-delivery-candidate-identity.js +13 -0
  114. package/packages/core/dev-delivery-contract-surface.js +76 -0
  115. package/packages/core/dev-delivery-execution-failure.js +133 -0
  116. package/packages/core/dev-delivery-execution-transfer.js +592 -0
  117. package/packages/core/dev-delivery-landing-admission-core.js +119 -0
  118. package/packages/core/dev-delivery-landing-readback.js +598 -0
  119. package/packages/core/dev-delivery-landing-terminal-evidence.js +271 -0
  120. package/packages/core/dev-delivery-landing-testing-port.js +6 -0
  121. package/packages/core/dev-delivery-native-execution.js +110 -0
  122. package/packages/core/dev-delivery-native-proof.js +562 -0
  123. package/packages/core/dev-delivery-process-boundary.js +563 -0
  124. package/packages/core/dev-delivery-provider-attempt.js +127 -0
  125. package/packages/core/dev-delivery-provider-heartbeat.js +382 -0
  126. package/packages/core/dev-delivery-warrant-cancellation.js +1 -0
  127. package/packages/core/dev-delivery-warrant-qualification.js +145 -0
  128. package/packages/core/dev-delivery-warrant-settlement.js +237 -36
  129. package/packages/core/dev-delivery-warrant-state.js +587 -0
  130. package/packages/core/dev-delivery-warrant.js +328 -370
  131. package/packages/core/github-governance-authority.js +1 -0
  132. package/packages/core/index.js +5 -0
  133. package/packages/core/kungfu-temporal-fact.js +557 -0
  134. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  135. package/packages/core/next-development-candidate-reservation.js +186 -0
  136. package/packages/core/next-development-controller.js +728 -0
  137. package/packages/core/next-development-projection.js +287 -0
  138. package/packages/core/next-development-transition.js +738 -0
  139. package/packages/core/paper-agent-entry.js +11 -5
  140. package/packages/core/paper.js +16 -5
  141. package/packages/core/published-delivery-authority.js +266 -0
  142. package/packages/core/release-candidate-recovery.js +70 -15
  143. package/packages/core/release-candidate.js +2 -2
  144. package/packages/core/release-passport.js +36 -9
  145. package/packages/core/v4-adopter-delivery-parity.js +3 -3
  146. package/packages/core/v4-adopter-delivery.js +359 -0
  147. package/packages/core/v4-canonical-contracts.js +5 -0
  148. package/packages/core/v4-delivery-warrant-read-candidate.js +10 -3
  149. package/packages/core/v4-floating-consumer-evidence.js +18 -4
  150. package/packages/core/v4-floating-consumer-policy.js +143 -20
  151. package/packages/core/v4-floating-consumer-release-passport.js +32 -5
  152. package/packages/core/v4-publication-rehearsal-capsule.js +468 -0
  153. package/packages/core/v4-publication-rehearsal-provider-bindings.js +212 -0
  154. package/packages/core/v4-publication-rehearsal.js +481 -0
  155. package/packages/core/v4-tail-reseal-contract.js +26 -0
  156. package/packages/core/v4-tail-reseal-github.js +178 -0
  157. package/packages/core/v4-tail-reseal-receipt.js +225 -0
  158. package/packages/core/v4-tail-reseal.js +594 -0
  159. package/packages/core/workflow-yaml-contract.js +24 -2
  160. package/scripts/buildchain-cli-help.mjs +41 -2
  161. package/scripts/check-ci-lane-change-budget.mjs +100 -0
  162. package/scripts/check-inventory.mjs +14 -3
  163. package/scripts/check-v4-floating-consumer-policy-contract.mjs +23 -4
  164. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  165. package/scripts/dev-delivery-authority-command-adapters.mjs +206 -0
  166. package/scripts/dev-delivery-authority-provider.mjs +28 -0
  167. package/scripts/dev-delivery-authority.mjs +490 -0
  168. package/scripts/dev-delivery-native-run.mjs +177 -0
  169. package/scripts/dev-delivery-process-boundary.mjs +260 -0
  170. package/scripts/dev-delivery-proof.mjs +67 -2
  171. package/scripts/dev-delivery-provider-heartbeat.mjs +215 -0
  172. package/scripts/dev-delivery-source-proof-replay.mjs +153 -0
  173. package/scripts/dev-delivery-source-proof-reuse.mjs +13 -97
  174. package/scripts/dev-delivery-two-phase-resume.mjs +345 -0
  175. package/scripts/dev-delivery-two-phase.mjs +573 -0
  176. package/scripts/dev-delivery-warrant-options.mjs +266 -0
  177. package/scripts/dev-delivery-warrant-store.mjs +231 -0
  178. package/scripts/dev-delivery-warrant.mjs +232 -194
  179. package/scripts/dev-pr-auto-merge.mjs +1 -1
  180. package/scripts/dev-pr-delivery-warrant.mjs +11 -0
  181. package/scripts/dev-qualification-patrol.mjs +9 -9
  182. package/scripts/dispatch-artifact-signing-authority.mjs +1 -1
  183. package/scripts/generate-channel-promotion-workflow.mjs +2 -2
  184. package/scripts/generate-next-development-guidance.mjs +49 -0
  185. package/scripts/generate-release-candidate-passport.mjs +152 -0
  186. package/scripts/generate-site-bundle.mjs +69 -4
  187. package/scripts/init-repo.mjs +22 -4
  188. package/scripts/next-development-self-dogfood-harness.mjs +460 -0
  189. package/scripts/next-development-self-dogfood.mjs +597 -0
  190. package/scripts/next-development-transition.mjs +47 -0
  191. package/scripts/npm-publish-transaction.mjs +2 -2
  192. package/scripts/promotion-channel-router.mjs +4 -4
  193. package/scripts/release-candidate-anchor-provenance.mjs +99 -0
  194. package/scripts/release-tail.mjs +51 -3
  195. package/scripts/release-train-self-dogfood.mjs +94 -92
  196. package/scripts/resume-from-candidate-run.mjs +557 -30
  197. package/scripts/site-capability-metadata.mjs +41 -0
  198. package/scripts/stable-candidate-qualification.mjs +9 -10
  199. package/scripts/v4-consumer-policy.mjs +5 -5
  200. package/scripts/v4-publication-rehearsal-fixture.mjs +144 -0
  201. package/scripts/v4-tail-reseal-macos-rehearsal.mjs +134 -0
  202. package/scripts/v4-tail-reseal.mjs +416 -0
  203. package/templates/native-dev-delivery.yml +143 -0
@@ -0,0 +1,416 @@
1
+ #!/usr/bin/env node
2
+
3
+ import crypto from "node:crypto";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { pathToFileURL } from "node:url";
7
+
8
+ import {
9
+ V4_TAIL_RESEAL_PLATFORMS,
10
+ normalizeV4TailResealRequest,
11
+ planV4TailReseal,
12
+ } from "../packages/core/v4-tail-reseal.js";
13
+ import { createV4TailResealReceipt } from "../packages/core/v4-tail-reseal-receipt.js";
14
+ import { validateV4TailResealGitHubEvidence } from "../packages/core/v4-tail-reseal-github.js";
15
+ import { v4ContentRoot } from "../packages/core/v4-canonical-contracts.js";
16
+
17
+ function flag(args, name, fallback = "") {
18
+ const index = args.indexOf(`--${name}`);
19
+ return index < 0 ? fallback : String(args[index + 1] || "");
20
+ }
21
+
22
+ function required(value, label) {
23
+ const normalized = String(value || "").trim();
24
+ if (!normalized) throw new Error(`${label} is required`);
25
+ return normalized;
26
+ }
27
+
28
+ function readJson(file, label = file) {
29
+ try {
30
+ return JSON.parse(fs.readFileSync(path.resolve(file), "utf8"));
31
+ } catch (error) {
32
+ throw new Error(`could not read ${label}: ${error.message}`);
33
+ }
34
+ }
35
+
36
+ function writeJson(file, value) {
37
+ const output = path.resolve(file);
38
+ fs.mkdirSync(path.dirname(output), { recursive: true });
39
+ fs.writeFileSync(output, `${JSON.stringify(value, null, 2)}\n`);
40
+ return output;
41
+ }
42
+
43
+ function sha256File(file) {
44
+ const hash = crypto.createHash("sha256");
45
+ const descriptor = fs.openSync(file, "r");
46
+ const buffer = Buffer.allocUnsafe(1024 * 1024);
47
+ try {
48
+ for (;;) {
49
+ const count = fs.readSync(descriptor, buffer, 0, buffer.length, null);
50
+ if (count === 0) break;
51
+ hash.update(buffer.subarray(0, count));
52
+ }
53
+ } finally {
54
+ fs.closeSync(descriptor);
55
+ }
56
+ return `sha256:${hash.digest("hex")}`;
57
+ }
58
+
59
+ function appendOutputs(values) {
60
+ if (!process.env.GITHUB_OUTPUT) return;
61
+ fs.appendFileSync(
62
+ process.env.GITHUB_OUTPUT,
63
+ `${Object.entries(values)
64
+ .map(([key, value]) => `${key}=${String(value)}`)
65
+ .join("\n")}\n`,
66
+ );
67
+ }
68
+
69
+ async function githubJson(repository, apiPath, token) {
70
+ const response = await fetch(
71
+ `https://api.github.com/repos/${repository}${apiPath}`,
72
+ {
73
+ headers: {
74
+ accept: "application/vnd.github+json",
75
+ authorization: `Bearer ${required(token, "GITHUB_TOKEN")}`,
76
+ "x-github-api-version": "2022-11-28",
77
+ },
78
+ },
79
+ );
80
+ if (!response.ok)
81
+ throw new Error(`GitHub API ${apiPath} failed: HTTP ${response.status}`);
82
+ return response.json();
83
+ }
84
+
85
+ async function pagedGithubItems(repository, apiPath, key, token) {
86
+ const values = [];
87
+ for (let page = 1; ; page += 1) {
88
+ const separator = apiPath.includes("?") ? "&" : "?";
89
+ const response = await githubJson(
90
+ repository,
91
+ `${apiPath}${separator}per_page=100&page=${page}`,
92
+ token,
93
+ );
94
+ const items = Array.isArray(response?.[key]) ? response[key] : [];
95
+ values.push(...items);
96
+ if (items.length < 100) return values;
97
+ }
98
+ }
99
+
100
+ async function admitFromGitHub(request) {
101
+ const token = required(process.env.GITHUB_TOKEN, "GITHUB_TOKEN");
102
+ const [
103
+ sourceCommit,
104
+ sourceRun,
105
+ sourceJobs,
106
+ sourceArtifacts,
107
+ signingRun,
108
+ signingArtifacts,
109
+ ] = await Promise.all([
110
+ githubJson(request.repository, `/git/commits/${request.source.sha}`, token),
111
+ githubJson(
112
+ request.repository,
113
+ `/actions/runs/${request.source.runId}`,
114
+ token,
115
+ ),
116
+ pagedGithubItems(
117
+ request.repository,
118
+ `/actions/runs/${request.source.runId}/jobs?filter=latest`,
119
+ "jobs",
120
+ token,
121
+ ),
122
+ pagedGithubItems(
123
+ request.repository,
124
+ `/actions/runs/${request.source.runId}/artifacts`,
125
+ "artifacts",
126
+ token,
127
+ ),
128
+ githubJson(
129
+ request.signing.authorityRepository,
130
+ `/actions/runs/${request.signing.authorityRunId}`,
131
+ token,
132
+ ),
133
+ pagedGithubItems(
134
+ request.signing.authorityRepository,
135
+ `/actions/runs/${request.signing.authorityRunId}/artifacts`,
136
+ "artifacts",
137
+ token,
138
+ ),
139
+ ]);
140
+ return validateV4TailResealGitHubEvidence({
141
+ request,
142
+ sourceCommit,
143
+ sourceRun,
144
+ sourceJobs,
145
+ sourceArtifacts,
146
+ signingRun,
147
+ signingArtifacts,
148
+ });
149
+ }
150
+
151
+ function locateManifest(root, platformId) {
152
+ const matches = [];
153
+ const visit = (directory) => {
154
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
155
+ const absolute = path.join(directory, entry.name);
156
+ if (entry.isDirectory()) visit(absolute);
157
+ else if (entry.name === "manifest.json") {
158
+ const value = readJson(absolute);
159
+ if (
160
+ value?.contract === "kungfu-buildchain-artifact" &&
161
+ value?.platform?.id === platformId
162
+ )
163
+ matches.push({ absolute, value });
164
+ }
165
+ }
166
+ };
167
+ visit(root);
168
+ if (matches.length !== 1)
169
+ throw new Error(
170
+ `expected exactly one ${platformId} manifest under ${root}, found ${matches.length}`,
171
+ );
172
+ return matches[0];
173
+ }
174
+
175
+ function resolvePayload(root, relative, platformId) {
176
+ const absolute = path.resolve(root, relative);
177
+ if (
178
+ !absolute.startsWith(`${root}${path.sep}`) ||
179
+ !fs.existsSync(absolute) ||
180
+ !fs.statSync(absolute).isFile()
181
+ )
182
+ throw new Error(`${platformId} manifest file is missing: ${relative}`);
183
+ return absolute;
184
+ }
185
+
186
+ export function verifyV4TailResealPlatform({
187
+ request,
188
+ platformId,
189
+ artifactRoot,
190
+ mode = "retained",
191
+ providerReadbackRoot = null,
192
+ } = {}) {
193
+ const normalized = normalizeV4TailResealRequest(request);
194
+ const platform = normalized.platforms.find(({ id }) => id === platformId);
195
+ if (!platform)
196
+ throw new Error(`tail reseal request does not bind platform ${platformId}`);
197
+ if (!new Set(["retained", "resealed"]).has(mode))
198
+ throw new Error(
199
+ "tail reseal verification mode must be retained or resealed",
200
+ );
201
+ if (mode === "resealed" && platformId !== "macos-arm64")
202
+ throw new Error("only macos-arm64 may produce a resealed byte set");
203
+ const root = path.resolve(artifactRoot || ".");
204
+ const { absolute: manifestPath, value: manifest } = locateManifest(
205
+ root,
206
+ platformId,
207
+ );
208
+ if (manifest.artifactName !== platform.artifactName)
209
+ throw new Error(`${platformId} manifest artifact name mismatch`);
210
+ if (
211
+ manifest.git?.repository !== normalized.repository ||
212
+ manifest.git?.sha !== normalized.source.sha ||
213
+ manifest.git?.treeSha !== normalized.source.treeSha
214
+ )
215
+ throw new Error(`${platformId} manifest source mismatch`);
216
+ if (
217
+ Number(manifest.git?.runId) !== normalized.source.runId ||
218
+ Number(manifest.git?.runAttempt) !== normalized.source.runAttempt
219
+ )
220
+ throw new Error(`${platformId} manifest original run mismatch`);
221
+ const files = (Array.isArray(manifest.files) ? manifest.files : [])
222
+ .map((file, index) => {
223
+ const relative = required(
224
+ file.path || file.name,
225
+ `${platformId} manifest files[${index}] path`,
226
+ );
227
+ const absolute = resolvePayload(root, relative, platformId);
228
+ const size = fs.statSync(absolute).size;
229
+ if (Number(file.size ?? file.bytes) !== size)
230
+ throw new Error(
231
+ `${platformId} manifest file size mismatch: ${relative}`,
232
+ );
233
+ const digest = sha256File(absolute);
234
+ const expected = `sha256:${String(file.sha256 || "").replace(/^sha256:/u, "")}`;
235
+ if (digest !== expected)
236
+ throw new Error(
237
+ `${platformId} manifest file digest mismatch: ${relative}`,
238
+ );
239
+ return { path: relative, size, digest };
240
+ })
241
+ .sort((left, right) =>
242
+ Buffer.from(left.path).compare(Buffer.from(right.path)),
243
+ );
244
+ if (files.length === 0)
245
+ throw new Error(`${platformId} manifest has no retained files`);
246
+ const observedArtifactRoot = v4ContentRoot(
247
+ "tail-reseal-artifact-files",
248
+ files,
249
+ );
250
+ const observedManifestRoot = sha256File(manifestPath);
251
+ const retained = mode === "retained";
252
+ if (
253
+ retained &&
254
+ (observedArtifactRoot !== platform.artifactRoot ||
255
+ observedManifestRoot !== platform.manifestRoot)
256
+ )
257
+ throw new Error(
258
+ `${platformId} retained artifact or manifest root mismatch`,
259
+ );
260
+ if (!retained) {
261
+ if (
262
+ observedArtifactRoot === platform.artifactRoot ||
263
+ observedManifestRoot === platform.manifestRoot
264
+ )
265
+ throw new Error(
266
+ "macos-arm64 reseal did not produce a distinct signed manifest",
267
+ );
268
+ if (providerReadbackRoot !== normalized.signing.providerReadbackRoot)
269
+ throw new Error("macos-arm64 provider readback root mismatch");
270
+ }
271
+ return {
272
+ platformId,
273
+ artifactRoot: observedArtifactRoot,
274
+ manifestRoot: observedManifestRoot,
275
+ capsuleRoot: platform.capsuleRoot,
276
+ byteIdentical: retained,
277
+ providerReadbackRoot: retained ? null : providerReadbackRoot,
278
+ };
279
+ }
280
+
281
+ function collectReadbacks(directory) {
282
+ const byPlatform = new Map();
283
+ for (const entry of fs.readdirSync(path.resolve(directory), {
284
+ recursive: true,
285
+ withFileTypes: true,
286
+ })) {
287
+ if (!entry.isFile() || !entry.name.endsWith("readback.json")) continue;
288
+ const value = readJson(path.join(entry.parentPath, entry.name));
289
+ if (byPlatform.has(value.platformId))
290
+ throw new Error(`duplicate tail reseal readback for ${value.platformId}`);
291
+ byPlatform.set(value.platformId, value);
292
+ }
293
+ return V4_TAIL_RESEAL_PLATFORMS.map((platformId) => {
294
+ if (!byPlatform.has(platformId))
295
+ throw new Error(`missing tail reseal readback for ${platformId}`);
296
+ return byPlatform.get(platformId);
297
+ });
298
+ }
299
+
300
+ export function runV4TailResealCli(args = process.argv.slice(2)) {
301
+ const [command, ...options] = args;
302
+ const requestPath = flag(options, "request");
303
+ if (command === "plan") {
304
+ const request = normalizeV4TailResealRequest(
305
+ readJson(required(requestPath, "--request"), "tail reseal request"),
306
+ );
307
+ const plan = planV4TailReseal(request);
308
+ const output = writeJson(
309
+ flag(options, "output", ".buildchain/tail-reseal/plan.json"),
310
+ plan,
311
+ );
312
+ appendOutputs({
313
+ "plan-root": plan.planRoot,
314
+ "plan-path": path.relative(process.cwd(), output),
315
+ "source-run-id": request.source.runId,
316
+ "source-run-attempt": request.source.runAttempt,
317
+ "source-sha": request.source.sha,
318
+ "source-tree-sha": request.source.treeSha,
319
+ "runtime-sha": request.runtime.sha,
320
+ "consumer-policy-receipt-root": request.runtime.consumerPolicyReceiptRoot,
321
+ "warrant-readback-root": request.warrant.stateReadbackRoot,
322
+ "signing-provider-readback-root": request.signing.providerReadbackRoot,
323
+ "release-tail-provider-readback-root":
324
+ request.releaseTail.providerReadbackRoot,
325
+ "signing-authority-repository": request.signing.authorityRepository,
326
+ "signing-authority-run-id": request.signing.authorityRunId,
327
+ "signing-result-artifact": request.signing.resultArtifact,
328
+ "target-version": request.target.version,
329
+ "platforms-json": JSON.stringify(request.platforms),
330
+ });
331
+ return plan;
332
+ }
333
+ if (command === "admit") {
334
+ const request = normalizeV4TailResealRequest(
335
+ readJson(required(requestPath, "--request"), "tail reseal request"),
336
+ );
337
+ return admitFromGitHub(request).then((admission) => {
338
+ const output = writeJson(
339
+ flag(options, "output", ".buildchain/tail-reseal/admission.json"),
340
+ admission,
341
+ );
342
+ appendOutputs({
343
+ "admission-root": admission.admissionRoot,
344
+ "admission-path": path.relative(process.cwd(), output),
345
+ });
346
+ return admission;
347
+ });
348
+ }
349
+ if (command === "verify-platform") {
350
+ const readback = verifyV4TailResealPlatform({
351
+ request: readJson(required(requestPath, "--request")),
352
+ platformId: required(flag(options, "platform"), "--platform"),
353
+ artifactRoot: flag(options, "artifact-root", process.cwd()),
354
+ mode: flag(options, "mode", "retained"),
355
+ providerReadbackRoot: flag(options, "provider-readback-root") || null,
356
+ });
357
+ const output = writeJson(
358
+ flag(
359
+ options,
360
+ "output",
361
+ `.buildchain/tail-reseal/${readback.platformId}-readback.json`,
362
+ ),
363
+ readback,
364
+ );
365
+ appendOutputs({
366
+ "readback-path": path.relative(process.cwd(), output),
367
+ "artifact-root": readback.artifactRoot,
368
+ "manifest-root": readback.manifestRoot,
369
+ });
370
+ return readback;
371
+ }
372
+ if (command === "seal") {
373
+ const request = readJson(required(requestPath, "--request"));
374
+ const receipt = createV4TailResealReceipt({
375
+ request,
376
+ plan: readJson(required(flag(options, "plan"), "--plan")),
377
+ readbacks: collectReadbacks(
378
+ required(flag(options, "readbacks"), "--readbacks"),
379
+ ),
380
+ passport: readJson(required(flag(options, "passport"), "--passport")),
381
+ protectedReadbackRoot: required(
382
+ flag(options, "protected-readback-root"),
383
+ "--protected-readback-root",
384
+ ),
385
+ currentRun: {
386
+ id: Number(required(process.env.GITHUB_RUN_ID, "GITHUB_RUN_ID")),
387
+ attempt: Number(
388
+ required(process.env.GITHUB_RUN_ATTEMPT, "GITHUB_RUN_ATTEMPT"),
389
+ ),
390
+ },
391
+ });
392
+ const output = writeJson(
393
+ flag(options, "output", ".buildchain/tail-reseal/receipt.json"),
394
+ receipt,
395
+ );
396
+ appendOutputs({
397
+ "receipt-root": receipt.receiptRoot,
398
+ "receipt-path": path.relative(process.cwd(), output),
399
+ });
400
+ return receipt;
401
+ }
402
+ throw new Error(
403
+ "usage: buildchain tail-reseal <plan|admit|verify-platform|seal> --request <request.json> [options]",
404
+ );
405
+ }
406
+
407
+ if (
408
+ !process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT &&
409
+ process.argv[1] &&
410
+ import.meta.url === pathToFileURL(process.argv[1]).href
411
+ ) {
412
+ runV4TailResealCli().catch((error) => {
413
+ console.error(`tail-reseal: ${error.message}`);
414
+ process.exitCode = 1;
415
+ });
416
+ }
@@ -0,0 +1,143 @@
1
+ name: Protected Dev Delivery
2
+
3
+ on:
4
+ repository_dispatch:
5
+ types: [buildchain-dev-delivery-wake]
6
+ workflow_dispatch:
7
+ inputs:
8
+ buildchain-ref:
9
+ description: "Buildchain runtime selector: v4, v4-alpha, or a trusted train/v4/v4.0/<capability>"
10
+ required: false
11
+ default: "v4-alpha"
12
+ target-branch:
13
+ description: "Protected dev/vN/vN.M branch"
14
+ required: true
15
+ expected-pr-number:
16
+ description: "Exact ready and approved PR number"
17
+ required: true
18
+ type: number
19
+ expected-head-sha:
20
+ description: "Exact immutable PR head"
21
+ required: true
22
+ source-workflow-run-id:
23
+ description: "Exact successful source workflow run"
24
+ required: false
25
+ type: number
26
+ default: 0
27
+ legacy-active-owner-binding-json:
28
+ description: "Explicit legacy-safe phase-less owner binding JSON"
29
+ required: false
30
+ default: ""
31
+ source-workflow-id:
32
+ description: "Pull-request workflow used only to recover a historical active owner with no recorded run"
33
+ required: false
34
+ default: ""
35
+ source-identity-root:
36
+ description: "Semantic source identity root"
37
+ required: true
38
+ source-patch-root:
39
+ description: "Semantic patch root"
40
+ required: true
41
+ assignment-root:
42
+ description: "Native Assignment root"
43
+ required: true
44
+ initiative-root:
45
+ description: "Parent Initiative root"
46
+ required: true
47
+ plan-root:
48
+ description: "Native qualification plan root"
49
+ required: true
50
+ closure-root:
51
+ description: "Affected closure root"
52
+ required: true
53
+ dependency-root:
54
+ description: "Dependency graph root"
55
+ required: true
56
+ toolchain-root:
57
+ description: "Native toolchain root"
58
+ required: true
59
+ environment-root:
60
+ description: "Exact native execution environment contract root bound before native spawn"
61
+ required: false
62
+ default: ""
63
+ affected-paths-json:
64
+ description: "JSON array representing the affected closure"
65
+ required: true
66
+ shard-evidence-roots-json:
67
+ description: "JSON array of exact native shard evidence roots"
68
+ required: false
69
+ default: "[]"
70
+ release-blocker-priority-json:
71
+ description: "Optional exact rooted release-blocker priority claim"
72
+ required: false
73
+ default: ""
74
+ native-proof-json:
75
+ description: "Optional reusable native proof"
76
+ required: false
77
+ default: ""
78
+ native-command:
79
+ description: "Slow native qualification command"
80
+ required: false
81
+ default: ""
82
+ native-command-root:
83
+ description: "Optional exact native command contract root"
84
+ required: false
85
+ default: ""
86
+ native-heartbeat-seconds:
87
+ description: "Heartbeat cadence while native qualification runs"
88
+ required: false
89
+ type: number
90
+ default: 300
91
+ delivery-class:
92
+ description: "Bounded delivery class"
93
+ required: false
94
+ default: "native-proof-required"
95
+ delivery-priority:
96
+ description: "Reviewed delivery priority"
97
+ required: false
98
+ default: "ordinary"
99
+
100
+ permissions:
101
+ actions: write
102
+ contents: write
103
+ pull-requests: write
104
+ checks: read
105
+ statuses: write
106
+
107
+ jobs:
108
+ deliver:
109
+ uses: kungfu-systems/buildchain/.github/workflows/dev-pr-auto-merge.yml@v4-alpha
110
+ with:
111
+ buildchain-ref: ${{ inputs.buildchain-ref || 'v4-alpha' }}
112
+ target-branch: ${{ github.event.client_payload.candidate.targetBranch || inputs.target-branch }}
113
+ expected-pr-number: ${{ github.event.client_payload.candidate.pullRequestNumber || inputs.expected-pr-number }}
114
+ expected-head-sha: ${{ github.event.client_payload.candidate.sourceHead || inputs.expected-head-sha }}
115
+ source-workflow-run-id: ${{ github.event.client_payload.candidate.sourceWorkflowRunId || inputs.source-workflow-run-id || github.run_id }}
116
+ legacy-active-owner-binding-json: ${{ inputs.legacy-active-owner-binding-json || '' }}
117
+ delivery-warrant-mode: required
118
+ handoff-workflow-id: native-dev-delivery.yml
119
+ source-workflow-id: ${{ inputs.source-workflow-id || '' }}
120
+ assignment-root: ${{ github.event.client_payload.candidate.assignmentRoot || inputs.assignment-root }}
121
+ initiative-root: ${{ github.event.client_payload.candidate.initiativeRoot || inputs.initiative-root }}
122
+ source-identity-root: ${{ github.event.client_payload.candidate.sourceIdentityRoot || inputs.source-identity-root }}
123
+ source-patch-root: ${{ github.event.client_payload.candidate.sourcePatchRoot || inputs.source-patch-root }}
124
+ plan-root: ${{ github.event.client_payload.candidate.planRoot || inputs.plan-root }}
125
+ closure-root: ${{ github.event.client_payload.candidate.closureRoot || inputs.closure-root }}
126
+ dependency-root: ${{ github.event.client_payload.candidate.dependencyRoot || inputs.dependency-root }}
127
+ toolchain-root: ${{ github.event.client_payload.candidate.toolchainRoot || inputs.toolchain-root }}
128
+ environment-root: ${{ github.event.client_payload.candidate.environmentRoot || inputs.environment-root }}
129
+ affected-paths-json: ${{ github.event_name == 'repository_dispatch' && toJSON(github.event.client_payload.candidate.affectedPaths) || inputs.affected-paths-json }}
130
+ shard-evidence-roots-json: ${{ github.event_name == 'repository_dispatch' && toJSON(github.event.client_payload.candidate.shardEvidenceRoots) || inputs.shard-evidence-roots-json || '[]' }}
131
+ release-blocker-priority-json: ${{ github.event_name == 'repository_dispatch' && toJSON(github.event.client_payload.candidate.releaseBlockerPriority) || inputs.release-blocker-priority-json || '' }}
132
+ native-proof-json: ${{ inputs.native-proof-json || '' }}
133
+ native-command: ${{ github.event.client_payload.candidate.nativeCommandContract.command || inputs.native-command || '' }}
134
+ native-command-root: ${{ github.event.client_payload.candidate.nativeCommandContract.commandRoot || inputs.native-command-root || '' }}
135
+ native-heartbeat-seconds: ${{ inputs.native-heartbeat-seconds || 300 }}
136
+ delivery-class: ${{ github.event.client_payload.candidate.deliveryClass || inputs.delivery-class || 'native-proof-required' }}
137
+ delivery-priority: ${{ github.event.client_payload.candidate.priority || inputs.delivery-priority || 'ordinary' }}
138
+ queue-admission-context: Queue admission lease
139
+ active-lease-context: Queue family lease/exact
140
+ landing-mode: queue
141
+ dry-run: false
142
+ secrets:
143
+ github-token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}