@kungfu-tech/buildchain 3.0.2-alpha.1 → 3.0.2-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 (78) hide show
  1. package/README.md +4 -2
  2. package/actions/github-artifact-attestation/README.md +10 -0
  3. package/actions/promote-buildchain-ref/README.md +7 -0
  4. package/bin/buildchain.mjs +5 -0
  5. package/bin/internal/trust-release-cli.mjs +74 -3
  6. package/contracts/auditable-demo-media-profiles-v1.json +168 -0
  7. package/contracts/evidence/auditable-demo-web-delivery-v1.json +103 -0
  8. package/contracts/fixtures/auditable-demo-web-delivery-v1/complete-transcript.txt +2 -0
  9. package/contracts/fixtures/auditable-demo-web-delivery-v1/public-projection.json +16 -0
  10. package/contracts/fixtures/auditable-demo-web-delivery-v1/scene.json +12 -0
  11. package/dist/site/artifact-schemas.json +5 -1
  12. package/dist/site/buildchain-contract.json +103 -34
  13. package/dist/site/buildchain-site.json +159 -40
  14. package/dist/site/capability-registry.json +13 -12
  15. package/dist/site/cli-registry.json +12 -0
  16. package/dist/site/controller-registry.json +48 -4
  17. package/dist/site/kfd-claims.json +320 -20
  18. package/dist/site/kfd-upstream-aggregate.json +1 -1
  19. package/dist/site/manual-registry.json +24 -9
  20. package/dist/site/node-api-registry.json +75 -10
  21. package/dist/site/page-registry.json +135 -25
  22. package/dist/site/public-surface-audit.json +197 -21
  23. package/dist/site/publication-authority-registry.json +72 -2
  24. package/dist/site/publication-registry.json +4 -4
  25. package/dist/site/release-model.json +2 -1
  26. package/dist/site/release-passport-check-manifest.json +1 -0
  27. package/dist/site/release-provenance.json +5 -0
  28. package/dist/site/schemas/release-passport-v1.schema.json +6 -0
  29. package/dist/site/site-manifest.json +21 -13
  30. package/dist/site/workflow-registry.json +161 -13
  31. package/docs/MAP.md +5 -1
  32. package/docs/auditable-demo.md +55 -3
  33. package/docs/binary-distribution.md +7 -0
  34. package/docs/cli.md +9 -0
  35. package/docs/dev-alpha-candidate-patrol.md +111 -0
  36. package/docs/github-artifact-attestation.md +219 -0
  37. package/docs/release-governance.md +32 -0
  38. package/docs/release-passport.md +13 -0
  39. package/docs/reusable-build-surface.md +83 -61
  40. package/docs/runtime-train-validation.md +21 -0
  41. package/docs/versioning.md +1 -0
  42. package/package.json +7 -1
  43. package/packages/core/artifact-signing-result.js +228 -0
  44. package/packages/core/artifact-signing.js +412 -0
  45. package/packages/core/buildchain-config.js +58 -0
  46. package/packages/core/buildchain-contract.js +14 -0
  47. package/packages/core/buildchain-kfd-claims.js +5 -0
  48. package/packages/core/buildchain-publication-authority.js +3 -0
  49. package/packages/core/channel-candidate.js +186 -0
  50. package/packages/core/detached-artifact-signature.js +121 -0
  51. package/packages/core/github-artifact-attestation.js +642 -0
  52. package/packages/core/github-governance-authority.js +6 -0
  53. package/packages/core/index.js +52 -0
  54. package/packages/core/publication-authority.js +1 -1
  55. package/packages/core/release-passport-contract.js +2 -0
  56. package/packages/core/release-passport.js +60 -3
  57. package/scripts/auditable-demo.mjs +520 -28
  58. package/scripts/build-contract-core.mjs +31 -0
  59. package/scripts/buildchain-channel-router.mjs +8 -2
  60. package/scripts/check-inventory.mjs +9 -0
  61. package/scripts/create-github-artifact-attestation-policy.mjs +62 -0
  62. package/scripts/dev-alpha-candidate-patrol.mjs +864 -0
  63. package/scripts/dispatch-artifact-signing-authority.mjs +152 -0
  64. package/scripts/finalize-native-artifact-signing-result.mjs +96 -0
  65. package/scripts/generate-channel-promotion-workflow.mjs +6 -0
  66. package/scripts/generate-site-bundle.mjs +19 -0
  67. package/scripts/import-artifact-signing-results.mjs +76 -0
  68. package/scripts/inspect-artifact-signing-requests.mjs +101 -0
  69. package/scripts/materialize-artifact-signing-request.mjs +66 -0
  70. package/scripts/merge-artifact-signing-results.mjs +76 -0
  71. package/scripts/publish-github-artifact-attestation-evidence.mjs +201 -0
  72. package/scripts/release-candidate-resolver.mjs +12 -0
  73. package/scripts/release-line-policy.mjs +27 -0
  74. package/scripts/runtime-ref-core.mjs +10 -6
  75. package/scripts/seal-artifact-signing-requests.mjs +368 -0
  76. package/scripts/sign-detached-artifact-requests.mjs +237 -0
  77. package/scripts/stage-github-artifact-attestation-inputs.mjs +65 -0
  78. package/scripts/verify-artifact-signing-results.mjs +99 -0
@@ -100,6 +100,12 @@ export {
100
100
  normalizeCandidateTimelineEvent,
101
101
  } from "./candidate-timeline.js";
102
102
 
103
+ export {
104
+ CHANNEL_CANDIDATE_DECISION_SCHEMA,
105
+ channelCandidateSourceLockRef,
106
+ decideChannelCandidate,
107
+ } from "./channel-candidate.js";
108
+
103
109
  export {
104
110
  BUILDCHAIN_ANCHORED_PACKAGE_RELEASE_VALIDATION_CONTRACT,
105
111
  BUILDCHAIN_DIAGNOSTICS_CONTRACT,
@@ -256,6 +262,33 @@ export {
256
262
  verifyArtifactVerificationEnvelope,
257
263
  } from "./artifact-verification-envelope.js";
258
264
 
265
+ export {
266
+ ARTIFACT_SIGNING_AUTHORITY_CONTRACT,
267
+ ARTIFACT_SIGNING_RECEIPT_CONTRACT,
268
+ ARTIFACT_SIGNING_REQUEST_CONTRACT,
269
+ artifactSigningDigest,
270
+ createArtifactSigningReceipt,
271
+ createArtifactSigningRequest,
272
+ listArtifactSigningProfiles,
273
+ resolveArtifactSigningProfile,
274
+ validateArtifactSigningReceipt,
275
+ validateArtifactSigningRequest,
276
+ } from "./artifact-signing.js";
277
+
278
+ export {
279
+ ARTIFACT_SIGNING_RESULT_CONTRACT,
280
+ artifactSigningEvidenceDigest,
281
+ createArtifactSigningResult,
282
+ validateArtifactSigningResult,
283
+ verifyArtifactSigningResultFiles,
284
+ } from "./artifact-signing-result.js";
285
+
286
+ export {
287
+ DETACHED_ARTIFACT_SIGNATURE_CONTRACT,
288
+ signDetachedArtifactRequest,
289
+ verifyDetachedArtifactSignature,
290
+ } from "./detached-artifact-signature.js";
291
+
259
292
  export {
260
293
  BUILDCHAIN_CONTRACT_LOCK,
261
294
  BUILDCHAIN_RUNTIME_CONTRACT_WORLD,
@@ -367,6 +400,25 @@ export {
367
400
  verifyReleasePassport,
368
401
  } from "./release-passport.js";
369
402
 
403
+ export {
404
+ GITHUB_ARTIFACT_ATTESTATION_EVIDENCE_CONTRACT,
405
+ GITHUB_ARTIFACT_ATTESTATION_POLICY_CONTRACT,
406
+ GITHUB_ARTIFACT_ATTESTATION_PREDICATE_CONTRACT,
407
+ GITHUB_ARTIFACT_ATTESTATION_PREDICATE_TYPE,
408
+ GITHUB_ARTIFACT_ATTESTATION_VERIFICATION_CONTRACT,
409
+ GITHUB_ARTIFACT_ATTESTATION_WORKFLOW,
410
+ createGitHubArtifactAttestationEvidence,
411
+ createGitHubArtifactAttestationPolicy,
412
+ createGitHubArtifactAttestationVerificationPlan,
413
+ githubArtifactAttestationRequiredPermissions,
414
+ githubArtifactAttestationSemanticRoot,
415
+ githubArtifactAttestationSha256Buffer,
416
+ githubArtifactAttestationSha256File,
417
+ normalizeGitHubArtifactAttestationPolicy,
418
+ prepareGitHubArtifactAttestation,
419
+ verifyGitHubArtifactAttestationEvidence,
420
+ } from "./github-artifact-attestation.js";
421
+
370
422
  export {
371
423
  KFD_AGENT_HUB_ADOPTION_CONTRACT,
372
424
  KFD_AGENT_HUB_ADOPTION_SCHEMA,
@@ -106,7 +106,7 @@ export function detectPublicationAuthoritySignals(workflowText = "") {
106
106
  const signals = [];
107
107
  const rules = [
108
108
  ["write-all", /permissions\s*:\s*write-all|permissions\s*:\s*\{[^}]*write-all/i],
109
- ["write-permission", /^\s*(?:contents|packages|deployments|checks|issues|pull-requests|actions)\s*:\s*write\s*$/im],
109
+ ["write-permission", /^\s*(?:contents|packages|deployments|checks|issues|pull-requests|actions|attestations|artifact-metadata)\s*:\s*write\s*$/im],
110
110
  ["oidc", /^\s*id-token\s*:\s*write\s*$/im],
111
111
  ["environment", /^\s*environment\s*:/im],
112
112
  ["npm-publish", /\bnpm\s+(?:stage\s+)?publish\b/i],
@@ -96,6 +96,7 @@ export const RELEASE_PASSPORT_SCHEMA = {
96
96
  platformArtifactManifests: { type: "array", items: OBJECT },
97
97
  distTagPromotion: OBJECT,
98
98
  controllerReceipts: { type: "array", items: OBJECT },
99
+ githubArtifactAttestations: { type: "array", items: OBJECT },
99
100
  "kfd-1": OBJECT,
100
101
  "kfd-2": OBJECT,
101
102
  "kfd-3": OBJECT,
@@ -123,6 +124,7 @@ const BUILDCHAIN_AGGREGATION_FIELDS = [
123
124
  "distTagPromotion",
124
125
  "controllerReceipts",
125
126
  "kfdSupport",
127
+ "githubArtifactAttestations",
126
128
  "artifacts",
127
129
  "evidence",
128
130
  "recovery",
@@ -21,6 +21,9 @@ import {
21
21
  import { createSurfaceTimestampPolicy } from "./surface-manifest.js";
22
22
  import { validatePublishEvidence as validateTransactionPublishEvidence } from "./publish-transaction.js";
23
23
  import { normalizeControllerReceiptReferences } from "./controller-evidence.js";
24
+ import {
25
+ normalizeGitHubArtifactAttestationPolicy,
26
+ } from "./github-artifact-attestation.js";
24
27
 
25
28
  export const RELEASE_PASSPORT_CONTRACT = "kungfu-buildchain-release-passport";
26
29
  export const ARTIFACT_EVIDENCE_CONTRACT = "kungfu-buildchain-artifact-evidence";
@@ -1166,6 +1169,8 @@ export function createReleasePassport({
1166
1169
  kfdAgentHubEvidencePath = "",
1167
1170
  controllerReceipts = [],
1168
1171
  controllerReceiptReferences = [],
1172
+ githubArtifactAttestations = [],
1173
+ checkedAt = "",
1169
1174
  } = {}) {
1170
1175
  const normalizedTag = nonEmptyString(tag, "tag");
1171
1176
  const artifactEvidence = createArtifactEvidence({ assets, repository, tag: normalizedTag, sourceSha, workflow });
@@ -1185,7 +1190,7 @@ export function createReleasePassport({
1185
1190
  ? normalizeEvidenceDocument(distTagPromotionEvidence, "distTagPromotionEvidence")
1186
1191
  : undefined;
1187
1192
  const normalizedImpact = normalizeImpactLedger(impact, { tag: normalizedTag, line });
1188
- const generatedAt = nowIso();
1193
+ const generatedAt = optionalString(checkedAt) || nowIso();
1189
1194
  const kfd1Metadata = resolveKfd1Metadata();
1190
1195
  const normalizedKfd1 = kfd1?.passportSection ? kfd1 : undefined;
1191
1196
  const normalizedKfd3 = kfd3?.passportSection ? kfd3 : undefined;
@@ -1231,6 +1236,8 @@ export function createReleasePassport({
1231
1236
  : [],
1232
1237
  requirePassed: true,
1233
1238
  });
1239
+ const normalizedGitHubArtifactAttestations = (githubArtifactAttestations || [])
1240
+ .map(normalizeGitHubArtifactAttestationPolicy);
1234
1241
  const publishArtifacts = normalizedPublishEvidence?.artifacts || [];
1235
1242
  const normalizedPublishSummary = normalizePublishSummary({
1236
1243
  packageSet: normalizedPackageSet,
@@ -1360,6 +1367,9 @@ export function createReleasePassport({
1360
1367
  ...(normalizedKfdAgentHub ? { kfdAgentHub: normalizedKfdAgentHub } : {}),
1361
1368
  ...(invariantPassports ? { invariantPassports } : {}),
1362
1369
  ...(normalizedControllerReceipts.length > 0 ? { controllerReceipts: normalizedControllerReceipts } : {}),
1370
+ ...(normalizedGitHubArtifactAttestations.length > 0
1371
+ ? { githubArtifactAttestations: normalizedGitHubArtifactAttestations }
1372
+ : {}),
1363
1373
  versionImpact: normalizedImpact.versionImpact,
1364
1374
  surfaceImpacts: normalizedImpact.surfaceImpacts,
1365
1375
  artifacts: [
@@ -1450,11 +1460,13 @@ export function collectGitHubReleasePassport({
1450
1460
  invariantPassportCommand = "",
1451
1461
  kfdAgentHubEvidenceJson = "",
1452
1462
  controllerReceiptReferences = [],
1463
+ githubArtifactAttestationPolicyJsons = [],
1453
1464
  basePassportJson = "",
1454
1465
  requireBaseKfd = false,
1455
1466
  releaseJsonExtra = "",
1456
1467
  publishJson = "",
1457
1468
  workflow = {},
1469
+ checkedAt = "",
1458
1470
  } = {}) {
1459
1471
  const release = parseJsonInput(releaseJson, {}, { cwd, label: "releaseJson" });
1460
1472
  const releaseExtra = parseJsonInput(releaseJsonExtra, {}, { cwd, label: "releaseJsonExtra" });
@@ -1526,6 +1538,13 @@ export function collectGitHubReleasePassport({
1526
1538
  undefined,
1527
1539
  { cwd, label: "kfdAgentHubEvidenceJson" },
1528
1540
  );
1541
+ const githubArtifactAttestationPolicies = (githubArtifactAttestationPolicyJsons || [])
1542
+ .filter(Boolean)
1543
+ .map((policyJson) => parseJsonInput(policyJson, undefined, {
1544
+ cwd,
1545
+ label: "githubArtifactAttestationPolicyJsons entry",
1546
+ }))
1547
+ .map(normalizeGitHubArtifactAttestationPolicy);
1529
1548
  const kfd3ArtifactWitnesses = [
1530
1549
  ...kfd3ArtifactWitnessMetas.map((meta) => meta.value),
1531
1550
  ...(kfd3ArtifactCommandMeta.value ? [kfd3ArtifactCommandMeta.value] : []),
@@ -1541,6 +1560,7 @@ export function collectGitHubReleasePassport({
1541
1560
  ];
1542
1561
  const resolvedTag = tag || release.tag_name || release.name || "";
1543
1562
  const resolvedOutputDir = path.resolve(cwd, outputDir);
1563
+ const resolvedCheckedAt = optionalString(checkedAt) || nowIso();
1544
1564
  const productMechanism = defaultProductMechanism({ repository, productName });
1545
1565
  const artifactEvidence = createArtifactEvidence({ assets, repository, tag: resolvedTag, sourceSha, workflow });
1546
1566
  const bundledPublishEvidencePath = publishEvidenceMeta.value ? "evidence.json" : "";
@@ -1568,7 +1588,7 @@ export function collectGitHubReleasePassport({
1568
1588
  matrixRoot: kfdSupportMatrixMeta.sha256 ? `sha256:${kfdSupportMatrixMeta.sha256}` : "",
1569
1589
  gateResults: kfdProductGateMetas.map((meta) => meta.value),
1570
1590
  expectedSourceSha: sourceSha,
1571
- checkedAt: nowIso(),
1591
+ checkedAt: resolvedCheckedAt,
1572
1592
  })
1573
1593
  : undefined;
1574
1594
  const passport = mergeAuthoritativePassportBase(createReleasePassport({
@@ -1623,9 +1643,11 @@ export function collectGitHubReleasePassport({
1623
1643
  : undefined,
1624
1644
  kfdAgentHubEvidencePath: kfdAgentHubEvidenceMeta.value ? "kfd-agent-hub-evidence.json" : "",
1625
1645
  controllerReceiptReferences,
1646
+ githubArtifactAttestations: githubArtifactAttestationPolicies,
1626
1647
  publishEvidencePath: publishEvidenceMeta.path ? path.relative(resolvedOutputDir, publishEvidenceMeta.path).split(path.sep).join("/") : "",
1627
1648
  transactionStatePath: transactionMeta.path ? path.relative(resolvedOutputDir, transactionMeta.path).split(path.sep).join("/") : "",
1628
1649
  workflow,
1650
+ checkedAt: resolvedCheckedAt,
1629
1651
  }), basePassportMeta.value, { requireKfd: requireBaseKfd });
1630
1652
  if (bundledPublishEvidencePath) {
1631
1653
  passport.evidence.publishEvidence = bundledPublishEvidencePath;
@@ -1639,7 +1661,7 @@ export function collectGitHubReleasePassport({
1639
1661
  productMechanism,
1640
1662
  kfdAgentHubEvidence: kfdAgentHubEvidenceMeta.value,
1641
1663
  kfdSupportEvidence: kfdSupport,
1642
- checkedAt: nowIso(),
1664
+ checkedAt: resolvedCheckedAt,
1643
1665
  });
1644
1666
  const files = {
1645
1667
  "product-mechanism.json": productMechanism,
@@ -1972,6 +1994,39 @@ export function createReleaseCheckReport({
1972
1994
  issues.push(issue("error", "kfdSupport.section", "KFD support evidence is present without a release-passport projection"));
1973
1995
  }
1974
1996
 
1997
+ for (const [index, value] of (passport?.githubArtifactAttestations || []).entries()) {
1998
+ try {
1999
+ const policy = normalizeGitHubArtifactAttestationPolicy(value);
2000
+ if (policy.caller.sourceSha !== String(passport?.release?.sourceSha || "").toLowerCase()) {
2001
+ issues.push(issue(
2002
+ "error",
2003
+ `githubArtifactAttestations[${index}].caller.sourceSha`,
2004
+ "attestation policy source SHA must match passport.release.sourceSha",
2005
+ ));
2006
+ }
2007
+ const artifact = (passport?.artifacts || []).find((entry) => entry.name === policy.subject.name);
2008
+ if (!artifact) {
2009
+ issues.push(issue(
2010
+ "error",
2011
+ `githubArtifactAttestations[${index}].subject.name`,
2012
+ `attestation subject ${policy.subject.name} is absent from the Release Passport artifacts`,
2013
+ ));
2014
+ } else if (artifact.sha256 !== policy.subject.digest.sha256) {
2015
+ issues.push(issue(
2016
+ "error",
2017
+ `githubArtifactAttestations[${index}].subject.digest`,
2018
+ `attestation subject ${policy.subject.name} digest differs from the Release Passport artifact`,
2019
+ ));
2020
+ }
2021
+ } catch (error) {
2022
+ issues.push(issue(
2023
+ "error",
2024
+ `githubArtifactAttestations[${index}]`,
2025
+ error.message,
2026
+ ));
2027
+ }
2028
+ }
2029
+
1975
2030
  const tag = passport?.release?.tag || "";
1976
2031
  if (!tag) {
1977
2032
  issues.push(issue("error", "release.tag", "release.tag is required"));
@@ -2422,6 +2477,7 @@ export async function verifyReleasePassport({
2422
2477
  productMechanismLocation = "",
2423
2478
  kfdAgentHubEvidenceLocation = "",
2424
2479
  kfdSupportEvidenceLocation = "",
2480
+ checkedAt = nowIso(),
2425
2481
  } = {}) {
2426
2482
  const passport = await readJsonFromLocation(passportLocation);
2427
2483
  const basePath = /^https?:\/\//.test(passportLocation) ? passportLocation : path.resolve(passportLocation);
@@ -2462,6 +2518,7 @@ export async function verifyReleasePassport({
2462
2518
  productMechanism,
2463
2519
  kfdAgentHubEvidence,
2464
2520
  kfdSupportEvidence,
2521
+ checkedAt,
2465
2522
  });
2466
2523
  }
2467
2524