@kungfu-tech/buildchain 3.0.6-alpha.3 → 3.0.6-alpha.5

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.
@@ -7604,7 +7604,7 @@
7604
7604
  "pageRegistryPath": "dist/site/page-registry.json",
7605
7605
  "cliRegistryDigest": "2e7804e1fa8ef08bbe59fcf58908e47daef4dc145675fc9a989862671e40f993",
7606
7606
  "workflowRegistryDigest": "1ab8b8d32f2ceb8dffad69d1f877f6ad6b37355dbe62c6ef5c0e6b9f4f197acb",
7607
- "pageRegistryDigest": "5604707e51d06fa0b1739abb00d8d2db53fb3dda7d49d34ef558d63772f1fb84"
7607
+ "pageRegistryDigest": "300d36c3126d981d2b749827b550f7428e0da8981bf87d8b189b6832bbda7816"
7608
7608
  },
7609
7609
  "comparison": {
7610
7610
  "missingCliRegistry": [],
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "contract": "kungfu-buildchain-publication-release-registry",
4
- "generatedAt": "2026-08-06T03:18:26.054Z",
5
- "publishedAt": "2026-08-06T03:18:26.054Z",
4
+ "generatedAt": "1970-01-01T00:00:00.000Z",
6
5
  "reproducible": true,
7
- "timestampPolicy": "ci-injected",
6
+ "timestampPolicy": "source-date-epoch",
8
7
  "deterministicInputs": [
9
8
  "README.md",
10
9
  "docs/*.md",
@@ -13,13 +12,11 @@
13
12
  "packages/core/README.md",
14
13
  "package.json#exports",
15
14
  "tests/buildchain-inventory.json",
16
- "sourceRevision",
17
15
  "sourceDateEpoch",
18
16
  "package content",
19
17
  "declared Buildchain surface manifest contract"
20
18
  ],
21
19
  "sourceDateEpoch": "0",
22
- "sourceRevision": "2e685b037b979732297210d74b480d5e061a7aa4",
23
20
  "timestampPolicyDetails": {
24
21
  "contract": "kungfu-buildchain-surface-timestamp-policy",
25
22
  "timestampFields": [
@@ -32,7 +29,7 @@
32
29
  },
33
30
  "package": {
34
31
  "name": "@kungfu-tech/buildchain",
35
- "version": "3.0.6-alpha.3",
32
+ "version": "3.0.6-alpha.5",
36
33
  "versionSource": "package.json#version"
37
34
  },
38
35
  "sourceKind": "package-site-bundle",
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "contract": "kungfu-buildchain-site-manifest",
4
- "generatedAt": "2026-08-06T03:18:26.054Z",
5
- "publishedAt": "2026-08-06T03:18:26.054Z",
4
+ "generatedAt": "1970-01-01T00:00:00.000Z",
6
5
  "reproducible": true,
7
- "timestampPolicy": "ci-injected",
6
+ "timestampPolicy": "source-date-epoch",
8
7
  "deterministicInputs": [
9
8
  "README.md",
10
9
  "docs/*.md",
@@ -13,13 +12,11 @@
13
12
  "packages/core/README.md",
14
13
  "package.json#exports",
15
14
  "tests/buildchain-inventory.json",
16
- "sourceRevision",
17
15
  "sourceDateEpoch",
18
16
  "package content",
19
17
  "declared Buildchain surface manifest contract"
20
18
  ],
21
19
  "sourceDateEpoch": "0",
22
- "sourceRevision": "2e685b037b979732297210d74b480d5e061a7aa4",
23
20
  "timestampPolicyDetails": {
24
21
  "contract": "kungfu-buildchain-surface-timestamp-policy",
25
22
  "timestampFields": [
@@ -37,7 +34,7 @@
37
34
  },
38
35
  "package": {
39
36
  "name": "@kungfu-tech/buildchain",
40
- "version": "3.0.6-alpha.3",
37
+ "version": "3.0.6-alpha.5",
41
38
  "versionSource": "package.json#version"
42
39
  },
43
40
  "entrypoint": "buildchain-site.json",
@@ -125,7 +122,7 @@
125
122
  "path": "docs/release-candidate.md",
126
123
  "plane": "verify",
127
124
  "exists": true,
128
- "digest": "sha256:71161bb57229fe6b66ca131189d3ff3f1dd1a8ca7f6894aa1f596827cb8167f3"
125
+ "digest": "sha256:9cb06463e0cbb06180ae4e9ed3258a9e7466237916ffc766c548ef5faa730651"
129
126
  },
130
127
  {
131
128
  "id": "release-propagation",
@@ -237,7 +234,7 @@
237
234
  "path": "docs/node-api-reference.md",
238
235
  "plane": "use",
239
236
  "exists": true,
240
- "digest": "sha256:3fbfe0227cf929f0ddc2050605d071643cee0b302a4c31920b4f9047c923ae8c"
237
+ "digest": "sha256:f8ae86b9182811d9f980b3ae1f1a42d2c84cd6c133003c996946848f938099a8"
241
238
  },
242
239
  {
243
240
  "id": "build-facts",
@@ -447,7 +447,7 @@ Target: `./packages/core/index.js`. Public symbols: 562.
447
447
  | `readReleaseTransaction` | function: function readReleaseTransaction(filePath) | filePath | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { readReleaseTransaction } from "@kungfu-tech/buildchain";` | `packages/core/publish-transaction.js:367` |
448
448
  | `recordReleaseActivationPhase` | function: function recordReleaseActivationPhase(transaction, phaseId, { receiptRoots = [], failure = "" } = {}) | transaction, phaseId, { receiptRoots = [], failure = "" } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | may-write-or-invoke-external-actions | `import { recordReleaseActivationPhase } from "@kungfu-tech/buildchain";` | `packages/core/release-activation-transaction.js:217` |
449
449
  | `recordReleasePropagationStage` | function: function recordReleasePropagationStage({ work, expectedWorkRoot, receipt } = {}) | { work, expectedWorkRoot, receipt } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | may-write-or-invoke-external-actions | `import { recordReleasePropagationStage } from "@kungfu-tech/buildchain";` | `packages/core/release-propagation-work-transitions.js:45` |
450
- | `recoveryFailure` | function: function recoveryFailure(error) | error | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { recoveryFailure } from "@kungfu-tech/buildchain";` | `packages/core/release-candidate-recovery.js:376` |
450
+ | `recoveryFailure` | function: function recoveryFailure(error) | error | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { recoveryFailure } from "@kungfu-tech/buildchain";` | `packages/core/release-candidate-recovery.js:441` |
451
451
  | `redactBuildchainLogAttributes` | function: function redactBuildchainLogAttributes(attributes = {}) | attributes = {} | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { redactBuildchainLogAttributes } from "@kungfu-tech/buildchain";` | `packages/core/logging.js:33` |
452
452
  | `redactDiagnosticsValue` | function: function redactDiagnosticsValue(key, value, pattern = DEFAULT_SECRET_KEY_PATTERN) | key, value, pattern = DEFAULT_SECRET_KEY_PATTERN | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | none-detected-by-static-source-scan | `import { redactDiagnosticsValue } from "@kungfu-tech/buildchain";` | `packages/core/diagnostics.js:953` |
453
453
  | `redactIssueText` | function: function redactIssueText(value) | value | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { redactIssueText } from "@kungfu-tech/buildchain";` | `packages/core/issue-reporting.js:51` |
@@ -571,7 +571,7 @@ Target: `./packages/core/index.js`. Public symbols: 562.
571
571
  | `verifyPublicationQualificationReceipt` | function: function verifyPublicationQualificationReceipt({ receipt, capability, gateAggregate, expected = {}, usedNonces = [], now = new Date(), } = {}) | { receipt, capability, gateAggregate, expected = {}, usedNonces = [], now = new Date(), } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | none-detected-by-static-source-scan | `import { verifyPublicationQualificationReceipt } from "@kungfu-tech/buildchain";` | `packages/core/publication-authority.js:1096` |
572
572
  | `verifyPublicationReproducibility` | function: function verifyPublicationReproducibility({ cwd = process.cwd(), sourceSha = "", output = DEFAULT_OUTPUT, promote = false, keepWorkspaces = false, pullToolchain = true, packageName = "", allowUnpinnedToolchain = false, overlayPaths = [DEFAULT_REGISTRY_INPUT_DIR, DEFAULT_REGISTRY_HYDRATION], } = {}) | { cwd = process.cwd(), sourceSha = "", output = DEFAULT_OUTPUT, promote = false, keepWorkspaces = false, pullToolchain = true, packageName = "", allowUnpinnedToolchain = false, overlayPaths = [DEFAULT_REGISTRY_INPUT_DIR, DEFAULT_REGISTRY_HYDRATION], } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | local-filesystem-write | `import { verifyPublicationReproducibility } from "@kungfu-tech/buildchain";` | `packages/core/publication-reproducibility.js:869` |
573
573
  | `verifyPublicationSealedBundle` | function: function verifyPublicationSealedBundle({ bundleRoot, manifest } = {}) | { bundleRoot, manifest } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | none-detected-by-static-source-scan | `import { verifyPublicationSealedBundle } from "@kungfu-tech/buildchain";` | `packages/core/publication-sealed-bundle.js:124` |
574
- | `verifyReleaseCandidateRecovery` | function: function verifyReleaseCandidateRecovery({ candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], productPayloadManifests = [], artifacts = [], currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {}) | { candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], productPayloadManifests = [], artifacts = [], currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {} | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { verifyReleaseCandidateRecovery } from "@kungfu-tech/buildchain";` | `packages/core/release-candidate-recovery.js:256` |
574
+ | `verifyReleaseCandidateRecovery` | function: function verifyReleaseCandidateRecovery({ candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], platformManifestEvidence = [], productPayloadManifests = [], artifacts = [], publicationVersion = "", currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {}) | { candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], platformManifestEvidence = [], productPayloadManifests = [], artifacts = [], publicationVersion = "", currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {} | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { verifyReleaseCandidateRecovery } from "@kungfu-tech/buildchain";` | `packages/core/release-candidate-recovery.js:318` |
575
575
  | `verifyReleasePassport` | function: async function verifyReleasePassport({ passportLocation, artifactEvidenceLocation = "", publishEvidenceLocation = "", impactLocation = "", agentIndexLocation = "", productMechanismLocation = "", kfdAgentHubEvidenceLocation = "", kfdSupportEvidenceLocation = "", checkedAt = nowIso(), } = {}) | { passportLocation, artifactEvidenceLocation = "", publishEvidenceLocation = "", impactLocation = "", agentIndexLocation = "", productMechanismLocation = "", kfdAgentHubEvidenceLocation = "", kfdSupportEvidenceLocation = "", checkedAt = nowIso(), } = {} | Promise<unknown> | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { verifyReleasePassport } from "@kungfu-tech/buildchain";` | `packages/core/release-passport.js:2743` |
576
576
  | `verifyReleasePropagationWork` | function: function verifyReleasePropagationWork(input) | input | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | none-detected-by-static-source-scan | `import { verifyReleasePropagationWork } from "@kungfu-tech/buildchain";` | `packages/core/release-propagation-work.js:486` |
577
577
  | `WEB_SURFACE_PRODUCTION_DECISION_CONTRACT` | constant: const WEB_SURFACE_PRODUCTION_DECISION_CONTRACT | none | value | Import does not declare a throw contract. | none-on-import | `import { WEB_SURFACE_PRODUCTION_DECISION_CONTRACT } from "@kungfu-tech/buildchain";` | `packages/core/web-surface-publication-candidate.js:7` |
@@ -1062,7 +1062,7 @@ Target: `./packages/core/index.js`. Public symbols: 562.
1062
1062
  | `readReleaseTransaction` | function: function readReleaseTransaction(filePath) | filePath | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { readReleaseTransaction } from "@kungfu-tech/buildchain/core";` | `packages/core/publish-transaction.js:367` |
1063
1063
  | `recordReleaseActivationPhase` | function: function recordReleaseActivationPhase(transaction, phaseId, { receiptRoots = [], failure = "" } = {}) | transaction, phaseId, { receiptRoots = [], failure = "" } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | may-write-or-invoke-external-actions | `import { recordReleaseActivationPhase } from "@kungfu-tech/buildchain/core";` | `packages/core/release-activation-transaction.js:217` |
1064
1064
  | `recordReleasePropagationStage` | function: function recordReleasePropagationStage({ work, expectedWorkRoot, receipt } = {}) | { work, expectedWorkRoot, receipt } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | may-write-or-invoke-external-actions | `import { recordReleasePropagationStage } from "@kungfu-tech/buildchain/core";` | `packages/core/release-propagation-work-transitions.js:45` |
1065
- | `recoveryFailure` | function: function recoveryFailure(error) | error | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { recoveryFailure } from "@kungfu-tech/buildchain/core";` | `packages/core/release-candidate-recovery.js:376` |
1065
+ | `recoveryFailure` | function: function recoveryFailure(error) | error | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { recoveryFailure } from "@kungfu-tech/buildchain/core";` | `packages/core/release-candidate-recovery.js:441` |
1066
1066
  | `redactBuildchainLogAttributes` | function: function redactBuildchainLogAttributes(attributes = {}) | attributes = {} | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { redactBuildchainLogAttributes } from "@kungfu-tech/buildchain/core";` | `packages/core/logging.js:33` |
1067
1067
  | `redactDiagnosticsValue` | function: function redactDiagnosticsValue(key, value, pattern = DEFAULT_SECRET_KEY_PATTERN) | key, value, pattern = DEFAULT_SECRET_KEY_PATTERN | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | none-detected-by-static-source-scan | `import { redactDiagnosticsValue } from "@kungfu-tech/buildchain/core";` | `packages/core/diagnostics.js:953` |
1068
1068
  | `redactIssueText` | function: function redactIssueText(value) | value | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { redactIssueText } from "@kungfu-tech/buildchain/core";` | `packages/core/issue-reporting.js:51` |
@@ -1186,7 +1186,7 @@ Target: `./packages/core/index.js`. Public symbols: 562.
1186
1186
  | `verifyPublicationQualificationReceipt` | function: function verifyPublicationQualificationReceipt({ receipt, capability, gateAggregate, expected = {}, usedNonces = [], now = new Date(), } = {}) | { receipt, capability, gateAggregate, expected = {}, usedNonces = [], now = new Date(), } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | none-detected-by-static-source-scan | `import { verifyPublicationQualificationReceipt } from "@kungfu-tech/buildchain/core";` | `packages/core/publication-authority.js:1096` |
1187
1187
  | `verifyPublicationReproducibility` | function: function verifyPublicationReproducibility({ cwd = process.cwd(), sourceSha = "", output = DEFAULT_OUTPUT, promote = false, keepWorkspaces = false, pullToolchain = true, packageName = "", allowUnpinnedToolchain = false, overlayPaths = [DEFAULT_REGISTRY_INPUT_DIR, DEFAULT_REGISTRY_HYDRATION], } = {}) | { cwd = process.cwd(), sourceSha = "", output = DEFAULT_OUTPUT, promote = false, keepWorkspaces = false, pullToolchain = true, packageName = "", allowUnpinnedToolchain = false, overlayPaths = [DEFAULT_REGISTRY_INPUT_DIR, DEFAULT_REGISTRY_HYDRATION], } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | local-filesystem-write | `import { verifyPublicationReproducibility } from "@kungfu-tech/buildchain/core";` | `packages/core/publication-reproducibility.js:869` |
1188
1188
  | `verifyPublicationSealedBundle` | function: function verifyPublicationSealedBundle({ bundleRoot, manifest } = {}) | { bundleRoot, manifest } = {} | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | none-detected-by-static-source-scan | `import { verifyPublicationSealedBundle } from "@kungfu-tech/buildchain/core";` | `packages/core/publication-sealed-bundle.js:124` |
1189
- | `verifyReleaseCandidateRecovery` | function: function verifyReleaseCandidateRecovery({ candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], productPayloadManifests = [], artifacts = [], currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {}) | { candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], productPayloadManifests = [], artifacts = [], currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {} | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { verifyReleaseCandidateRecovery } from "@kungfu-tech/buildchain/core";` | `packages/core/release-candidate-recovery.js:256` |
1189
+ | `verifyReleaseCandidateRecovery` | function: function verifyReleaseCandidateRecovery({ candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], platformManifestEvidence = [], productPayloadManifests = [], artifacts = [], publicationVersion = "", currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {}) | { candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], platformManifestEvidence = [], productPayloadManifests = [], artifacts = [], publicationVersion = "", currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {} | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { verifyReleaseCandidateRecovery } from "@kungfu-tech/buildchain/core";` | `packages/core/release-candidate-recovery.js:318` |
1190
1190
  | `verifyReleasePassport` | function: async function verifyReleasePassport({ passportLocation, artifactEvidenceLocation = "", publishEvidenceLocation = "", impactLocation = "", agentIndexLocation = "", productMechanismLocation = "", kfdAgentHubEvidenceLocation = "", kfdSupportEvidenceLocation = "", checkedAt = nowIso(), } = {}) | { passportLocation, artifactEvidenceLocation = "", publishEvidenceLocation = "", impactLocation = "", agentIndexLocation = "", productMechanismLocation = "", kfdAgentHubEvidenceLocation = "", kfdSupportEvidenceLocation = "", checkedAt = nowIso(), } = {} | Promise<unknown> | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { verifyReleasePassport } from "@kungfu-tech/buildchain/core";` | `packages/core/release-passport.js:2743` |
1191
1191
  | `verifyReleasePropagationWork` | function: function verifyReleasePropagationWork(input) | input | unknown | May throw an Error on rejected input or failed operations; follow the linked source contract. | none-detected-by-static-source-scan | `import { verifyReleasePropagationWork } from "@kungfu-tech/buildchain/core";` | `packages/core/release-propagation-work.js:486` |
1192
1192
  | `WEB_SURFACE_PRODUCTION_DECISION_CONTRACT` | constant: const WEB_SURFACE_PRODUCTION_DECISION_CONTRACT | none | value | Import does not declare a throw contract. | none-on-import | `import { WEB_SURFACE_PRODUCTION_DECISION_CONTRACT } from "@kungfu-tech/buildchain/core";` | `packages/core/web-surface-publication-candidate.js:7` |
@@ -1906,14 +1906,15 @@ Target: `./packages/core/release-candidate.js`. Public symbols: 5.
1906
1906
 
1907
1907
  ## `@kungfu-tech/buildchain/release-candidate-recovery`
1908
1908
 
1909
- Target: `./packages/core/release-candidate-recovery.js`. Public symbols: 4.
1909
+ Target: `./packages/core/release-candidate-recovery.js`. Public symbols: 5.
1910
1910
 
1911
1911
  | Symbol | Kind and signature | Parameters | Return | Errors | Side effects | Example | Source |
1912
1912
  | --- | --- | --- | --- | --- | --- | --- | --- |
1913
- | `recoveryFailure` | function: function recoveryFailure(error) | error | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { recoveryFailure } from "@kungfu-tech/buildchain/release-candidate-recovery";` | `packages/core/release-candidate-recovery.js:376` |
1913
+ | `recoveryFailure` | function: function recoveryFailure(error) | error | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { recoveryFailure } from "@kungfu-tech/buildchain/release-candidate-recovery";` | `packages/core/release-candidate-recovery.js:441` |
1914
1914
  | `RELEASE_CANDIDATE_RECOVERY_CONTRACT` | constant: const RELEASE_CANDIDATE_RECOVERY_CONTRACT | none | value | Import does not declare a throw contract. | none-on-import | `import { RELEASE_CANDIDATE_RECOVERY_CONTRACT } from "@kungfu-tech/buildchain/release-candidate-recovery";` | `packages/core/release-candidate-recovery.js:11` |
1915
1915
  | `ReleaseCandidateRecoveryError` | class: class ReleaseCandidateRecoveryError | none | ReleaseCandidateRecoveryError | Construction and method errors follow the linked source implementation. | class-dependent | `import { ReleaseCandidateRecoveryError } from "@kungfu-tech/buildchain/release-candidate-recovery";` | `packages/core/release-candidate-recovery.js:18` |
1916
- | `verifyReleaseCandidateRecovery` | function: function verifyReleaseCandidateRecovery({ candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], productPayloadManifests = [], artifacts = [], currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {}) | { candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], productPayloadManifests = [], artifacts = [], currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {} | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { verifyReleaseCandidateRecovery } from "@kungfu-tech/buildchain/release-candidate-recovery";` | `packages/core/release-candidate-recovery.js:256` |
1916
+ | `validateReleaseCandidateRecoveryReceipt` | function: function validateReleaseCandidateRecoveryReceipt({ receipt, passport, repository = "", targetChannel = "", targetRef = "", targetSha = "", targetTree = "", version = "", } = {}) | { receipt, passport, repository = "", targetChannel = "", targetRef = "", targetSha = "", targetTree = "", version = "", } = {} | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { validateReleaseCandidateRecoveryReceipt } from "@kungfu-tech/buildchain/release-candidate-recovery";` | `packages/core/release-candidate-recovery.js:96` |
1917
+ | `verifyReleaseCandidateRecovery` | function: function verifyReleaseCandidateRecovery({ candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], platformManifestEvidence = [], productPayloadManifests = [], artifacts = [], publicationVersion = "", currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {}) | { candidateRepository, targetRepository, expectedRunId, expectedWorkflowFile, expectedWorkflowName, channel, targetRef, targetSha, targetTree, expectedSourceTree = "", expectedCandidateRoot = "", expectedRuntimeSha, expectedTransactionId = "", existingTransaction = undefined, run, workflow, pullRequest, ancestry, passport, buildSummary, controllerReceipts = [], platformManifests = [], platformManifestEvidence = [], productPayloadManifests = [], artifacts = [], publicationVersion = "", currentToolingSha, recoveryRunId = "", createdAt = new Date().toISOString(), } = {} | unknown | Errors from called operations may propagate; no narrower throw contract is declared in source. | none-detected-by-static-source-scan | `import { verifyReleaseCandidateRecovery } from "@kungfu-tech/buildchain/release-candidate-recovery";` | `packages/core/release-candidate-recovery.js:318` |
1917
1918
 
1918
1919
  ## `@kungfu-tech/buildchain/stable-candidate-ledger`
1919
1920
 
@@ -195,6 +195,15 @@ the skipped stages, current tooling SHA, transaction identity/state, and an
195
195
  exact receipt root. The receipt is uploaded as an Actions artifact and staged
196
196
  with immutable GitHub Release Passport assets.
197
197
 
198
+ The original candidate Passport is never rewritten when a reusable fixture or
199
+ consumer build records a product version different from the sealed publication
200
+ package. In that case the promote action validates the Passport without
201
+ discarding its original target, then requires the immutable recovery receipt to
202
+ bind the original candidate root and source/tree to the exact version read from
203
+ the sealed payload. Without that receipt, the existing direct Passport version
204
+ check remains mandatory; receipt, candidate-root, target, or version drift fails
205
+ before publication side effects.
206
+
198
207
  Missing or expired artifacts, archive or payload digest drift, tree/root,
199
208
  repository/workflow/channel/target mismatch, untrusted run/PR provenance,
200
209
  incomplete controller evidence, and transaction conflict fail closed with an
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "3.0.6-alpha.3",
3
+ "version": "3.0.6-alpha.5",
4
4
  "private": false,
5
5
  "description": "Buildchain Release Passport, release governance, CLI toolkit, and site facts.",
6
6
  "repository": "https://github.com/kungfu-systems/buildchain",
@@ -93,13 +93,59 @@ function normalizedRef(value) {
93
93
  return String(value || "").replace(/^refs\/heads\//, "").trim();
94
94
  }
95
95
 
96
- function isBuildchainDiagnosticsEnvelope(file) {
97
- return String(file?.path || "").replace(/\\/g, "/").startsWith(".buildchain/");
96
+ export function validateReleaseCandidateRecoveryReceipt({
97
+ receipt,
98
+ passport,
99
+ repository = "",
100
+ targetChannel = "",
101
+ targetRef = "",
102
+ targetSha = "",
103
+ targetTree = "",
104
+ version = "",
105
+ } = {}) {
106
+ const receiptObject = Boolean(receipt && typeof receipt === "object" && !Array.isArray(receipt));
107
+ const passportObject = Boolean(passport && typeof passport === "object" && !Array.isArray(passport));
108
+ const rootedReceipt = Object.assign({}, receipt);
109
+ delete rootedReceipt.root;
110
+ const candidateHash = String(passport?.candidateHash || "");
111
+ const candidateRoot = `sha256:${candidateHash}`;
112
+ const checks = [
113
+ [receiptObject, "receipt must be an object"],
114
+ [passportObject, "passport must be an object"],
115
+ [receipt?.contract === RELEASE_CANDIDATE_RECOVERY_CONTRACT, `contract must be ${RELEASE_CANDIDATE_RECOVERY_CONTRACT}`],
116
+ [Number(receipt?.schemaVersion) === 1, "schemaVersion must be 1"],
117
+ [receipt?.action === "reused", "action must be reused"],
118
+ [receipt?.payloadBytes === "unchanged", "payloadBytes must be unchanged"],
119
+ [JSON.stringify(receipt?.skippedBuildStages) === JSON.stringify(["install", "build", "verify", "platform-matrix"]), "skippedBuildStages must record the complete skipped product build matrix"],
120
+ [receipt?.root === `sha256:${sha256Json(rootedReceipt)}`, "receipt root mismatch"],
121
+ [!repository || receipt?.repository === repository, `repository mismatch: expected ${repository}, got ${receipt?.repository || "<empty>"}`],
122
+ [!targetChannel || receipt?.target?.channel === targetChannel, `target channel mismatch: expected ${targetChannel}, got ${receipt?.target?.channel || "<empty>"}`],
123
+ [!targetRef || normalizedRef(receipt?.target?.ref) === normalizedRef(targetRef), `target ref mismatch: expected ${normalizedRef(targetRef)}, got ${normalizedRef(receipt?.target?.ref) || "<empty>"}`],
124
+ [!targetSha || receipt?.target?.sha === targetSha, `target SHA mismatch: expected ${targetSha}, got ${receipt?.target?.sha || "<empty>"}`],
125
+ [!targetTree || receipt?.target?.tree === targetTree, `target tree mismatch: expected ${targetTree}, got ${receipt?.target?.tree || "<empty>"}`],
126
+ [!version || receipt?.target?.version === version, `publication version mismatch: expected ${version}, got ${receipt?.target?.version || "<empty>"}`],
127
+ [passportObject && /^[0-9a-f]{64}$/.test(candidateHash), "passport candidateHash must be a sha256 digest"],
128
+ [passportObject && receipt?.recovered?.candidateRoot === candidateRoot, `candidate root mismatch: expected ${candidateRoot}, got ${receipt?.recovered?.candidateRoot || "<empty>"}`],
129
+ [passportObject && receipt?.originalCandidate?.sourceSha === passport?.source?.headSha, "original candidate source SHA mismatch"],
130
+ [passportObject && receipt?.originalCandidate?.tree === passport?.source?.treeHash, "original candidate tree mismatch"],
131
+ ];
132
+ const errors = checks.filter(([ok]) => !ok).map(([, message]) => message);
133
+ return {
134
+ ok: errors.length === 0,
135
+ errors,
136
+ publicationVersion: String(receipt?.target?.version || ""),
137
+ candidateRoot: String(receipt?.recovered?.candidateRoot || ""),
138
+ };
98
139
  }
99
140
 
100
- function validatePlatformPayloads(passport, artifacts, platformManifests) {
141
+ function sameArtifactFile(left, right) {
142
+ return Boolean(left && right && left.size === right.size && left.sha256 === right.sha256);
143
+ }
144
+
145
+ function validatePlatformPayloads(passport, artifacts, platformManifests, platformManifestEvidence) {
101
146
  const byName = new Map(artifacts.map((artifact) => [artifact.name, artifact]));
102
147
  const manifestsByArtifact = new Map((platformManifests || []).map((manifest) => [manifest.artifactName, manifest]));
148
+ const evidenceByArtifact = new Map((platformManifestEvidence || []).map((evidence) => [evidence.artifactName, evidence]));
103
149
  if (manifestsByArtifact.size !== (passport.platformMatrix || []).length) {
104
150
  fail("platform-matrix-mismatch", "platform manifest count differs from the Passport platform matrix", "Restore every exact platform manifest from the candidate run.");
105
151
  }
@@ -122,10 +168,26 @@ function validatePlatformPayloads(passport, artifacts, platformManifests) {
122
168
  size: Number(file.size ?? file.bytes),
123
169
  sha256: `sha256:${String(file.sha256 || "").replace(/^sha256:/, "")}`,
124
170
  })).sort((left, right) => left.path.localeCompare(right.path));
125
- const productPayloadFiles = payload.files.filter((file) => !isBuildchainDiagnosticsEnvelope(file));
126
- const manifestProductFiles = manifestFiles.filter((file) => !isBuildchainDiagnosticsEnvelope(file));
127
- if (JSON.stringify(productPayloadFiles) !== JSON.stringify(manifestProductFiles)) {
128
- fail("artifact-manifest-mismatch", `platform payload bytes differ from the uploaded platform manifest: ${platform.artifactName}`, "Do not publish; preserve the mismatched manifest and payload evidence.");
171
+ const platformId = required(platform.platformId, `${platform.artifactName}.platformId`);
172
+ const buildchainEvidencePrefix = `.buildchain/artifacts/${platformId}/`;
173
+ const manifestByPath = new Map(manifestFiles.map((file) => [file.path, file]));
174
+ const evidenceFiles = new Map((evidenceByArtifact.get(platform.artifactName)?.files || []).map((file) => [file.path, file]));
175
+ const payloadPaths = new Set(payload.files.map((file) => file.path));
176
+ for (const manifestFile of manifestFiles) {
177
+ if (!payloadPaths.has(manifestFile.path)) {
178
+ fail("artifact-manifest-mismatch", `platform payload omits a manifest-declared file: ${platform.artifactName}/${manifestFile.path}`, "Do not publish; preserve the mismatched manifest and payload evidence.");
179
+ }
180
+ }
181
+ for (const payloadFile of payload.files) {
182
+ const manifestFile = manifestByPath.get(payloadFile.path);
183
+ if (sameArtifactFile(payloadFile, manifestFile)) continue;
184
+ const evidencePath = payloadFile.path.startsWith(buildchainEvidencePrefix)
185
+ ? payloadFile.path.slice(buildchainEvidencePrefix.length)
186
+ : "";
187
+ const evidenceFile = evidencePath ? evidenceFiles.get(evidencePath) : undefined;
188
+ if (!sameArtifactFile(payloadFile, evidenceFile)) {
189
+ fail("artifact-manifest-mismatch", `platform payload contains unbound bytes or evidence drift: ${platform.artifactName}/${payloadFile.path}`, "Do not publish; preserve the platform payload, manifest, and independently uploaded evidence.");
190
+ }
129
191
  }
130
192
  if (passportFiles.length > 0 && JSON.stringify(manifestFiles) !== JSON.stringify(passportFiles)) {
131
193
  fail("artifact-manifest-mismatch", `platform manifest differs from Passport inventory: ${platform.artifactName}`, "Do not publish; preserve the mismatched manifest and Passport evidence.");
@@ -236,17 +298,17 @@ function validateCandidateIdentity({
236
298
  return { sha, tree, runtimeSha, toolingSha };
237
299
  }
238
300
 
239
- function validateRecoveryTransaction({ existingTransaction, expectedTransactionId, repository, passport, sha, targetRef, candidateRoot }) {
301
+ function validateRecoveryTransaction({ existingTransaction, expectedTransactionId, repository, version, passport, sha, targetRef, candidateRoot }) {
240
302
  const actualTransactionId = String(existingTransaction?.id || "");
241
303
  if (expectedTransactionId && !actualTransactionId) fail("transaction-identity-conflict", `expected transaction ${expectedTransactionId} does not exist`, "Remove the stale transaction identity only if no durable transaction was ever sealed; otherwise preserve evidence and enter repair_required.");
242
304
  if (expectedTransactionId && expectedTransactionId !== actualTransactionId) fail("transaction-identity-conflict", `existing transaction ${actualTransactionId} conflicts with expected ${expectedTransactionId}`, "Enter repair_required and inspect the durable transaction before any retry.");
243
305
  if (existingTransaction) {
244
- const expectedIdentity = releaseTransactionId({ repository, version: passport.target.version, sourceSha: sha, targetRef: normalizedRef(targetRef) });
306
+ const expectedIdentity = releaseTransactionId({ repository, version, sourceSha: sha, targetRef: normalizedRef(targetRef) });
245
307
  assertEqual(existingTransaction.id, expectedIdentity, "transaction-identity-conflict", "durable transaction identity", "Enter repair_required; the durable transaction does not belong to this exact publication target.");
246
308
  assertEqual(existingTransaction.repository, repository, "transaction-identity-conflict", "durable transaction repository", "Enter repair_required; never cross repository transaction boundaries.");
247
309
  assertEqual(normalizedRef(existingTransaction.target_ref), normalizedRef(targetRef), "transaction-identity-conflict", "durable transaction target ref", "Enter repair_required; never retarget a sealed transaction.");
248
310
  assertEqual(existingTransaction.source_sha, sha, "transaction-identity-conflict", "durable transaction source SHA", "Resume with the transaction's exact promotion SHA or enter repair_required.");
249
- assertEqual(existingTransaction.version, passport.target.version, "transaction-identity-conflict", "durable transaction version", "Enter repair_required; never change a sealed publication version.");
311
+ assertEqual(existingTransaction.version, version, "transaction-identity-conflict", "durable transaction version", "Enter repair_required; never change a sealed publication version.");
250
312
  assertEqual(existingTransaction.channel, passport.target.channel, "transaction-identity-conflict", "durable transaction channel", "Enter repair_required; never move a transaction between channels.");
251
313
  }
252
314
  if (existingTransaction?.candidateRoot && existingTransaction.candidateRoot !== candidateRoot) fail("transaction-identity-conflict", "existing transaction is sealed to a different candidate root", "Enter repair_required; never reuse the conflicting transaction.");
@@ -276,8 +338,10 @@ export function verifyReleaseCandidateRecovery({
276
338
  buildSummary,
277
339
  controllerReceipts = [],
278
340
  platformManifests = [],
341
+ platformManifestEvidence = [],
279
342
  productPayloadManifests = [],
280
343
  artifacts = [],
344
+ publicationVersion = "",
281
345
  currentToolingSha,
282
346
  recoveryRunId = "",
283
347
  createdAt = new Date().toISOString(),
@@ -296,7 +360,7 @@ export function verifyReleaseCandidateRecovery({
296
360
  if (new Set(recoveredArtifacts.map((artifact) => artifact.name)).size !== recoveredArtifacts.length) {
297
361
  fail("artifact-count-mismatch", "candidate artifact names are not unique", "Inspect the candidate run and remove ambiguity by creating a new candidate.");
298
362
  }
299
- validatePlatformPayloads(passport, recoveredArtifacts, platformManifests);
363
+ validatePlatformPayloads(passport, recoveredArtifacts, platformManifests, platformManifestEvidence);
300
364
 
301
365
  const references = new Map((passport.controllerReceipts || []).map((reference) => [reference.controllerId, reference]));
302
366
  for (const receipt of controllerReceipts) {
@@ -331,8 +395,9 @@ export function verifyReleaseCandidateRecovery({
331
395
  runtimeSha,
332
396
  });
333
397
 
398
+ const version = required(publicationVersion || passport.target?.version, "publicationVersion");
334
399
  const actualTransactionId = validateRecoveryTransaction({
335
- existingTransaction, expectedTransactionId, repository, passport, sha, targetRef, candidateRoot,
400
+ existingTransaction, expectedTransactionId, repository, version, passport, sha, targetRef, candidateRoot,
336
401
  });
337
402
 
338
403
  const receipt = {
@@ -351,7 +416,7 @@ export function verifyReleaseCandidateRecovery({
351
416
  mergeSha: String(pullRequest.mergeSha || ""),
352
417
  tree: passport.source.treeHash,
353
418
  },
354
- target: { channel: passport.target.channel, ref: normalizedRef(targetRef), sha, tree },
419
+ target: { channel: passport.target.channel, ref: normalizedRef(targetRef), sha, tree, version },
355
420
  recovered: {
356
421
  candidateRoot,
357
422
  buildSummaryRoot: `sha256:${passport.diagnostics.buildSummaryHash}`,
@@ -992,7 +992,7 @@ for (const requiredSnippet of [
992
992
  "resume-buildchain-runtime-sha:",
993
993
  "github-release: true",
994
994
  "release-passport-buildchain-self-kfd: true",
995
- "artifact-patterns: ${{ inputs['resume-candidate-run-id'] != '' && 'buildchain-package-*' || '' }}",
995
+ 'artifact-patterns: "buildchain-package-*"',
996
996
  "release-passport-impact-json: .buildchain/release-impact.json",
997
997
  ]) {
998
998
  if (!buildchainRefPromotionWorkflow.includes(requiredSnippet)) {
@@ -1051,6 +1051,8 @@ for (const requiredSnippet of [
1051
1051
  "publish-sealed-bundle-root: ${{ steps.rc.outputs.publish-sealed-bundle-root }}",
1052
1052
  "BUILDCHAIN_EXPECTED_TRANSACTION_ID: ${{ inputs.resume-transaction-id }}",
1053
1053
  "if: ${{ inputs.resume-candidate-run-id == '' }}",
1054
+ "Bridge Buildchain self-runtime dependencies",
1055
+ "ln -s .buildchain/runtime/node_modules node_modules",
1054
1056
  ]) {
1055
1057
  if (!releaseCandidatePromoteWorkflow.includes(requiredSnippet)) {
1056
1058
  throw new Error(`release candidate promote workflow missing KFD gate pass-through: ${requiredSnippet}`);
@@ -0,0 +1,104 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+
5
+ import {
6
+ PUBLICATION_ARTIFACT_CANDIDATE_CONTRACT,
7
+ publicationArtifactCandidateDigest,
8
+ } from "../packages/core/publication-artifact-candidate.js";
9
+ import { createPublicationSealedBundle } from "../packages/core/publication-sealed-bundle.js";
10
+
11
+ function requiredString(value, label) {
12
+ const normalized = String(value || "").trim();
13
+ if (!normalized) throw new Error(`${label} must be a non-empty string`);
14
+ return normalized;
15
+ }
16
+
17
+ function normalizeSha256(value, label) {
18
+ const digest = requiredString(value, label).replace(/^sha256:/, "").toLowerCase();
19
+ if (!/^[0-9a-f]{64}$/.test(digest)) throw new Error(`${label} must be a sha256 digest`);
20
+ return digest;
21
+ }
22
+
23
+ function assertGitSha(value, label) {
24
+ const sha = requiredString(value, label);
25
+ if (!/^[0-9a-f]{40}$/i.test(sha)) throw new Error(`${label} must be a 40-character Git SHA`);
26
+ return sha.toLowerCase();
27
+ }
28
+
29
+ function collectCandidateFiles(root) {
30
+ const resolvedRoot = path.resolve(requiredString(root, "bundleRoot"));
31
+ const files = [];
32
+ const stack = fs.existsSync(resolvedRoot) ? [resolvedRoot] : [];
33
+ while (stack.length) {
34
+ const current = stack.pop();
35
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
36
+ const absolutePath = path.join(current, entry.name);
37
+ if (entry.isDirectory()) {
38
+ stack.push(absolutePath);
39
+ } else if (entry.isFile()) {
40
+ files.push({
41
+ path: path.relative(resolvedRoot, absolutePath).split(path.sep).join("/"),
42
+ absolutePath,
43
+ size: fs.statSync(absolutePath).size,
44
+ sha256: crypto.createHash("sha256").update(fs.readFileSync(absolutePath)).digest("hex"),
45
+ });
46
+ }
47
+ }
48
+ }
49
+ return { resolvedRoot, files: files.sort((left, right) => left.path.localeCompare(right.path)) };
50
+ }
51
+
52
+ export function createResolvedPublicationSealedBundle({
53
+ bundleRoot,
54
+ repository,
55
+ sourceSha,
56
+ sourceTreeSha,
57
+ runtimeSha,
58
+ releaseCandidateRoot,
59
+ npmArtifacts = [],
60
+ releaseAssetPaths = [],
61
+ } = {}) {
62
+ if (npmArtifacts.length === 0) return undefined;
63
+ const { resolvedRoot, files } = collectCandidateFiles(bundleRoot);
64
+ const byAbsolutePath = new Map(files.map((file) => [path.resolve(file.absolutePath), file]));
65
+ const resolvedNpmArtifacts = npmArtifacts.map((artifact, index) => {
66
+ const file = byAbsolutePath.get(path.resolve(requiredString(artifact.path, `npmArtifacts[${index}].path`)));
67
+ if (!file) throw new Error(`npmArtifacts[${index}].path is outside the sealed payload root`);
68
+ return { file, metadata: artifact };
69
+ });
70
+ const main = resolvedNpmArtifacts.find((entry) => entry.metadata.role === "main")
71
+ || (resolvedNpmArtifacts.length === 1 ? resolvedNpmArtifacts[0] : undefined);
72
+ if (!main) throw new Error("candidate npm payload set has no unique main package tarball");
73
+ const selectedReleaseAssets = (releaseAssetPaths.length > 0
74
+ ? releaseAssetPaths
75
+ : resolvedNpmArtifacts.map((entry) => entry.file.absolutePath))
76
+ .map((assetPath, index) => {
77
+ const file = byAbsolutePath.get(path.resolve(assetPath));
78
+ if (!file) throw new Error(`releaseAssetPaths[${index}] is outside the sealed payload root`);
79
+ return file;
80
+ });
81
+ const candidatePayload = {
82
+ schemaVersion: 1,
83
+ contract: PUBLICATION_ARTIFACT_CANDIDATE_CONTRACT,
84
+ repository: requiredString(repository, "repository"),
85
+ sourceSha: assertGitSha(sourceSha, "sourceSha"),
86
+ sourceTreeSha: assertGitSha(sourceTreeSha, "sourceTreeSha"),
87
+ runtimeSha: assertGitSha(runtimeSha, "runtimeSha"),
88
+ releaseCandidateRoot: `sha256:${normalizeSha256(releaseCandidateRoot, "releaseCandidateRoot")}`,
89
+ files: files.map(({ path: filePath, size, sha256 }) => ({ path: filePath, size, sha256 })),
90
+ };
91
+ const candidate = {
92
+ ...candidatePayload,
93
+ candidateDigest: publicationArtifactCandidateDigest(candidatePayload),
94
+ };
95
+ const manifest = createPublicationSealedBundle({
96
+ candidate,
97
+ packageName: main.metadata.name,
98
+ packageVersion: main.metadata.ref,
99
+ npmTarballPath: main.file.path,
100
+ npmIntegrity: main.metadata.integrity,
101
+ releaseAssetPaths: selectedReleaseAssets.map((file) => file.path),
102
+ });
103
+ return { root: resolvedRoot, manifest, npmArtifacts: resolvedNpmArtifacts, files };
104
+ }
@@ -5,6 +5,7 @@ import os from "node:os";
5
5
  import path from "node:path";
6
6
  import { execFileSync } from "node:child_process";
7
7
  import { pathToFileURL } from "node:url";
8
+ import { createResolvedPublicationSealedBundle } from "./publication-candidate-sealer.mjs";
8
9
  import { writeGitHubOutputs } from "./build-contract-core.mjs";
9
10
 
10
11
  const DEFAULT_WORKFLOW_FILE = "build-surface-fixture.yml";
@@ -421,6 +422,7 @@ export async function resolveReleaseCandidateArtifacts({
421
422
  requiredArtifactCount = 0,
422
423
  publishArtifactKind = "npm",
423
424
  publishPackageMain = "",
425
+ runtimeSha = "",
424
426
  outputDir = ".buildchain/release-candidate",
425
427
  fetchImpl = globalThis.fetch,
426
428
  download = true,
@@ -668,6 +670,27 @@ export async function resolveReleaseCandidateArtifacts({
668
670
  });
669
671
  const requiredArtifactsPath = path.join(resolvedOutput, "publish-required-artifacts.json");
670
672
  fs.writeFileSync(requiredArtifactsPath, `${JSON.stringify(generatedRequiredArtifacts, null, 2)}\n`);
673
+ const sealedBundle = publishArtifactKind === "npm"
674
+ ? createResolvedPublicationSealedBundle({
675
+ bundleRoot: payloadDir,
676
+ repository: repoInfo.fullName,
677
+ sourceSha: passport.source?.headSha,
678
+ sourceTreeSha: passport.source?.treeHash,
679
+ runtimeSha: runtimeSha || sha,
680
+ releaseCandidateRoot: passport.candidateHash,
681
+ npmArtifacts: npmTarballPaths.map((tarballPath) => ({
682
+ path: tarballPath,
683
+ ...readNpmPackageArtifact({ tarballPath, mainPackage: publishPackageMain }),
684
+ })),
685
+ releaseAssetPaths,
686
+ })
687
+ : undefined;
688
+ const sealedBundleManifestPath = sealedBundle
689
+ ? path.join(resolvedOutput, "sealed-bundle.json")
690
+ : "";
691
+ if (sealedBundleManifestPath) {
692
+ fs.writeFileSync(sealedBundleManifestPath, `${JSON.stringify(sealedBundle.manifest, null, 2)}\n`);
693
+ }
671
694
  return {
672
695
  ...result,
673
696
  paths: {
@@ -679,6 +702,8 @@ export async function resolveReleaseCandidateArtifacts({
679
702
  npmTarballs: npmTarballPaths.map(outputPath),
680
703
  releaseAssets: releaseAssetPaths.map(outputPath),
681
704
  publishRequiredArtifacts: outputPath(requiredArtifactsPath),
705
+ sealedBundleRoot: sealedBundle ? outputPath(sealedBundle.root) : "",
706
+ sealedBundleManifest: sealedBundleManifestPath ? outputPath(sealedBundleManifestPath) : "",
682
707
  },
683
708
  version: passport.target?.version || "",
684
709
  candidateHash: passport.candidateHash || "",
@@ -705,6 +730,7 @@ export async function resolveReleaseCandidateArtifactsCli() {
705
730
  requiredArtifactCount: env("BUILDCHAIN_REQUIRED_ARTIFACT_COUNT", "0"),
706
731
  publishArtifactKind: env("BUILDCHAIN_PUBLISH_ARTIFACT_KIND", "npm"),
707
732
  publishPackageMain: env("BUILDCHAIN_PUBLISH_PACKAGE_MAIN"),
733
+ runtimeSha: env("BUILDCHAIN_CURRENT_RUNTIME_SHA", env("BUILDCHAIN_RUNTIME_SHA", env("BUILDCHAIN_TARGET_SHA"))),
708
734
  outputDir: env("BUILDCHAIN_RC_OUTPUT_DIR", ".buildchain/release-candidate"),
709
735
  download: releaseCandidateDownloadEnabled(env("BUILDCHAIN_RC_DOWNLOAD", "true")),
710
736
  waitSeconds: env("BUILDCHAIN_RC_WAIT_SECONDS", "600"),
@@ -735,6 +761,8 @@ export async function resolveReleaseCandidateArtifactsCli() {
735
761
  ).join("\n"),
736
762
  "publish-required-artifacts-json": JSON.stringify(result.publishRequiredArtifacts || []),
737
763
  "publish-required-artifacts-path": result.paths?.publishRequiredArtifacts || "",
764
+ "publish-sealed-bundle-root": result.paths?.sealedBundleRoot || "",
765
+ "publish-sealed-bundle-manifest": result.paths?.sealedBundleManifest || "",
738
766
  "release-candidate-run-id": result.run?.id || "",
739
767
  "release-candidate-run-url": result.run?.url || "",
740
768
  "release-candidate-pr": result.pullRequest?.number ? String(result.pullRequest.number) : "",