@kungfu-tech/buildchain 3.0.2-alpha.0 → 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 (83) 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 +133 -34
  13. package/dist/site/buildchain-site.json +159 -40
  14. package/dist/site/capability-registry.json +14 -13
  15. package/dist/site/cli-registry.json +12 -0
  16. package/dist/site/controller-registry.json +72 -4
  17. package/dist/site/kfd-claims.json +338 -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 +89 -11
  21. package/dist/site/page-registry.json +135 -25
  22. package/dist/site/public-surface-audit.json +203 -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 +6 -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 +167 -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 +8 -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/cache-evidence.js +288 -0
  50. package/packages/core/channel-candidate.js +186 -0
  51. package/packages/core/detached-artifact-signature.js +121 -0
  52. package/packages/core/diagnostics.js +276 -10
  53. package/packages/core/github-artifact-attestation.js +642 -0
  54. package/packages/core/github-governance-authority.js +77 -16
  55. package/packages/core/index.js +62 -0
  56. package/packages/core/publication-authority.js +1 -1
  57. package/packages/core/release-passport-contract.js +2 -0
  58. package/packages/core/release-passport.js +60 -3
  59. package/scripts/auditable-demo.mjs +520 -28
  60. package/scripts/build-contract-core.mjs +31 -0
  61. package/scripts/buildchain-channel-router.mjs +8 -2
  62. package/scripts/check-inventory.mjs +9 -0
  63. package/scripts/create-github-artifact-attestation-policy.mjs +62 -0
  64. package/scripts/dev-alpha-candidate-patrol.mjs +864 -0
  65. package/scripts/dispatch-artifact-signing-authority.mjs +152 -0
  66. package/scripts/finalize-native-artifact-signing-result.mjs +96 -0
  67. package/scripts/generate-channel-promotion-workflow.mjs +6 -0
  68. package/scripts/generate-site-bundle.mjs +20 -0
  69. package/scripts/import-artifact-signing-results.mjs +76 -0
  70. package/scripts/inspect-artifact-signing-requests.mjs +101 -0
  71. package/scripts/locked-source-checkout.mjs +48 -0
  72. package/scripts/materialize-artifact-signing-request.mjs +66 -0
  73. package/scripts/merge-artifact-signing-results.mjs +76 -0
  74. package/scripts/publish-github-artifact-attestation-evidence.mjs +201 -0
  75. package/scripts/reconcile-github-governance.mjs +158 -25
  76. package/scripts/release-candidate-resolver.mjs +12 -0
  77. package/scripts/release-line-policy.mjs +27 -0
  78. package/scripts/runtime-ref-core.mjs +10 -6
  79. package/scripts/seal-artifact-signing-requests.mjs +368 -0
  80. package/scripts/shifu-gate-profile.mjs +26 -20
  81. package/scripts/sign-detached-artifact-requests.mjs +237 -0
  82. package/scripts/stage-github-artifact-attestation-inputs.mjs +65 -0
  83. package/scripts/verify-artifact-signing-results.mjs +99 -0
@@ -49,6 +49,7 @@ const PUBLIC_REPOSITORY_TARGETS = Object.freeze({
49
49
  target("dev/v3/v3.0", [check("check")], false),
50
50
  target("alpha/v3/v3.0", [check("check"), check("verify")], false),
51
51
  target("release/v3/v3.0", [check("check")], true),
52
+ target("authority/v3/v3.0/artifact-signing", [check("check"), check("verify")], true),
52
53
  target("publish-gate/major", [check("check")], true),
53
54
  ],
54
55
  "homebrew-tap": [
@@ -65,6 +66,11 @@ const PUBLIC_REPOSITORY_TARGETS = Object.freeze({
65
66
  check("signoff"),
66
67
  check("validate"),
67
68
  ], true),
69
+ target("release/v4/v4.0", [
70
+ check("build", null),
71
+ check("signoff"),
72
+ check("validate"),
73
+ ], true),
68
74
  ],
69
75
  libnode: [
70
76
  target("dev/v22/v22.22", [check("build")], true),
@@ -1191,20 +1197,38 @@ export function createGithubRulesetGovernanceRolloutPlan({
1191
1197
  repository,
1192
1198
  targetRef,
1193
1199
  rulesetId,
1200
+ rulesetName,
1194
1201
  inventory,
1195
1202
  rollbackSnapshot,
1196
1203
  desiredProtection,
1197
1204
  } = {}) {
1198
1205
  const fullName = requiredString(repository, "repository");
1199
1206
  const branch = normalizedRef(targetRef);
1200
- const id = Number(rulesetId);
1201
- if (!Number.isInteger(id) || id <= 0) {
1202
- throw new Error("ruleset id must be a positive integer");
1207
+ const creating = rulesetId === null || rulesetId === undefined || rulesetId === "";
1208
+ const id = creating ? null : Number(rulesetId);
1209
+ if (!creating && (!Number.isInteger(id) || id <= 0)) {
1210
+ throw new Error("ruleset id must be a positive integer when supplied");
1203
1211
  }
1204
- if (!inventory || !rollbackSnapshot) {
1205
- throw new Error("read-only inventory and frozen rollback snapshot are required");
1212
+ if (!inventory || (!creating && !rollbackSnapshot)) {
1213
+ throw new Error(
1214
+ "read-only inventory and any existing frozen rollback snapshot are required",
1215
+ );
1206
1216
  }
1207
- const before = normalizeGithubRulesetSnapshot(rollbackSnapshot);
1217
+ const before = creating
1218
+ ? {
1219
+ name: requiredString(rulesetName, "ruleset name"),
1220
+ target: "branch",
1221
+ enforcement: "active",
1222
+ bypass_actors: [],
1223
+ conditions: {
1224
+ ref_name: {
1225
+ include: [`refs/heads/${branch}`],
1226
+ exclude: [],
1227
+ },
1228
+ },
1229
+ rules: [],
1230
+ }
1231
+ : normalizeGithubRulesetSnapshot(rollbackSnapshot);
1208
1232
  const exactInclude = before.conditions?.ref_name?.include || [];
1209
1233
  const exactExclude = before.conditions?.ref_name?.exclude || [];
1210
1234
  if (
@@ -1265,28 +1289,53 @@ export function createGithubRulesetGovernanceRolloutPlan({
1265
1289
  });
1266
1290
  if (pullRequestRules.length === 0) desiredRules.push(desiredPullRequestRule);
1267
1291
  if (statusCheckRules.length === 0) desiredRules.push(desiredStatusCheckRule);
1292
+ if (
1293
+ desiredProtection?.blockDeletions === true &&
1294
+ !desiredRules.some((rule) => rule.type === "deletion")
1295
+ ) {
1296
+ desiredRules.push({ type: "deletion" });
1297
+ }
1298
+ if (
1299
+ desiredProtection?.blockNonFastForward === true &&
1300
+ !desiredRules.some((rule) => rule.type === "non_fast_forward")
1301
+ ) {
1302
+ desiredRules.push({ type: "non_fast_forward" });
1303
+ }
1268
1304
  const desired = {
1269
1305
  ...before,
1306
+ name: rulesetName
1307
+ ? requiredString(rulesetName, "ruleset name")
1308
+ : before.name,
1270
1309
  bypass_actors: providerRulesetBypassActors(
1271
1310
  desiredProtection?.rulesetBypassActors,
1272
1311
  ),
1273
1312
  rules: desiredRules,
1274
1313
  };
1275
- const endpoint = `repos/${fullName}/rulesets/${id}`;
1314
+ const endpoint = creating
1315
+ ? `repos/${fullName}/rulesets`
1316
+ : `repos/${fullName}/rulesets/${id}`;
1276
1317
  const core = {
1277
1318
  schemaVersion: 1,
1278
1319
  contract: GITHUB_GOVERNANCE_RULESET_ROLLOUT_CONTRACT,
1279
1320
  repository: fullName,
1280
1321
  targetRef: branch,
1281
1322
  rulesetId: id,
1323
+ rulesetName: desired.name,
1324
+ action: creating ? "create" : "update",
1282
1325
  inventoryRoot: githubGovernanceDigest(inventory),
1283
- rollbackSnapshotRoot: githubGovernanceDigest(before),
1284
- operations: [{ method: "PUT", endpoint, body: desired }],
1326
+ rollbackSnapshotRoot: creating
1327
+ ? githubGovernanceDigest({ rulesetExists: false, targetRef: branch })
1328
+ : githubGovernanceDigest(before),
1329
+ operations: [
1330
+ { method: creating ? "POST" : "PUT", endpoint, body: desired },
1331
+ ],
1285
1332
  impact: [
1286
1333
  "replace ruleset bypass actors with the exact provider-admitted desired set",
1287
1334
  "require fresh Code Owner review and resolved review threads",
1288
1335
  "bind required status checks and strictness to the authoritative target descriptor",
1289
- "preserve unrelated ruleset rules and exact target conditions",
1336
+ creating
1337
+ ? "create one exact-branch active ruleset because no matching ruleset exists"
1338
+ : "preserve unrelated ruleset rules and exact target conditions",
1290
1339
  ],
1291
1340
  expectedObservation: {
1292
1341
  rulesetRoot: githubGovernanceDigest(desired),
@@ -1296,12 +1345,24 @@ export function createGithubRulesetGovernanceRolloutPlan({
1296
1345
  desiredProtection?.strictRequiredChecks === true,
1297
1346
  requiredApprovals,
1298
1347
  },
1299
- rollback: [{
1300
- method: "PUT",
1301
- endpoint,
1302
- body: before,
1303
- preconditionRoot: githubGovernanceDigest(before),
1304
- }],
1348
+ rollback: creating
1349
+ ? [
1350
+ {
1351
+ method: "DELETE",
1352
+ endpoint: `repos/${fullName}/rulesets/{ruleset_id}`,
1353
+ body: null,
1354
+ preconditionRoot: githubGovernanceDigest(desired),
1355
+ requiresApplyReceipt: true,
1356
+ },
1357
+ ]
1358
+ : [
1359
+ {
1360
+ method: "PUT",
1361
+ endpoint,
1362
+ body: before,
1363
+ preconditionRoot: githubGovernanceDigest(before),
1364
+ },
1365
+ ],
1305
1366
  };
1306
1367
  return { ...core, planRoot: githubGovernanceDigest(core) };
1307
1368
  }
@@ -64,6 +64,16 @@ export {
64
64
  verifyPortableDevCachePlan,
65
65
  } from "./portable-dev-cache.js";
66
66
 
67
+ export {
68
+ BUILDCHAIN_CACHE_EVIDENCE_SET_CONTRACT,
69
+ BUILDCHAIN_CACHE_OPERATION_RECEIPT_CONTRACT,
70
+ cacheEvidenceDigest,
71
+ createCacheEvidenceSet,
72
+ createCacheOperationReceipt,
73
+ verifyCacheEvidenceSet,
74
+ verifyCacheOperationReceipt,
75
+ } from "./cache-evidence.js";
76
+
67
77
  export {
68
78
  explainReleaseLineDryRun,
69
79
  formatReleaseLineDryRun,
@@ -90,6 +100,12 @@ export {
90
100
  normalizeCandidateTimelineEvent,
91
101
  } from "./candidate-timeline.js";
92
102
 
103
+ export {
104
+ CHANNEL_CANDIDATE_DECISION_SCHEMA,
105
+ channelCandidateSourceLockRef,
106
+ decideChannelCandidate,
107
+ } from "./channel-candidate.js";
108
+
93
109
  export {
94
110
  BUILDCHAIN_ANCHORED_PACKAGE_RELEASE_VALIDATION_CONTRACT,
95
111
  BUILDCHAIN_DIAGNOSTICS_CONTRACT,
@@ -246,6 +262,33 @@ export {
246
262
  verifyArtifactVerificationEnvelope,
247
263
  } from "./artifact-verification-envelope.js";
248
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
+
249
292
  export {
250
293
  BUILDCHAIN_CONTRACT_LOCK,
251
294
  BUILDCHAIN_RUNTIME_CONTRACT_WORLD,
@@ -357,6 +400,25 @@ export {
357
400
  verifyReleasePassport,
358
401
  } from "./release-passport.js";
359
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
+
360
422
  export {
361
423
  KFD_AGENT_HUB_ADOPTION_CONTRACT,
362
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