@kungfu-tech/buildchain 4.0.1-alpha.5 → 4.0.1-alpha.6

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 (79) hide show
  1. package/actions/release-tail/README.md +8 -0
  2. package/architecture/internal-capabilities.json +65 -5
  3. package/architecture/maintainability-policy.json +22 -16
  4. package/architecture/release-tail-contract-inventory.json +5 -2
  5. package/architecture/v4-adopter-delivery-parity.json +32 -5
  6. package/architecture/v4-publication-rehearsal-parity.json +84 -0
  7. package/bin/buildchain.mjs +7 -1
  8. package/bin/internal/adopter-delivery-cli.mjs +70 -0
  9. package/bin/internal/command-registry.mjs +1 -0
  10. package/contracts/fixtures/v4-adopter-delivery-v1/archive-template.json +19 -0
  11. package/contracts/fixtures/v4-adopter-delivery-v1/bootstrap-positive.json +93 -0
  12. package/contracts/fixtures/v4-adopter-delivery-v1/gate-positive.json +29 -0
  13. package/contracts/fixtures/v4-adopter-delivery-v1/gate-unknown-selector.json +26 -0
  14. package/contracts/fixtures/v4-adopter-delivery-v1/offline-vectors.json +50 -0
  15. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/artifacts/product.bin +1 -0
  16. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/config/buildchain.toml +5 -0
  17. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/release-activation.json +1 -0
  18. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/signed-channel.json +1 -0
  19. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/evidence/qualification.json +1 -0
  20. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/candidate.json +5 -0
  21. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/release-passport.json +1 -0
  22. package/contracts/fixtures/v4-publication-rehearsal-v1/capsule.json +707 -0
  23. package/contracts/fixtures/v4-publication-rehearsal-v1/offline-vectors.json +27 -0
  24. package/contracts/v4-adopter-delivery-v1.schema.json +81 -0
  25. package/contracts/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  26. package/dist/site/agent-index.json +3 -0
  27. package/dist/site/artifact-schemas.json +6 -0
  28. package/dist/site/buildchain-contract.json +14 -14
  29. package/dist/site/buildchain-site.json +219 -22
  30. package/dist/site/capability-registry.json +10 -9
  31. package/dist/site/cli-registry.json +53 -1
  32. package/dist/site/kfd-claims.json +253 -14
  33. package/dist/site/kfd-upstream-aggregate.json +1 -1
  34. package/dist/site/manual-registry.json +20 -5
  35. package/dist/site/node-api-registry.json +11501 -9312
  36. package/dist/site/page-registry.json +202 -13
  37. package/dist/site/public-surface-audit.json +195 -11
  38. package/dist/site/publication-authority-registry.json +17 -4
  39. package/dist/site/publication-registry.json +4 -4
  40. package/dist/site/release-provenance.json +14 -0
  41. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +199 -0
  42. package/dist/site/schemas/v4-adopter-delivery-v1.schema.json +81 -0
  43. package/dist/site/schemas/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  44. package/dist/site/site-manifest.json +17 -9
  45. package/dist/site/workflow-registry.json +89 -8
  46. package/docs/MAP.md +3 -1
  47. package/docs/cli-reference.md +68 -0
  48. package/docs/cli.md +8 -0
  49. package/docs/node-api-reference.md +198 -51
  50. package/docs/release-tail-provider-plane.md +30 -0
  51. package/docs/v4-adopter-delivery.md +133 -0
  52. package/docs/v4-publication-rehearsal.md +130 -0
  53. package/package.json +17 -3
  54. package/packages/core/adopter-delivery-passport.js +259 -0
  55. package/packages/core/adopter-delivery-vectors.js +158 -0
  56. package/packages/core/adopter-delivery-vectors.json +77 -0
  57. package/packages/core/buildchain-agent-manuals.js +1 -0
  58. package/packages/core/buildchain-config.js +84 -0
  59. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  60. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  61. package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
  62. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  63. package/packages/core/published-delivery-authority.js +266 -0
  64. package/packages/core/release-passport.js +26 -8
  65. package/packages/core/v4-adopter-delivery-parity.js +3 -3
  66. package/packages/core/v4-adopter-delivery.js +359 -0
  67. package/packages/core/v4-publication-rehearsal-capsule.js +468 -0
  68. package/packages/core/v4-publication-rehearsal-provider-bindings.js +212 -0
  69. package/packages/core/v4-publication-rehearsal.js +481 -0
  70. package/scripts/buildchain-cli-help.mjs +10 -0
  71. package/scripts/check-inventory.mjs +3 -3
  72. package/scripts/dev-delivery-source-proof-replay.mjs +153 -0
  73. package/scripts/dev-delivery-source-proof-reuse.mjs +13 -97
  74. package/scripts/generate-release-candidate-passport.mjs +152 -0
  75. package/scripts/generate-site-bundle.mjs +30 -0
  76. package/scripts/release-tail.mjs +51 -3
  77. package/scripts/resume-from-candidate-run.mjs +545 -15
  78. package/scripts/site-capability-metadata.mjs +16 -0
  79. package/scripts/v4-publication-rehearsal-fixture.mjs +144 -0
@@ -0,0 +1,167 @@
1
+ import {
2
+ ADOPTER_PROTOCOL_DRIVER_INTERFACE,
3
+ adopterDeliveryGateDigest,
4
+ defineAdopterProtocolDriver,
5
+ } from "./adopter-delivery-gate.js";
6
+ import {
7
+ KFD_LEGACY_SUPPORT_MATRIX_CONTRACT,
8
+ validateKfdAdopterManifestGate,
9
+ validateKfdLegacySupportMatrixProjection,
10
+ } from "./kfd-adopter-manifest.js";
11
+
12
+ export const LEGACY_KFD_ADOPTER_PROTOCOL_ID =
13
+ "buildchain.kfd-adopter/legacy-support-matrix";
14
+ export const LEGACY_KFD_ADOPTER_PROTOCOL_VERSION = "1.0.0";
15
+ export const LEGACY_KFD_ADOPTER_DRIVER_REPORT_CONTRACT =
16
+ "kungfu-buildchain-legacy-kfd-adopter-driver-report";
17
+
18
+ function issue(code, path, message) {
19
+ return { code, path, message };
20
+ }
21
+
22
+ function normalizedIssues(entries) {
23
+ return (entries ?? []).map(({ code, path, message }) => ({
24
+ code,
25
+ path: path ? `/${path.replaceAll(".", "/")}` : "/declaration",
26
+ message,
27
+ }));
28
+ }
29
+
30
+ function sameJson(left, right) {
31
+ try {
32
+ return adopterDeliveryGateDigest(left) === adopterDeliveryGateDigest(right);
33
+ } catch {
34
+ return false;
35
+ }
36
+ }
37
+
38
+ function bindingIssues(request, manifest) {
39
+ const issues = [];
40
+ if (
41
+ request.project.instanceId !== manifest?.manifestId ||
42
+ request.project.adopterId !== manifest?.adopter?.id
43
+ ) {
44
+ issues.push(
45
+ issue(
46
+ "delivery-legacy-project-binding-mismatch",
47
+ "/project",
48
+ "Delivery project identity must match the standard adopter manifest.",
49
+ ),
50
+ );
51
+ }
52
+ if (!sameJson(request.artifact, manifest?.adopter?.artifact)) {
53
+ issues.push(
54
+ issue(
55
+ "delivery-legacy-artifact-binding-mismatch",
56
+ "/artifact",
57
+ "Delivery artifact must match the standard adopter manifest artifact.",
58
+ ),
59
+ );
60
+ }
61
+ return issues;
62
+ }
63
+
64
+ function invalidContextResult(issues) {
65
+ const report = {
66
+ schemaVersion: 1,
67
+ contract: LEGACY_KFD_ADOPTER_DRIVER_REPORT_CONTRACT,
68
+ valid: false,
69
+ qualifying: false,
70
+ selfCertified: false,
71
+ independentlyCertified: false,
72
+ manifestRoot: null,
73
+ manifestGateRoot: null,
74
+ legacyProjectionRoot: null,
75
+ legacyProjection: null,
76
+ adapterIssues: issues,
77
+ nonClaims: [
78
+ "The legacy support matrix is a one-way projection, not declaration authority.",
79
+ "Buildchain carries the existing standard manifest decision and does not certify KFD adoption.",
80
+ ],
81
+ };
82
+ return {
83
+ valid: false,
84
+ report,
85
+ reportRoot: adopterDeliveryGateDigest(report),
86
+ issues,
87
+ };
88
+ }
89
+
90
+ export function createLegacyKfdAdopterProtocolDriver() {
91
+ return defineAdopterProtocolDriver({
92
+ interface: ADOPTER_PROTOCOL_DRIVER_INTERFACE,
93
+ id: LEGACY_KFD_ADOPTER_PROTOCOL_ID,
94
+ version: LEGACY_KFD_ADOPTER_PROTOCOL_VERSION,
95
+ verify({ request, context }) {
96
+ const manifest = context?.adopterManifest;
97
+ const manifestGate = context?.adopterManifestGate;
98
+ if (!manifest || !manifestGate) {
99
+ return invalidContextResult([
100
+ issue(
101
+ "delivery-legacy-verification-context-invalid",
102
+ "/protocol",
103
+ "The exact standard adopter manifest and manifest gate are required.",
104
+ ),
105
+ ]);
106
+ }
107
+
108
+ const source = manifest?.adopter?.artifact?.coordinate?.match(
109
+ /^([^@\s]+)@([0-9a-f]{40})$/,
110
+ );
111
+ const gateValidation = validateKfdAdopterManifestGate(manifestGate, {
112
+ expectedAdopterId: manifest?.adopter?.id,
113
+ expectedSourceRepository: source?.[1] ?? "",
114
+ expectedSourceSha: source?.[2] ?? "",
115
+ checkedAt: manifestGate?.checkedAt,
116
+ });
117
+ const projectionValidation = validateKfdLegacySupportMatrixProjection(
118
+ request.declaration,
119
+ { manifest, manifestGate },
120
+ );
121
+ const adapterIssues = [
122
+ ...bindingIssues(request, manifest),
123
+ ...normalizedIssues(gateValidation.issues),
124
+ ...normalizedIssues(projectionValidation.issues),
125
+ ];
126
+ if (
127
+ request.declaration?.contract !== KFD_LEGACY_SUPPORT_MATRIX_CONTRACT
128
+ ) {
129
+ adapterIssues.push(
130
+ issue(
131
+ "delivery-legacy-contract-invalid",
132
+ "/declaration/contract",
133
+ `Legacy declaration must use ${KFD_LEGACY_SUPPORT_MATRIX_CONTRACT}.`,
134
+ ),
135
+ );
136
+ }
137
+
138
+ const valid =
139
+ gateValidation.valid &&
140
+ projectionValidation.valid &&
141
+ adapterIssues.length === 0;
142
+ const report = {
143
+ schemaVersion: 1,
144
+ contract: LEGACY_KFD_ADOPTER_DRIVER_REPORT_CONTRACT,
145
+ valid,
146
+ qualifying: false,
147
+ selfCertified: false,
148
+ independentlyCertified: false,
149
+ manifestRoot: manifestGate?.authority?.manifestRoot ?? null,
150
+ manifestGateRoot: manifestGate?.gateRoot ?? null,
151
+ legacyProjectionRoot: adopterDeliveryGateDigest(request.declaration),
152
+ legacyProjection: structuredClone(request.declaration),
153
+ adapterIssues,
154
+ nonClaims: [
155
+ "The legacy support matrix is a one-way projection, not declaration authority.",
156
+ "Buildchain carries the existing standard manifest decision and does not certify KFD adoption.",
157
+ ],
158
+ };
159
+ return {
160
+ valid,
161
+ report,
162
+ reportRoot: adopterDeliveryGateDigest(report),
163
+ issues: adapterIssues,
164
+ };
165
+ },
166
+ });
167
+ }
@@ -0,0 +1,266 @@
1
+ import { createHash } from "node:crypto";
2
+ import { createReadStream } from "node:fs";
3
+ import {
4
+ copyFile,
5
+ mkdir,
6
+ mkdtemp,
7
+ readFile,
8
+ realpath,
9
+ rm,
10
+ } from "node:fs/promises";
11
+ import { tmpdir } from "node:os";
12
+ import path from "node:path";
13
+ import { promisify } from "node:util";
14
+ import { pathToFileURL } from "node:url";
15
+ import { execFile } from "node:child_process";
16
+
17
+ import { adopterDeliveryGateDigest } from "./adopter-delivery-gate.js";
18
+
19
+ export const PUBLISHED_DELIVERY_AUTHORITY_CONTRACT =
20
+ "kungfu-buildchain-published-delivery-authority/v1";
21
+
22
+ const execFileAsync = promisify(execFile);
23
+ const ROOT_PATTERN = /^sha256:[0-9a-f]{64}$/;
24
+ const PACKAGES = [
25
+ {
26
+ key: "buildchain",
27
+ name: "@kungfu-tech/buildchain",
28
+ packageRoot: "archive",
29
+ modules: {
30
+ adopterDeliveryGate: "packages/core/adopter-delivery-gate.js",
31
+ bootstrap: "packages/core/buildchain-delivery-bootstrap.js",
32
+ infrastructure: "packages/core/buildchain-delivery-infrastructure.js",
33
+ kfdCategoryDriver: "packages/core/kfd-adopter-category-driver.js",
34
+ },
35
+ },
36
+ {
37
+ key: "kfd",
38
+ name: "@kungfu-tech/kfd",
39
+ packageRoot: "profiles/adopter-conformance/adopters/kfd/manifest.json",
40
+ modules: {},
41
+ },
42
+ ];
43
+
44
+ async function sha256File(file) {
45
+ const hash = createHash("sha256");
46
+ for await (const chunk of createReadStream(file)) hash.update(chunk);
47
+ return `sha256:${hash.digest("hex")}`;
48
+ }
49
+
50
+ function exactDeclaration(value, expectedName, label) {
51
+ if (
52
+ value?.name !== expectedName ||
53
+ typeof value.version !== "string" ||
54
+ value.version.length === 0 ||
55
+ typeof value.archivePath !== "string" ||
56
+ value.archivePath.length === 0 ||
57
+ !ROOT_PATTERN.test(value.archiveRoot ?? "") ||
58
+ !ROOT_PATTERN.test(value.artifactRoot ?? "")
59
+ ) {
60
+ throw new TypeError(`${label} package declaration is incomplete`);
61
+ }
62
+ return structuredClone(value);
63
+ }
64
+
65
+ function safeArchiveEntries(listing, verboseListing, label) {
66
+ const entries = listing.split("\n").filter(Boolean);
67
+ const types = verboseListing.split("\n").filter(Boolean);
68
+ if (entries.length === 0 || entries.length !== types.length) {
69
+ throw new Error(`${label} archive listing is incomplete`);
70
+ }
71
+ for (let index = 0; index < entries.length; index += 1) {
72
+ const entry = entries[index];
73
+ const parts = entry.split("/");
74
+ if (
75
+ parts[0] !== "package" ||
76
+ parts.some((part, partIndex) =>
77
+ partIndex === parts.length - 1 && part === ""
78
+ ? false
79
+ : part === "" || part === "." || part === "..",
80
+ )
81
+ ) {
82
+ throw new Error(`${label} archive contains an unsafe path`);
83
+ }
84
+ if (!["-", "d"].includes(types[index][0])) {
85
+ throw new Error(`${label} archive contains a non-file entry`);
86
+ }
87
+ }
88
+ }
89
+
90
+ async function extractPackage(declaration, destination, definition, label) {
91
+ const archivePath = path.resolve(declaration.archivePath);
92
+ const observedRoot = await sha256File(archivePath);
93
+ if (observedRoot !== declaration.archiveRoot) {
94
+ throw new Error(`${label} archive bytes do not match archiveRoot`);
95
+ }
96
+ await mkdir(destination, { recursive: true });
97
+ const stagedArchiveName = `.buildchain-${definition.key}-authority.tgz`;
98
+ const stagedArchivePath = path.join(
99
+ path.dirname(destination),
100
+ stagedArchiveName,
101
+ );
102
+ const stagedArchiveFile = `../${stagedArchiveName}`;
103
+ await copyFile(archivePath, stagedArchivePath);
104
+ try {
105
+ if ((await sha256File(stagedArchivePath)) !== declaration.archiveRoot) {
106
+ throw new Error(`${label} staged archive bytes do not match archiveRoot`);
107
+ }
108
+ const [{ stdout: listing }, { stdout: verboseListing }] = await Promise.all(
109
+ [
110
+ execFileAsync("tar", ["-tzf", stagedArchiveFile], {
111
+ cwd: destination,
112
+ maxBuffer: 16 * 1024 * 1024,
113
+ }),
114
+ execFileAsync("tar", ["-tvzf", stagedArchiveFile], {
115
+ cwd: destination,
116
+ maxBuffer: 16 * 1024 * 1024,
117
+ }),
118
+ ],
119
+ );
120
+ safeArchiveEntries(listing, verboseListing, label);
121
+ await execFileAsync(
122
+ "tar",
123
+ ["-xzf", stagedArchiveFile, "--strip-components", "1"],
124
+ { cwd: destination, maxBuffer: 16 * 1024 * 1024 },
125
+ );
126
+ } finally {
127
+ await rm(stagedArchivePath, { force: true });
128
+ }
129
+ const packageJsonPath = path.join(destination, "package.json");
130
+ const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
131
+ if (
132
+ packageJson.name !== declaration.name ||
133
+ packageJson.version !== declaration.version
134
+ ) {
135
+ throw new Error(`${label} extracted package identity does not match`);
136
+ }
137
+ if (definition.packageRoot === "archive") {
138
+ if (declaration.artifactRoot !== declaration.archiveRoot) {
139
+ throw new Error(`${label} package artifactRoot must match archiveRoot`);
140
+ }
141
+ } else {
142
+ const packageManifest = JSON.parse(
143
+ await readFile(path.join(destination, definition.packageRoot), "utf8"),
144
+ );
145
+ const packageCut = packageManifest?.kfdCut?.package;
146
+ if (
147
+ packageCut?.name !== declaration.name ||
148
+ packageCut?.version !== declaration.version ||
149
+ packageCut?.artifactRoot !== declaration.artifactRoot
150
+ ) {
151
+ throw new Error(`${label} semantic package identity does not match`);
152
+ }
153
+ }
154
+ const destinationRoot = await realpath(destination);
155
+ if (!destinationRoot.endsWith(path.join(...declaration.name.split("/")))) {
156
+ throw new Error(`${label} extraction escaped its package coordinate`);
157
+ }
158
+ return {
159
+ name: declaration.name,
160
+ version: declaration.version,
161
+ archiveRoot: declaration.archiveRoot,
162
+ artifactRoot: declaration.artifactRoot,
163
+ };
164
+ }
165
+
166
+ async function importAuthorityRuntime(buildchainRoot) {
167
+ const definition = PACKAGES[0];
168
+ const imported = {};
169
+ for (const [key, relativePath] of Object.entries(definition.modules)) {
170
+ imported[key] = await import(
171
+ pathToFileURL(path.join(buildchainRoot, relativePath)).href
172
+ );
173
+ }
174
+ const runtime = {
175
+ createAdopterDeliveryGate:
176
+ imported.adopterDeliveryGate.createAdopterDeliveryGate,
177
+ createPackageArtifactProfile:
178
+ imported.adopterDeliveryGate.createPackageArtifactProfile,
179
+ qualifyBuildchainDeliveryInfrastructureBootstrap:
180
+ imported.bootstrap.qualifyBuildchainDeliveryInfrastructureBootstrap,
181
+ createBuildchainDeliveryInfrastructureInstanceManifest:
182
+ imported.infrastructure
183
+ .createBuildchainDeliveryInfrastructureInstanceManifest,
184
+ verifyBuildchainDeliveryInfrastructureInstance:
185
+ imported.infrastructure.verifyBuildchainDeliveryInfrastructureInstance,
186
+ createKfdAdopterCategoryProtocolDriver:
187
+ imported.kfdCategoryDriver.createKfdAdopterCategoryProtocolDriver,
188
+ };
189
+ for (const [name, implementation] of Object.entries(runtime)) {
190
+ if (typeof implementation !== "function") {
191
+ throw new Error(`published Buildchain authority is missing ${name}`);
192
+ }
193
+ }
194
+ return runtime;
195
+ }
196
+
197
+ export async function loadPublishedBuildchainDeliveryAuthority({
198
+ buildchain,
199
+ kfd,
200
+ } = {}) {
201
+ const declarations = {
202
+ buildchain: exactDeclaration(
203
+ buildchain,
204
+ "@kungfu-tech/buildchain",
205
+ "Buildchain authority",
206
+ ),
207
+ kfd: exactDeclaration(kfd, "@kungfu-tech/kfd", "KFD authority"),
208
+ };
209
+ const temporaryRoot = await mkdtemp(
210
+ path.join(tmpdir(), "buildchain-published-delivery-authority-"),
211
+ );
212
+ let retained = false;
213
+ try {
214
+ const identities = {};
215
+ for (const definition of PACKAGES) {
216
+ identities[definition.key] = await extractPackage(
217
+ declarations[definition.key],
218
+ path.join(temporaryRoot, "node_modules", ...definition.name.split("/")),
219
+ definition,
220
+ `${definition.key} authority`,
221
+ );
222
+ }
223
+ const authorityRuntime = await importAuthorityRuntime(
224
+ path.join(temporaryRoot, "node_modules", ...PACKAGES[0].name.split("/")),
225
+ );
226
+ const authority = {
227
+ schemaVersion: 1,
228
+ contract: PUBLISHED_DELIVERY_AUTHORITY_CONTRACT,
229
+ packages: identities,
230
+ moduleCoordinates: structuredClone(PACKAGES[0].modules),
231
+ qualifying: false,
232
+ selfCertified: false,
233
+ releaseAuthorized: false,
234
+ finalAuthority:
235
+ "caller-bound-public-npm-archive-bytes-and-package-identity",
236
+ };
237
+ authority.authorityRoot = adopterDeliveryGateDigest(authority);
238
+ retained = true;
239
+ return {
240
+ ...authority,
241
+ authorityRuntime,
242
+ temporaryRoot,
243
+ async dispose() {
244
+ await rm(temporaryRoot, { recursive: true, force: true });
245
+ },
246
+ };
247
+ } finally {
248
+ if (!retained) await rm(temporaryRoot, { recursive: true, force: true });
249
+ }
250
+ }
251
+
252
+ export async function withPublishedBuildchainDeliveryAuthority(
253
+ declarations,
254
+ operation,
255
+ ) {
256
+ if (typeof operation !== "function") {
257
+ throw new TypeError("published authority operation must be a function");
258
+ }
259
+ const authority =
260
+ await loadPublishedBuildchainDeliveryAuthority(declarations);
261
+ try {
262
+ return await operation(authority);
263
+ } finally {
264
+ await authority.dispose();
265
+ }
266
+ }
@@ -439,11 +439,17 @@ function mergeAuthoritativePassportBase(passport, basePassport = undefined, { re
439
439
  kfd3: basePassport.evidence?.kfd3 || passport.evidence?.kfd3 || "",
440
440
  },
441
441
  };
442
- for (const key of ["versionImpact", "surfaceImpacts"]) {
443
- if (basePassport[key] !== undefined) {
444
- merged[key] = basePassport[key];
445
- }
446
- }
442
+ for (const key of [
443
+ "versionImpact",
444
+ "surfaceImpacts",
445
+ "promotionRouting",
446
+ "v4ConsumerPolicy",
447
+ "v4RuntimeResume",
448
+ "transaction",
449
+ "trustedPublishing",
450
+ "distTagPromotion",
451
+ ])
452
+ if (basePassport[key] !== undefined) merged[key] = basePassport[key];
447
453
  if (basePassport.controllerReceipts !== undefined) {
448
454
  merged.controllerReceipts = basePassport.controllerReceipts;
449
455
  }
@@ -1162,6 +1168,18 @@ function normalizeV4RuntimeResumeEvidence(value, expected = {}) {
1162
1168
  };
1163
1169
  }
1164
1170
 
1171
+ function v4RuntimeResumeSourceSha(release, fallback = "") {
1172
+ const builtSourceSha = releaseField(
1173
+ release || {},
1174
+ "builtSourceSha",
1175
+ "built_source_sha",
1176
+ );
1177
+ return release?.treeEquivalent === true && builtSourceSha
1178
+ ? builtSourceSha
1179
+ : fallback;
1180
+ }
1181
+
1182
+
1165
1183
  function prepareBuildEvidence({
1166
1184
  buildSummary,
1167
1185
  buildFacts,
@@ -1317,7 +1335,7 @@ export function createReleasePassport(options = {}) {
1317
1335
  const { promotion, buildEvidence } = preparePromotionBuild(options);
1318
1336
  const normalizedV4RuntimeResume = normalizeV4RuntimeResumeEvidence(v4RuntimeResumeEvidence, {
1319
1337
  repository,
1320
- sourceSha,
1338
+ sourceSha: v4RuntimeResumeSourceSha(release, sourceSha),
1321
1339
  resumeRuntimeSha: promotion.routing?.runtime?.resolvedSha || "",
1322
1340
  consumerPolicyReceiptRoot: promotion.consumerPolicy?.certification?.receiptRoot || "",
1323
1341
  });
@@ -2302,7 +2320,7 @@ function validateV4RuntimeResumePassportSection({ passport, issues }) {
2302
2320
  receipt: evidence.authorization,
2303
2321
  receiptRoot: evidence.authorizationRoot,
2304
2322
  repository: passport?.product?.repository || "",
2305
- sourceSha: passport?.release?.sourceSha || "",
2323
+ sourceSha: v4RuntimeResumeSourceSha(passport?.release, passport?.release?.sourceSha || ""),
2306
2324
  runtimeSha: passport?.promotionRouting?.runtime?.resolvedSha || "",
2307
2325
  consumerPolicyReceiptRoot,
2308
2326
  });
@@ -2313,7 +2331,7 @@ function validateV4RuntimeResumePassportSection({ passport, issues }) {
2313
2331
  lineage: evidence.lineage,
2314
2332
  lineageRoot: evidence.lineageRoot,
2315
2333
  repository: passport?.product?.repository || "",
2316
- sourceSha: passport?.release?.sourceSha || "",
2334
+ sourceSha: v4RuntimeResumeSourceSha(passport?.release, passport?.release?.sourceSha || ""),
2317
2335
  resumeRuntimeSha: passport?.promotionRouting?.runtime?.resolvedSha || "",
2318
2336
  consumerPolicyReceiptRoot,
2319
2337
  });
@@ -31,10 +31,10 @@ const root = path.resolve(
31
31
  );
32
32
 
33
33
  export const V4_ADOPTER_DELIVERY_PARITY_SOURCE = Object.freeze({
34
- v3Commit: "c3f58d76391c1c6ceddfc900a68e91c7ab82a575",
34
+ v3Commit: "6b96bdad8d9f8ccf9275f27d9370a226a9c78465",
35
35
  vectorSuiteRoot:
36
- "sha256:cf329805d928a9883cbafbdfdf21ef66c6a0889ed8dfe14356b4e0d25d6738f9",
37
- kfdPackage: "@kungfu-tech/kfd@1.0.0-alpha.62",
36
+ "sha256:c978707556406ffda4ef4192032332c01c2da1cebb6ad8c4f0edfc65d5cef0c7",
37
+ kfdPackage: "@kungfu-tech/kfd@1.0.0-alpha.65",
38
38
  });
39
39
 
40
40
  function clone(value) {