@kungfu-tech/buildchain 3.0.5 → 3.0.6-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +31 -0
  2. package/actions/macos-credential-island/README.md +8 -0
  3. package/bin/buildchain.mjs +1 -1
  4. package/contracts/auditable-demo-media-profiles-v1.json +61 -0
  5. package/contracts/auditable-demo-scenario-v1.schema.json +164 -0
  6. package/contracts/evidence/auditable-demo-responsive-web-delivery-v1.json +3 -3
  7. package/contracts/evidence/auditable-demo-web-delivery-v1.json +3 -3
  8. package/dist/site/buildchain-contract.json +107 -26
  9. package/dist/site/buildchain-site.json +121 -49
  10. package/dist/site/capability-registry.json +3 -3
  11. package/dist/site/cli-registry.json +9 -3
  12. package/dist/site/controller-registry.json +27 -3
  13. package/dist/site/kfd-claims.json +101 -15
  14. package/dist/site/kfd-upstream-aggregate.json +1 -1
  15. package/dist/site/manual-registry.json +10 -9
  16. package/dist/site/node-api-registry.json +540 -31
  17. package/dist/site/page-registry.json +105 -29
  18. package/dist/site/public-surface-audit.json +184 -11
  19. package/dist/site/publication-authority-registry.json +62 -1
  20. package/dist/site/publication-registry.json +4 -4
  21. package/dist/site/site-manifest.json +13 -13
  22. package/dist/site/workflow-registry.json +118 -4
  23. package/docs/MAP.md +4 -1
  24. package/docs/auditable-demo.md +90 -7
  25. package/docs/aws-us-elastic-runner-burst-plane.md +151 -16
  26. package/docs/cli-reference.md +35 -2
  27. package/docs/dev-alpha-candidate-patrol.md +14 -5
  28. package/docs/dev-qualification-patrol.md +108 -0
  29. package/docs/node-api-reference.md +123 -72
  30. package/docs/publish-transaction.md +7 -5
  31. package/docs/release-flow.md +4 -0
  32. package/docs/release-governance.md +39 -0
  33. package/docs/release-propagation.md +93 -0
  34. package/docs/reusable-build-surface.md +53 -12
  35. package/docs/stable-candidate-patrol.md +5 -2
  36. package/package.json +1 -1
  37. package/packages/core/buildchain-contract.js +36 -1
  38. package/packages/core/buildchain-publication-authority.js +3 -0
  39. package/packages/core/public-surface-audit.js +4 -35
  40. package/packages/core/release-propagation-agent-entry.js +185 -0
  41. package/packages/core/release-propagation-pickup.js +387 -0
  42. package/packages/core/release-propagation-push.js +293 -0
  43. package/packages/core/release-propagation-release.js +61 -18
  44. package/packages/core/release-propagation-stage-evidence.js +36 -0
  45. package/packages/core/release-propagation-work.js +8 -4
  46. package/packages/core/release-propagation.js +27 -2
  47. package/packages/core/workflow-call-contract.js +308 -0
  48. package/packages/core/workflow-yaml-contract.js +272 -0
  49. package/scripts/artifact-signing-controller-core.mjs +525 -0
  50. package/scripts/artifact-signing-controller.mjs +302 -0
  51. package/scripts/artifact-signing-delegation.mjs +51 -3
  52. package/scripts/auditable-demo-platform.mjs +564 -0
  53. package/scripts/auditable-demo-renditions.mjs +7 -2
  54. package/scripts/auditable-demo-transport-smoke.mjs +176 -0
  55. package/scripts/auditable-demo.mjs +27 -21
  56. package/scripts/aws-macos-jit-controller-core.mjs +389 -0
  57. package/scripts/aws-macos-jit-controller-runtime.mjs +82 -0
  58. package/scripts/aws-macos-jit-controller.mjs +558 -0
  59. package/scripts/aws-macos-jit-job-controller.mjs +401 -0
  60. package/scripts/aws-windows-jit-campaign-core.mjs +296 -0
  61. package/scripts/aws-windows-jit-campaign.mjs +202 -0
  62. package/scripts/aws-windows-jit-controller-core.mjs +20 -2
  63. package/scripts/aws-windows-jit-controller.mjs +184 -109
  64. package/scripts/aws-windows-jit-core.mjs +21 -3
  65. package/scripts/aws-windows-jit.mjs +2 -0
  66. package/scripts/build-standalone-binary.mjs +6 -0
  67. package/scripts/buildchain-cli-help.mjs +2 -1
  68. package/scripts/capture-package-release-propagation.mjs +24 -1
  69. package/scripts/check-inventory.mjs +6 -0
  70. package/scripts/compiler-cache-evidence.mjs +90 -7
  71. package/scripts/dev-alpha-candidate-patrol.mjs +80 -5
  72. package/scripts/dev-pr-auto-merge.mjs +4 -4
  73. package/scripts/dev-qualification-patrol.mjs +594 -0
  74. package/scripts/dispatch-artifact-signing-authority.mjs +312 -61
  75. package/scripts/finalize-native-artifact-signing-result.mjs +37 -15
  76. package/scripts/generate-site-bundle.mjs +5 -0
  77. package/scripts/inspect-artifact-signing-requests.mjs +12 -0
  78. package/scripts/locked-source-checkout.mjs +17 -3
  79. package/scripts/release-propagation.mjs +150 -2
  80. package/scripts/run-lifecycle-core.mjs +25 -0
  81. package/scripts/site-capability-metadata.mjs +1 -1
  82. package/scripts/stable-candidate-patrol.mjs +30 -4
  83. package/scripts/workflow-call-contract.mjs +133 -0
@@ -12,37 +12,110 @@ function required(value, label) {
12
12
 
13
13
  function repository(value, label) {
14
14
  const normalized = required(value, label);
15
- if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(normalized)) throw new Error(`${label} must be owner/repository`);
15
+ if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(normalized))
16
+ throw new Error(`${label} must be owner/repository`);
16
17
  return normalized;
17
18
  }
18
19
 
19
20
  const TRANSIENT_GITHUB_STATUSES = new Set([408, 429, 500, 502, 503, 504]);
20
- const DEFAULT_ARTIFACT_SIGNING_AUTHORITY_REF = "authority/v3/v3.0/artifact-signing";
21
+ const DEFAULT_ARTIFACT_SIGNING_AUTHORITY_REF =
22
+ "authority/v3/v3.0/artifact-signing";
23
+ const AUTHORITY_WORKFLOW = "artifact-signing-authority.yml";
21
24
 
22
25
  export function resolveAuthorityDispatchRef(value) {
23
26
  const ref = required(value, "authority ref");
24
- return /^[0-9a-f]{40}$/u.test(ref) ? DEFAULT_ARTIFACT_SIGNING_AUTHORITY_REF : ref;
27
+ return /^[0-9a-f]{40}$/u.test(ref)
28
+ ? DEFAULT_ARTIFACT_SIGNING_AUTHORITY_REF
29
+ : ref;
30
+ }
31
+
32
+ export async function resolveArtifactSigningAuthorityRuntime({
33
+ authorityRepository,
34
+ authorityRef,
35
+ token,
36
+ requestImpl = githubRequest,
37
+ }) {
38
+ const authorityRepo = repository(authorityRepository, "authority repository");
39
+ const ref = resolveAuthorityDispatchRef(authorityRef);
40
+ const encodedRef = ref.split("/").map(encodeURIComponent).join("/");
41
+ const response = await requestImpl(
42
+ `/repos/${authorityRepo}/git/ref/heads/${encodedRef}`,
43
+ { token: required(token, "Buildchain authority dispatch token") },
44
+ );
45
+ if (response?.object?.type !== "commit") {
46
+ throw new Error(
47
+ "Buildchain signing authority ref does not resolve to a commit",
48
+ );
49
+ }
50
+ const sha = String(response.object.sha || "");
51
+ if (!/^[0-9a-f]{40}$/u.test(sha)) {
52
+ throw new Error("Buildchain signing authority runtime SHA must be exact");
53
+ }
54
+ return { ref, sha };
25
55
  }
26
56
 
27
57
  function retryDelayMs(attempt) {
28
- return Math.min(1_000 * (2 ** (attempt - 1)), 10_000);
58
+ return Math.min(1_000 * 2 ** (attempt - 1), 10_000);
29
59
  }
30
60
 
31
- export async function githubRequest(url, {
32
- token,
33
- method = "GET",
34
- body,
35
- fetchImpl = fetch,
36
- delayImpl = delay,
37
- maxAttempts = 5,
38
- warnImpl = console.warn,
39
- } = {}) {
61
+ function authorityError(message, outputs = {}) {
62
+ const error = new Error(message);
63
+ error.authorityOutputs = outputs;
64
+ return error;
65
+ }
66
+
67
+ export function validateArtifactSigningAuthorityRun(
68
+ run,
69
+ { authorityRepository, authorityRuntimeSha, expectedTitle },
70
+ ) {
71
+ if (!run || typeof run !== "object") {
72
+ throw new Error("Buildchain signing authority run is missing");
73
+ }
74
+ if (String(run.display_title || "") !== expectedTitle) {
75
+ throw new Error("Buildchain signing authority correlation mismatch");
76
+ }
77
+ if (String(run.event || "") !== "workflow_dispatch") {
78
+ throw new Error("Buildchain signing authority event mismatch");
79
+ }
80
+ if (String(run.head_sha || "") !== authorityRuntimeSha) {
81
+ throw new Error("Buildchain signing authority runtime SHA mismatch");
82
+ }
83
+ if (
84
+ run.repository?.full_name &&
85
+ String(run.repository.full_name) !== authorityRepository
86
+ ) {
87
+ throw new Error("Buildchain signing authority repository mismatch");
88
+ }
89
+ if (
90
+ run.path &&
91
+ !String(run.path).startsWith(`.github/workflows/${AUTHORITY_WORKFLOW}@`)
92
+ ) {
93
+ throw new Error("Buildchain signing authority workflow path mismatch");
94
+ }
95
+ return run;
96
+ }
97
+
98
+ export async function githubRequest(
99
+ url,
100
+ {
101
+ token,
102
+ method = "GET",
103
+ body,
104
+ fetchImpl = fetch,
105
+ delayImpl = delay,
106
+ maxAttempts = 5,
107
+ warnImpl = console.warn,
108
+ } = {},
109
+ ) {
40
110
  const methodName = String(method).toUpperCase();
41
111
  const retrySafe = methodName === "GET";
42
112
  const requestedAttempts = Number(maxAttempts);
43
- const attemptLimit = retrySafe && Number.isSafeInteger(requestedAttempts) && requestedAttempts > 0
44
- ? requestedAttempts
45
- : 1;
113
+ const attemptLimit =
114
+ retrySafe &&
115
+ Number.isSafeInteger(requestedAttempts) &&
116
+ requestedAttempts > 0
117
+ ? requestedAttempts
118
+ : 1;
46
119
  for (let attempt = 1; attempt <= attemptLimit; attempt += 1) {
47
120
  let response;
48
121
  try {
@@ -59,7 +132,9 @@ export async function githubRequest(url, {
59
132
  });
60
133
  } catch (error) {
61
134
  if (retrySafe && attempt < attemptLimit) {
62
- warnImpl(`Buildchain signing authority: GitHub API GET transport failure; retry ${attempt + 1}/${attemptLimit}`);
135
+ warnImpl(
136
+ `Buildchain signing authority: GitHub API GET transport failure; retry ${attempt + 1}/${attemptLimit}`,
137
+ );
63
138
  await delayImpl(retryDelayMs(attempt));
64
139
  continue;
65
140
  }
@@ -67,19 +142,29 @@ export async function githubRequest(url, {
67
142
  }
68
143
  if (!response.ok) {
69
144
  const text = await response.text();
70
- if (retrySafe && TRANSIENT_GITHUB_STATUSES.has(response.status) && attempt < attemptLimit) {
71
- warnImpl(`Buildchain signing authority: GitHub API GET returned ${response.status}; retry ${attempt + 1}/${attemptLimit}`);
145
+ if (
146
+ retrySafe &&
147
+ TRANSIENT_GITHUB_STATUSES.has(response.status) &&
148
+ attempt < attemptLimit
149
+ ) {
150
+ warnImpl(
151
+ `Buildchain signing authority: GitHub API GET returned ${response.status}; retry ${attempt + 1}/${attemptLimit}`,
152
+ );
72
153
  await delayImpl(retryDelayMs(attempt));
73
154
  continue;
74
155
  }
75
- throw new Error(`GitHub API ${methodName} ${url} failed (${response.status}): ${text.slice(0, 500)}`);
156
+ throw new Error(
157
+ `GitHub API ${methodName} ${url} failed (${response.status}): ${text.slice(0, 500)}`,
158
+ );
76
159
  }
77
160
  if (response.status === 204) return {};
78
161
  try {
79
162
  return await response.json();
80
163
  } catch (error) {
81
164
  if (retrySafe && attempt < attemptLimit) {
82
- warnImpl(`Buildchain signing authority: GitHub API GET response failed to decode; retry ${attempt + 1}/${attemptLimit}`);
165
+ warnImpl(
166
+ `Buildchain signing authority: GitHub API GET response failed to decode; retry ${attempt + 1}/${attemptLimit}`,
167
+ );
83
168
  await delayImpl(retryDelayMs(attempt));
84
169
  continue;
85
170
  }
@@ -89,70 +174,236 @@ export async function githubRequest(url, {
89
174
  throw new Error("GitHub API retry loop exhausted");
90
175
  }
91
176
 
177
+ async function pollArtifactSigningAuthorityRun({
178
+ authorityRepository,
179
+ token,
180
+ authorityRuntimeSha,
181
+ expectedTitle,
182
+ startedAtMs,
183
+ deadline,
184
+ baseOutputs,
185
+ requestImpl,
186
+ delayImpl,
187
+ nowImpl,
188
+ }) {
189
+ let run;
190
+ while (nowImpl() < deadline) {
191
+ const response = await requestImpl(
192
+ `/repos/${authorityRepository}/actions/workflows/${AUTHORITY_WORKFLOW}/runs?event=workflow_dispatch&per_page=50`,
193
+ { token },
194
+ );
195
+ const matches = (response.workflow_runs || []).filter(
196
+ (entry) =>
197
+ new Date(entry.created_at).getTime() >= startedAtMs - 30_000 &&
198
+ String(entry.display_title || "") === expectedTitle,
199
+ );
200
+ if (matches.length > 1) {
201
+ throw authorityError(
202
+ "multiple Buildchain signing authority runs share one correlation",
203
+ { ...baseOutputs, "authority-status": "failed" },
204
+ );
205
+ }
206
+ if (matches.length === 1) {
207
+ try {
208
+ run = validateArtifactSigningAuthorityRun(matches[0], {
209
+ authorityRepository,
210
+ authorityRuntimeSha,
211
+ expectedTitle,
212
+ });
213
+ } catch (error) {
214
+ throw authorityError(error.message, {
215
+ ...baseOutputs,
216
+ "authority-run-id": String(matches[0].id || ""),
217
+ "authority-run-url": String(matches[0].html_url || ""),
218
+ "authority-status": "failed",
219
+ });
220
+ }
221
+ }
222
+ if (run?.status === "completed") return run;
223
+ await delayImpl(10_000);
224
+ }
225
+ throw authorityError("timed out waiting for Buildchain signing authority", {
226
+ ...baseOutputs,
227
+ "authority-run-id": String(run?.id || ""),
228
+ "authority-run-url": String(run?.html_url || ""),
229
+ "authority-status": "timed-out",
230
+ "authority-conclusion": String(run?.conclusion || "timed-out"),
231
+ "controller-completed-at": new Date(nowImpl()).toISOString(),
232
+ });
233
+ }
234
+
235
+ function successfulAuthorityResult({
236
+ run,
237
+ baseOutputs,
238
+ resultArtifact,
239
+ correlationId,
240
+ controllerStartedAt,
241
+ completedAt,
242
+ }) {
243
+ if (run.conclusion !== "success") {
244
+ const status = run.conclusion === "cancelled" ? "cancelled" : "failed";
245
+ throw authorityError(
246
+ `Buildchain signing authority failed: ${run.html_url}`,
247
+ {
248
+ ...baseOutputs,
249
+ "authority-run-id": String(run.id),
250
+ "authority-run-url": String(run.html_url || ""),
251
+ "authority-status": status,
252
+ "authority-conclusion": String(run.conclusion || status),
253
+ "controller-completed-at": completedAt,
254
+ },
255
+ );
256
+ }
257
+ return {
258
+ outputs: {
259
+ ...baseOutputs,
260
+ "authority-run-id": String(run.id),
261
+ "authority-run-url": String(run.html_url || ""),
262
+ "authority-status": "succeeded",
263
+ "authority-conclusion": "success",
264
+ "controller-completed-at": completedAt,
265
+ },
266
+ result: {
267
+ runId: run.id,
268
+ runUrl: run.html_url,
269
+ authorityRuntimeSha: baseOutputs["authority-runtime-sha"],
270
+ resultArtifact,
271
+ correlationId,
272
+ status: "succeeded",
273
+ startedAt: controllerStartedAt,
274
+ completedAt,
275
+ },
276
+ };
277
+ }
278
+
92
279
  export async function dispatchArtifactSigningAuthority({
93
280
  token = process.env.BUILDCHAIN_AUTHORITY_DISPATCH_TOKEN,
94
- authorityRepository = process.env.BUILDCHAIN_AUTHORITY_REPOSITORY || "kungfu-systems/buildchain",
281
+ authorityRepository = process.env.BUILDCHAIN_AUTHORITY_REPOSITORY ||
282
+ "kungfu-systems/buildchain",
95
283
  authorityRef = process.env.BUILDCHAIN_AUTHORITY_REF,
96
284
  sourceRepository = process.env.GITHUB_REPOSITORY,
97
285
  sourceRunId = process.env.GITHUB_RUN_ID,
98
286
  sourceRunAttempt = process.env.GITHUB_RUN_ATTEMPT || "1",
99
287
  requestArtifact = process.env.BUILDCHAIN_SIGNING_REQUEST_ARTIFACT,
288
+ requestRoot = process.env.BUILDCHAIN_SIGNING_REQUEST_ROOT_DIGEST,
100
289
  runtimeSha = process.env.BUILDCHAIN_RUNTIME_SHA,
101
290
  resultArtifact = process.env.BUILDCHAIN_SIGNING_RESULT_ARTIFACT,
291
+ correlationId = process.env.BUILDCHAIN_AUTHORITY_CORRELATION_ID || "",
102
292
  timeoutSeconds = process.env.BUILDCHAIN_SIGNING_TIMEOUT_SECONDS || "7200",
293
+ requestImpl = githubRequest,
294
+ delayImpl = delay,
295
+ nowImpl = () => Date.now(),
103
296
  } = {}) {
104
297
  const authToken = required(token, "Buildchain authority dispatch token");
105
298
  const authorityRepo = repository(authorityRepository, "authority repository");
106
299
  const sourceRepo = repository(sourceRepository, "source repository");
107
300
  const ref = resolveAuthorityDispatchRef(authorityRef);
108
301
  const runtime = required(runtimeSha, "Buildchain runtime SHA");
109
- if (!/^[0-9a-f]{40}$/u.test(runtime)) throw new Error("Buildchain runtime SHA must be exact");
110
- const correlationId = `${required(sourceRunId, "source run ID")}-${required(sourceRunAttempt, "source run attempt")}-${runtime.slice(0, 12)}-${required(requestArtifact, "request artifact").replace(/[^A-Za-z0-9._-]+/gu, "-")}`;
302
+ if (!/^[0-9a-f]{40}$/u.test(runtime))
303
+ throw new Error("Buildchain runtime SHA must be exact");
304
+ const runId = required(sourceRunId, "source run ID");
305
+ const runAttempt = required(sourceRunAttempt, "source run attempt");
306
+ if (!/^[1-9][0-9]*$/u.test(runAttempt)) {
307
+ throw new Error("source run attempt must be a positive integer");
308
+ }
309
+ const requestName = required(requestArtifact, "request artifact");
310
+ const requestRootDigest = required(requestRoot, "request root");
311
+ if (!/^sha256:[0-9a-f]{64}$/u.test(requestRootDigest)) {
312
+ throw new Error("request root must be a canonical sha256 root");
313
+ }
314
+ const correlation = required(
315
+ correlationId ||
316
+ `${runId}-${runAttempt}-${runtime.slice(0, 12)}-${requestName.replace(/[^A-Za-z0-9._-]+/gu, "-")}`,
317
+ "correlation ID",
318
+ );
111
319
  const resultName = required(resultArtifact, "result artifact");
112
- const workflow = "artifact-signing-authority.yml";
113
- const startedAt = Date.now() - 30_000;
114
- await githubRequest(`/repos/${authorityRepo}/actions/workflows/${workflow}/dispatches`, {
115
- token: authToken,
116
- method: "POST",
117
- body: {
118
- ref,
119
- inputs: {
120
- "source-repository": sourceRepo,
121
- "source-run-id": String(sourceRunId),
122
- "request-artifact-pattern": required(requestArtifact, "request artifact"),
123
- "result-artifact-name": resultName,
124
- "correlation-id": correlationId,
125
- "expected-runtime-sha": runtime,
320
+ const timeout = Number(timeoutSeconds);
321
+ if (!Number.isFinite(timeout) || timeout <= 0) {
322
+ throw new Error("Buildchain signing timeout must be positive");
323
+ }
324
+ const controllerStartedAtMs = nowImpl();
325
+ const controllerStartedAt = new Date(controllerStartedAtMs).toISOString();
326
+ const baseOutputs = {
327
+ "result-artifact": resultName,
328
+ "correlation-id": correlation,
329
+ "controller-started-at": controllerStartedAt,
330
+ };
331
+ try {
332
+ const authorityRuntime = await resolveArtifactSigningAuthorityRuntime({
333
+ authorityRepository: authorityRepo,
334
+ authorityRef: ref,
335
+ token: authToken,
336
+ requestImpl,
337
+ });
338
+ baseOutputs["authority-runtime-sha"] = authorityRuntime.sha;
339
+ await requestImpl(
340
+ `/repos/${authorityRepo}/actions/workflows/${AUTHORITY_WORKFLOW}/dispatches`,
341
+ {
342
+ token: authToken,
343
+ method: "POST",
344
+ body: {
345
+ ref: authorityRuntime.ref,
346
+ inputs: {
347
+ "source-repository": sourceRepo,
348
+ "source-run-id": runId,
349
+ "source-run-attempt": runAttempt,
350
+ "request-artifact-pattern": requestName,
351
+ "expected-request-root": requestRootDigest,
352
+ "result-artifact-name": resultName,
353
+ "correlation-id": correlation,
354
+ "expected-runtime-sha": runtime,
355
+ },
356
+ },
126
357
  },
127
- },
128
- });
129
- const deadline = Date.now() + Number(timeoutSeconds) * 1000;
130
- let run;
131
- while (Date.now() < deadline) {
132
- const response = await githubRequest(`/repos/${authorityRepo}/actions/workflows/${workflow}/runs?event=workflow_dispatch&per_page=50`, { token: authToken });
133
- run = (response.workflow_runs || []).find((entry) =>
134
- new Date(entry.created_at).getTime() >= startedAt &&
135
- String(entry.display_title || "").includes(correlationId),
136
358
  );
137
- if (run?.status === "completed") break;
138
- await delay(10_000);
139
- }
140
- if (!run || run.status !== "completed") throw new Error("timed out waiting for Buildchain signing authority");
141
- if (run.conclusion !== "success") throw new Error(`Buildchain signing authority failed: ${run.html_url}`);
142
- writeGitHubOutputs({
143
- "authority-run-id": String(run.id),
144
- "authority-run-url": run.html_url,
145
- "result-artifact": resultName,
146
- "correlation-id": correlationId,
147
- });
148
- return { runId: run.id, runUrl: run.html_url, resultArtifact: resultName, correlationId };
359
+ const expectedTitle = `Sign ${sourceRepo} run ${runId} (${correlation})`;
360
+ const run = await pollArtifactSigningAuthorityRun({
361
+ authorityRepository: authorityRepo,
362
+ token: authToken,
363
+ authorityRuntimeSha: authorityRuntime.sha,
364
+ expectedTitle,
365
+ startedAtMs: controllerStartedAtMs,
366
+ deadline: controllerStartedAtMs + timeout * 1000,
367
+ baseOutputs,
368
+ requestImpl,
369
+ delayImpl,
370
+ nowImpl,
371
+ });
372
+ const completedAt = new Date(nowImpl()).toISOString();
373
+ const completed = successfulAuthorityResult({
374
+ run,
375
+ baseOutputs,
376
+ resultArtifact: resultName,
377
+ correlationId: correlation,
378
+ controllerStartedAt,
379
+ completedAt,
380
+ });
381
+ writeGitHubOutputs(completed.outputs);
382
+ return completed.result;
383
+ } catch (error) {
384
+ if (!error.authorityOutputs) {
385
+ error.authorityOutputs = {
386
+ ...baseOutputs,
387
+ "authority-status": "failed",
388
+ "authority-conclusion": "controller-error",
389
+ "controller-completed-at": new Date(nowImpl()).toISOString(),
390
+ };
391
+ }
392
+ throw error;
393
+ }
149
394
  }
150
395
 
151
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
396
+ if (
397
+ process.argv[1] &&
398
+ import.meta.url === pathToFileURL(process.argv[1]).href
399
+ ) {
152
400
  try {
153
401
  await dispatchArtifactSigningAuthority();
154
402
  } catch (error) {
155
- console.error(`::error::${String(error?.message || error).replace(/\r?\n/gu, "%0A")}`);
403
+ if (error?.authorityOutputs) writeGitHubOutputs(error.authorityOutputs);
404
+ console.error(
405
+ `::error::${String(error?.message || error).replace(/\r?\n/gu, "%0A")}`,
406
+ );
156
407
  process.exitCode = 1;
157
408
  }
158
409
  }
@@ -12,6 +12,7 @@ import {
12
12
  artifactSigningEvidenceDigest,
13
13
  createArtifactSigningResult,
14
14
  } from "../packages/core/artifact-signing-result.js";
15
+ import { acceptedMacosCredentialEvidence } from "../actions/macos-credential-island/dmg-assembly.js";
15
16
  import { writeGitHubOutputs } from "./build-contract-core.mjs";
16
17
 
17
18
  function required(value, label) {
@@ -32,15 +33,39 @@ function resolveBelow(root, relative, label) {
32
33
  return target;
33
34
  }
34
35
 
36
+ function expectedCredentialExecution(
37
+ appBundleResult,
38
+ expectedRunId,
39
+ expectedRunAttempt,
40
+ ) {
41
+ if (!appBundleResult) return null;
42
+ return {
43
+ runId: required(expectedRunId, "credential execution run id"),
44
+ runAttempt: required(
45
+ expectedRunAttempt,
46
+ "credential execution run attempt",
47
+ ),
48
+ };
49
+ }
50
+
51
+ function acceptedProviderEvidence(evidence, request, expectedExecution) {
52
+ return expectedExecution
53
+ ? acceptedMacosCredentialEvidence(evidence, request, expectedExecution)
54
+ : evidence.status === "passed" &&
55
+ evidence.provider === request.signature.provider;
56
+ }
57
+
35
58
  export function finalizeNativeArtifactSigningResult({
36
59
  requestRoot = process.env.BUILDCHAIN_SIGNING_REQUEST_ROOT,
37
60
  requestPath = process.env.BUILDCHAIN_SIGNING_REQUEST_PATH,
38
61
  signedPayload = process.env.BUILDCHAIN_SIGNED_PAYLOAD,
39
62
  evidencePath = process.env.BUILDCHAIN_SIGNING_EVIDENCE,
40
- credentialArtifactRoot =
41
- process.env.BUILDCHAIN_SIGNING_CREDENTIAL_ARTIFACT_ROOT,
63
+ credentialArtifactRoot = process.env
64
+ .BUILDCHAIN_SIGNING_CREDENTIAL_ARTIFACT_ROOT,
42
65
  outputRoot = process.env.BUILDCHAIN_SIGNING_RESULT_ROOT,
43
66
  checks = process.env.BUILDCHAIN_SIGNING_VERIFICATION_CHECKS,
67
+ expectedRunId = process.env.GITHUB_RUN_ID,
68
+ expectedRunAttempt = process.env.GITHUB_RUN_ATTEMPT,
44
69
  } = {}) {
45
70
  const requests = path.resolve(required(requestRoot, "signing request root"));
46
71
  const request = JSON.parse(
@@ -77,19 +102,16 @@ export function finalizeNativeArtifactSigningResult({
77
102
  fs.copyFileSync(evidenceSource, evidenceOutput, fs.constants.COPYFILE_EXCL);
78
103
  const evidenceDocument = JSON.parse(fs.readFileSync(evidenceOutput, "utf8"));
79
104
  const appBundleResult = request.artifact.kind === "app-bundle";
80
- const providerEvidencePassed = appBundleResult
81
- ? evidenceDocument.schema ===
82
- "buildchain.macos-credential-island-evidence/v1" &&
83
- evidenceDocument.status === "accepted" &&
84
- evidenceDocument.source?.repository === request.source.repository &&
85
- evidenceDocument.source?.sha === request.source.sha &&
86
- evidenceDocument.source?.treeSha === request.source.treeSha &&
87
- evidenceDocument.buildchain?.runtimeSha === request.runtime.sha &&
88
- evidenceDocument.app?.architecture === request.artifact.arch &&
89
- evidenceDocument.notarization?.application?.status === "Accepted" &&
90
- evidenceDocument.notarization?.diskImage?.status === "Accepted"
91
- : evidenceDocument.status === "passed" &&
92
- evidenceDocument.provider === request.signature.provider;
105
+ const expectedExecution = expectedCredentialExecution(
106
+ appBundleResult,
107
+ expectedRunId,
108
+ expectedRunAttempt,
109
+ );
110
+ const providerEvidencePassed = acceptedProviderEvidence(
111
+ evidenceDocument,
112
+ request,
113
+ expectedExecution,
114
+ );
93
115
  if (!providerEvidencePassed) {
94
116
  throw new Error(
95
117
  "provider evidence does not prove the requested native signature",
@@ -364,6 +364,7 @@ const manualMetaById = new Map(Object.entries({
364
364
  "release-activation-transaction": { capabilityGroup: "release-passport-trust", audience: ["release-operator", "agent"], maturity: "preview", order: 125 },
365
365
  "release-candidate": { capabilityGroup: "reusable-build", audience: ["release-operator", "consumer"], maturity: "stable", order: 130 },
366
366
  "stable-candidate-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer"], maturity: "preview", order: 135 },
367
+ "dev-qualification-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 136 },
367
368
  "dev-alpha-candidate-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 137 },
368
369
  "observed-evidence-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 140 },
369
370
  "reusable-build-surface": { capabilityGroup: "reusable-build", audience: ["consumer", "release-operator"], maturity: "stable", order: 200 },
@@ -724,6 +725,7 @@ function buildSiteBundle() {
724
725
  "docs/reusable-build-surface.md",
725
726
  "docs/release-candidate.md",
726
727
  "docs/stable-candidate-patrol.md",
728
+ "docs/dev-qualification-patrol.md",
727
729
  "docs/dev-alpha-candidate-patrol.md",
728
730
  "docs/observed-evidence-patrol.md",
729
731
  "docs/release-governance.md",
@@ -767,6 +769,7 @@ function buildSiteBundle() {
767
769
  ["build", "channel-build-router"],
768
770
  [".build", "reusable-build"],
769
771
  [".auditable-demo", "auditable-demo"],
772
+ [".declarative-auditable-demo", "declarative-auditable-demo"],
770
773
  ["web-surface", "site-app-deployment"],
771
774
  ["buildchain-ref-promotion", "release-governance"],
772
775
  ["release-line-bootstrap", "release-governance"],
@@ -783,6 +786,7 @@ function buildSiteBundle() {
783
786
  ["buildchain-patrol-weekly", "repository-patrol"],
784
787
  ["buildchain-patrol-monthly", "repository-patrol"],
785
788
  ["stable-candidate-patrol", "repository-patrol"],
789
+ ["dev-qualification-patrol", "repository-patrol"],
786
790
  ["dev-alpha-candidate-patrol", "repository-patrol"],
787
791
  ["buildchain-stable-candidate-patrol", "repository-patrol"],
788
792
  ["buildchain-stable-candidate-qualification", "repository-patrol"],
@@ -793,6 +797,7 @@ function buildSiteBundle() {
793
797
  ]);
794
798
  const statusById = new Map([
795
799
  [".auditable-demo", "preview"],
800
+ [".declarative-auditable-demo", "preview"],
796
801
  ["release-propagation", "preview"],
797
802
  ["candidate-lab", "repository-internal"],
798
803
  ["build-surface-fixture", "repository-internal"],
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { pathToFileURL } from "node:url";
5
5
 
6
6
  import { validateArtifactSigningRequest } from "../packages/core/artifact-signing.js";
7
+ import { artifactSigningRequestRoot } from "./artifact-signing-controller-core.mjs";
7
8
  import { writeGitHubOutputs } from "./build-contract-core.mjs";
8
9
 
9
10
  function required(value, label) {
@@ -35,12 +36,14 @@ export function inspectArtifactSigningRequests({
35
36
  inputRoot = process.env.BUILDCHAIN_SIGNING_REQUEST_ROOT,
36
37
  expectedRepository = process.env.BUILDCHAIN_SIGNING_SOURCE_REPOSITORY,
37
38
  expectedRuntimeSha = process.env.BUILDCHAIN_RUNTIME_SHA,
39
+ expectedRequestRoot = process.env.BUILDCHAIN_SIGNING_EXPECTED_REQUEST_ROOT,
38
40
  } = {}) {
39
41
  const root = path.resolve(required(inputRoot, "signing request root"));
40
42
  const indexes = walk(root, "index.json");
41
43
  if (indexes.length === 0)
42
44
  throw new Error("no artifact signing request indexes found");
43
45
  const seen = new Set();
46
+ const observedRoots = [];
44
47
  const matrices = {
45
48
  detached: [],
46
49
  macos: [],
@@ -52,6 +55,7 @@ export function inspectArtifactSigningRequests({
52
55
  index.contract !== "kungfu-buildchain-artifact-signing-request-index/v1"
53
56
  )
54
57
  continue;
58
+ observedRoots.push(artifactSigningRequestRoot(index));
55
59
  for (const entry of index.requests || []) {
56
60
  const requestPath = path.resolve(path.dirname(indexPath), entry.path);
57
61
  const relative = path.relative(root, requestPath);
@@ -113,6 +117,14 @@ export function inspectArtifactSigningRequests({
113
117
  );
114
118
  }
115
119
  }
120
+ if (expectedRequestRoot) {
121
+ if (observedRoots.length !== 1) {
122
+ throw new Error("signing authority expected exactly one request root");
123
+ }
124
+ if (observedRoots[0] !== expectedRequestRoot) {
125
+ throw new Error("signing authority request root mismatch");
126
+ }
127
+ }
116
128
  for (const entries of Object.values(matrices))
117
129
  entries.sort((a, b) => a.request.localeCompare(b.request));
118
130
  writeGitHubOutputs({
@@ -46,6 +46,14 @@ function normalizeFallback(value = "github") {
46
46
  return fallback;
47
47
  }
48
48
 
49
+ function normalizeHistoryMode(value = "shallow") {
50
+ const mode = String(value || "shallow").trim().toLowerCase() || "shallow";
51
+ if (!["shallow", "full"].includes(mode)) {
52
+ throw new Error(`checkout-history-mode must be shallow or full; got ${value}`);
53
+ }
54
+ return mode;
55
+ }
56
+
49
57
  function splitRepository(repository) {
50
58
  const match = String(repository || "").trim().match(/^([^/\s]+)\/([^/\s]+)$/);
51
59
  if (!match) {
@@ -237,19 +245,25 @@ export function fetchSourceCommit({
237
245
  sourceTreeSha = "",
238
246
  timeoutMs,
239
247
  env = {},
248
+ historyMode = readEnv("BUILDCHAIN_CHECKOUT_HISTORY_MODE", "shallow"),
240
249
  allowFullFetchRetry = false,
241
250
  runGit = git,
242
251
  containsCommit = hasCommit,
243
252
  }) {
253
+ const normalizedHistoryMode = normalizeHistoryMode(historyMode);
244
254
  const fetchEnv = isolatedGitFetchEnv(env, targetPath);
245
255
  const fetch = (refspec) => {
246
256
  const options = { cwd: targetPath, timeoutMs, env: fetchEnv };
257
+ const fetchArgs = ["fetch", "--no-tags"];
258
+ if (normalizedHistoryMode === "shallow") fetchArgs.push("--depth=1");
259
+ fetchArgs.push(remoteName, refspec);
247
260
  try {
248
- runGit(["fetch", "--no-tags", "--depth=1", remoteName, refspec], options);
249
- return "shallow";
261
+ runGit(fetchArgs, options);
262
+ return normalizedHistoryMode;
250
263
  } catch (error) {
251
264
  if (
252
- !allowFullFetchRetry
265
+ normalizedHistoryMode !== "shallow"
266
+ || !allowFullFetchRetry
253
267
  || !/dumb http transport does not support shallow capabilities/i.test(
254
268
  String(error?.message || error || ""),
255
269
  )