@kungfu-tech/buildchain 3.0.2-alpha.6 → 3.0.2-alpha.8

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 (54) hide show
  1. package/README.md +3 -2
  2. package/contracts/auditable-demo-media-profiles-v1.json +168 -0
  3. package/contracts/evidence/auditable-demo-web-delivery-v1.json +103 -0
  4. package/contracts/fixtures/auditable-demo-web-delivery-v1/complete-transcript.txt +2 -0
  5. package/contracts/fixtures/auditable-demo-web-delivery-v1/public-projection.json +16 -0
  6. package/contracts/fixtures/auditable-demo-web-delivery-v1/scene.json +12 -0
  7. package/dist/site/buildchain-contract.json +45 -27
  8. package/dist/site/buildchain-site.json +42 -32
  9. package/dist/site/capability-registry.json +3 -3
  10. package/dist/site/controller-registry.json +11 -3
  11. package/dist/site/kfd-claims.json +74 -8
  12. package/dist/site/kfd-upstream-aggregate.json +1 -1
  13. package/dist/site/manual-registry.json +7 -7
  14. package/dist/site/node-api-registry.json +44 -5
  15. package/dist/site/page-registry.json +30 -20
  16. package/dist/site/public-surface-audit.json +38 -10
  17. package/dist/site/publication-authority-registry.json +26 -1
  18. package/dist/site/publication-registry.json +4 -4
  19. package/dist/site/release-provenance.json +3 -0
  20. package/dist/site/site-manifest.json +11 -11
  21. package/dist/site/workflow-registry.json +41 -7
  22. package/docs/MAP.md +2 -0
  23. package/docs/auditable-demo.md +55 -3
  24. package/docs/dev-alpha-candidate-patrol.md +9 -0
  25. package/docs/github-artifact-attestation.md +1 -1
  26. package/docs/release-governance.md +32 -0
  27. package/docs/reusable-build-surface.md +73 -58
  28. package/docs/runtime-train-validation.md +21 -0
  29. package/docs/versioning.md +1 -0
  30. package/package.json +5 -1
  31. package/packages/core/artifact-signing-result.js +228 -0
  32. package/packages/core/artifact-signing.js +412 -0
  33. package/packages/core/buildchain-config.js +58 -0
  34. package/packages/core/buildchain-contract.js +8 -0
  35. package/packages/core/buildchain-publication-authority.js +1 -0
  36. package/packages/core/detached-artifact-signature.js +121 -0
  37. package/packages/core/github-governance-authority.js +6 -0
  38. package/packages/core/index.js +27 -0
  39. package/scripts/auditable-demo.mjs +491 -22
  40. package/scripts/buildchain-channel-router.mjs +8 -2
  41. package/scripts/check-inventory.mjs +5 -0
  42. package/scripts/dev-alpha-candidate-patrol.mjs +18 -0
  43. package/scripts/dispatch-artifact-signing-authority.mjs +152 -0
  44. package/scripts/finalize-native-artifact-signing-result.mjs +96 -0
  45. package/scripts/generate-site-bundle.mjs +3 -0
  46. package/scripts/import-artifact-signing-results.mjs +76 -0
  47. package/scripts/inspect-artifact-signing-requests.mjs +101 -0
  48. package/scripts/materialize-artifact-signing-request.mjs +66 -0
  49. package/scripts/merge-artifact-signing-results.mjs +76 -0
  50. package/scripts/release-line-policy.mjs +27 -0
  51. package/scripts/runtime-ref-core.mjs +10 -6
  52. package/scripts/seal-artifact-signing-requests.mjs +368 -0
  53. package/scripts/sign-detached-artifact-requests.mjs +237 -0
  54. package/scripts/verify-artifact-signing-results.mjs +99 -0
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+
6
+ import {
7
+ validateArtifactSigningRequest,
8
+ } from "../packages/core/artifact-signing.js";
9
+ import {
10
+ verifyArtifactSigningResultFiles,
11
+ } from "../packages/core/artifact-signing-result.js";
12
+ import { writeGitHubOutputs } from "./build-contract-core.mjs";
13
+
14
+ function required(value, label) {
15
+ const normalized = String(value || "").trim();
16
+ if (!normalized) throw new Error(`${label} is required`);
17
+ return normalized;
18
+ }
19
+
20
+ function resolveBelow(root, relative, label) {
21
+ const resolvedRoot = path.resolve(root);
22
+ const target = path.resolve(resolvedRoot, required(relative, label));
23
+ const rel = path.relative(resolvedRoot, target);
24
+ if (!rel || rel.startsWith("..") || path.isAbsolute(rel)) {
25
+ throw new Error(`${label} must resolve below its root`);
26
+ }
27
+ return target;
28
+ }
29
+
30
+ export function verifyArtifactSigningResults({
31
+ requestRoot = process.env.BUILDCHAIN_SIGNING_REQUEST_ROOT,
32
+ resultRoot = process.env.BUILDCHAIN_SIGNING_RESULT_ROOT,
33
+ } = {}) {
34
+ const requests = path.resolve(required(requestRoot, "signing request root"));
35
+ const results = path.resolve(required(resultRoot, "signing result root"));
36
+ const requestIndex = JSON.parse(
37
+ fs.readFileSync(path.join(requests, "index.json"), "utf8"),
38
+ );
39
+ const resultIndex = JSON.parse(
40
+ fs.readFileSync(path.join(results, "index.json"), "utf8"),
41
+ );
42
+ if (requestIndex.contract !== "kungfu-buildchain-artifact-signing-request-index/v1") {
43
+ throw new Error("artifact signing request index contract mismatch");
44
+ }
45
+ if (resultIndex.contract !== "kungfu-buildchain-artifact-signing-result-index/v1") {
46
+ throw new Error("artifact signing result index contract mismatch");
47
+ }
48
+ const expected = new Map((requestIndex.requests || []).map((entry) => [entry.id, entry]));
49
+ const verified = [];
50
+ for (const entry of resultIndex.results || []) {
51
+ const requestEntry = expected.get(entry.id);
52
+ if (!requestEntry) throw new Error(`unexpected signing result: ${entry.id}`);
53
+ const request = JSON.parse(
54
+ fs.readFileSync(resolveBelow(requests, requestEntry.path, "request path"), "utf8"),
55
+ );
56
+ const requestCheck = validateArtifactSigningRequest(request);
57
+ if (!requestCheck.ok || request.digest !== requestEntry.digest) {
58
+ throw new Error(`invalid sealed signing request: ${entry.id}`);
59
+ }
60
+ const resultPath = resolveBelow(results, entry.result, "result path");
61
+ const resultDirectory = path.dirname(resultPath);
62
+ const result = JSON.parse(fs.readFileSync(resultPath, "utf8"));
63
+ const receipt = JSON.parse(
64
+ fs.readFileSync(resolveBelow(resultDirectory, result.receipt.path, "receipt path"), "utf8"),
65
+ );
66
+ const check = verifyArtifactSigningResultFiles({
67
+ root: resultDirectory,
68
+ request,
69
+ receipt,
70
+ result,
71
+ });
72
+ if (!check.ok) {
73
+ throw new Error(`invalid signing result ${entry.id}: ${check.issues.join(", ")}`);
74
+ }
75
+ if (entry.requestDigest !== request.digest || entry.resultDigest !== result.digest) {
76
+ throw new Error(`signing result index binding mismatch: ${entry.id}`);
77
+ }
78
+ expected.delete(entry.id);
79
+ verified.push({ id: entry.id, resultDigest: result.digest });
80
+ }
81
+ const missingRequired = [...expected.values()].filter((entry) => entry.required !== false);
82
+ if (missingRequired.length > 0) {
83
+ throw new Error(`missing required signing results: ${missingRequired.map((entry) => entry.id).join(", ")}`);
84
+ }
85
+ writeGitHubOutputs({
86
+ "verified-count": String(verified.length),
87
+ "verified-result-root": results,
88
+ });
89
+ return { ok: true, verified };
90
+ }
91
+
92
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
93
+ try {
94
+ verifyArtifactSigningResults();
95
+ } catch (error) {
96
+ console.error(`::error::${String(error?.message || error).replace(/\r?\n/gu, "%0A")}`);
97
+ process.exitCode = 1;
98
+ }
99
+ }