@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.
- package/README.md +4 -2
- package/actions/github-artifact-attestation/README.md +10 -0
- package/actions/promote-buildchain-ref/README.md +7 -0
- package/bin/buildchain.mjs +5 -0
- package/bin/internal/trust-release-cli.mjs +74 -3
- package/contracts/auditable-demo-media-profiles-v1.json +168 -0
- package/contracts/evidence/auditable-demo-web-delivery-v1.json +103 -0
- package/contracts/fixtures/auditable-demo-web-delivery-v1/complete-transcript.txt +2 -0
- package/contracts/fixtures/auditable-demo-web-delivery-v1/public-projection.json +16 -0
- package/contracts/fixtures/auditable-demo-web-delivery-v1/scene.json +12 -0
- package/dist/site/artifact-schemas.json +5 -1
- package/dist/site/buildchain-contract.json +133 -34
- package/dist/site/buildchain-site.json +159 -40
- package/dist/site/capability-registry.json +14 -13
- package/dist/site/cli-registry.json +12 -0
- package/dist/site/controller-registry.json +72 -4
- package/dist/site/kfd-claims.json +338 -20
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +24 -9
- package/dist/site/node-api-registry.json +89 -11
- package/dist/site/page-registry.json +135 -25
- package/dist/site/public-surface-audit.json +203 -21
- package/dist/site/publication-authority-registry.json +72 -2
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-model.json +2 -1
- package/dist/site/release-passport-check-manifest.json +1 -0
- package/dist/site/release-provenance.json +6 -0
- package/dist/site/schemas/release-passport-v1.schema.json +6 -0
- package/dist/site/site-manifest.json +21 -13
- package/dist/site/workflow-registry.json +167 -13
- package/docs/MAP.md +5 -1
- package/docs/auditable-demo.md +55 -3
- package/docs/binary-distribution.md +7 -0
- package/docs/cli.md +9 -0
- package/docs/dev-alpha-candidate-patrol.md +111 -0
- package/docs/github-artifact-attestation.md +219 -0
- package/docs/release-governance.md +32 -0
- package/docs/release-passport.md +13 -0
- package/docs/reusable-build-surface.md +83 -61
- package/docs/runtime-train-validation.md +21 -0
- package/docs/versioning.md +1 -0
- package/package.json +8 -1
- package/packages/core/artifact-signing-result.js +228 -0
- package/packages/core/artifact-signing.js +412 -0
- package/packages/core/buildchain-config.js +58 -0
- package/packages/core/buildchain-contract.js +14 -0
- package/packages/core/buildchain-kfd-claims.js +5 -0
- package/packages/core/buildchain-publication-authority.js +3 -0
- package/packages/core/cache-evidence.js +288 -0
- package/packages/core/channel-candidate.js +186 -0
- package/packages/core/detached-artifact-signature.js +121 -0
- package/packages/core/diagnostics.js +276 -10
- package/packages/core/github-artifact-attestation.js +642 -0
- package/packages/core/github-governance-authority.js +77 -16
- package/packages/core/index.js +62 -0
- package/packages/core/publication-authority.js +1 -1
- package/packages/core/release-passport-contract.js +2 -0
- package/packages/core/release-passport.js +60 -3
- package/scripts/auditable-demo.mjs +520 -28
- package/scripts/build-contract-core.mjs +31 -0
- package/scripts/buildchain-channel-router.mjs +8 -2
- package/scripts/check-inventory.mjs +9 -0
- package/scripts/create-github-artifact-attestation-policy.mjs +62 -0
- package/scripts/dev-alpha-candidate-patrol.mjs +864 -0
- package/scripts/dispatch-artifact-signing-authority.mjs +152 -0
- package/scripts/finalize-native-artifact-signing-result.mjs +96 -0
- package/scripts/generate-channel-promotion-workflow.mjs +6 -0
- package/scripts/generate-site-bundle.mjs +20 -0
- package/scripts/import-artifact-signing-results.mjs +76 -0
- package/scripts/inspect-artifact-signing-requests.mjs +101 -0
- package/scripts/locked-source-checkout.mjs +48 -0
- package/scripts/materialize-artifact-signing-request.mjs +66 -0
- package/scripts/merge-artifact-signing-results.mjs +76 -0
- package/scripts/publish-github-artifact-attestation-evidence.mjs +201 -0
- package/scripts/reconcile-github-governance.mjs +158 -25
- package/scripts/release-candidate-resolver.mjs +12 -0
- package/scripts/release-line-policy.mjs +27 -0
- package/scripts/runtime-ref-core.mjs +10 -6
- package/scripts/seal-artifact-signing-requests.mjs +368 -0
- package/scripts/shifu-gate-profile.mjs +26 -20
- package/scripts/sign-detached-artifact-requests.mjs +237 -0
- package/scripts/stage-github-artifact-attestation-inputs.mjs +65 -0
- 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
|
|
1201
|
-
|
|
1202
|
-
|
|
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(
|
|
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 =
|
|
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 =
|
|
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:
|
|
1284
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
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
|
}
|
package/packages/core/index.js
CHANGED
|
@@ -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:
|
|
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:
|
|
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
|
|