@kungfu-tech/buildchain 2.14.16 → 2.14.17-alpha.1
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/dist/site/buildchain-contract.json +8 -5
- package/dist/site/buildchain-site.json +4 -4
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/node-api-registry.json +2 -2
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +4 -4
- package/package.json +1 -1
- package/packages/core/buildchain-contract.js +8 -1
- package/packages/core/publication-control-plane-audit.js +46 -0
- package/scripts/assemble-binary-release-admission.mjs +15 -3
- package/scripts/audit-publication-control-plane.mjs +49 -4
- package/scripts/web-surface-core.mjs +1 -1
- package/scripts/web-surface-production-decision.mjs +7 -3
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"product": {
|
|
5
5
|
"name": "Buildchain",
|
|
6
6
|
"package": "@kungfu-tech/buildchain",
|
|
7
|
-
"version": "2.14.
|
|
7
|
+
"version": "2.14.17-alpha.1",
|
|
8
8
|
"repository": "https://github.com/kungfu-systems/buildchain"
|
|
9
9
|
},
|
|
10
10
|
"majorLine": "v2",
|
|
@@ -256,7 +256,7 @@
|
|
|
256
256
|
"channel-aware artifact host facts are checked against the deploy plan before adapter side effects"
|
|
257
257
|
],
|
|
258
258
|
"breakingDigest": "sha256:da569f90374e878948e3d5160ed9929338ce0572473ca8ee54867b0fe1aaeace",
|
|
259
|
-
"auditDigest": "sha256:
|
|
259
|
+
"auditDigest": "sha256:4a7c696ec399c14aa3170fdd24adac0d624bd33db6a2639c489e2b58726c190b"
|
|
260
260
|
},
|
|
261
261
|
{
|
|
262
262
|
"contractVersion": 1,
|
|
@@ -323,6 +323,9 @@
|
|
|
323
323
|
"publish transactions can require a resolved publish-gate source lock to prevent floating-ref drift",
|
|
324
324
|
"semver GitHub Releases are created or updated only after transaction completion, with prerelease/latest metadata bound to the authoritative publication channel and tag syntax retained as the fallback for ordinary callers"
|
|
325
325
|
],
|
|
326
|
+
"compatibleBreakingDigests": [
|
|
327
|
+
"sha256:a59f0910e6df842e7699139472e5dd69ac2fdd7f7213bf2cb346d1d622556874"
|
|
328
|
+
],
|
|
326
329
|
"breakingDigest": "sha256:6147c0a8d5c36bfaa6021871574e1fc28192a3f1b8cfdae4d24ef3059ac1ebda",
|
|
327
330
|
"auditDigest": "sha256:ff220542fd1cb21fc4780d0bb31eb9f78d44d70746b6c4364483e104b48ae083"
|
|
328
331
|
},
|
|
@@ -604,7 +607,7 @@
|
|
|
604
607
|
"agents can discover supported Node APIs without importing internal file paths"
|
|
605
608
|
],
|
|
606
609
|
"breakingDigest": "sha256:48f925608d3e2131d90936b07dc2a30341204cae3e6e785c0f77d61ad755c945",
|
|
607
|
-
"auditDigest": "sha256:
|
|
610
|
+
"auditDigest": "sha256:915daa5d9dd8879a356865d2ab9336a8f2fb9806b43f5ba18eadfe448e6d8304"
|
|
608
611
|
},
|
|
609
612
|
{
|
|
610
613
|
"contractVersion": 1,
|
|
@@ -1850,7 +1853,7 @@
|
|
|
1850
1853
|
"missing receipts are non-qualifying and must not be represented as a successful controller run"
|
|
1851
1854
|
],
|
|
1852
1855
|
"breakingDigest": "sha256:f14825324a16b51c2e9ed708ebe64e1932e05b6d5e0866f83aea8439decb4a27",
|
|
1853
|
-
"auditDigest": "sha256:
|
|
1856
|
+
"auditDigest": "sha256:4a7c696ec399c14aa3170fdd24adac0d624bd33db6a2639c489e2b58726c190b"
|
|
1854
1857
|
},
|
|
1855
1858
|
{
|
|
1856
1859
|
"contractVersion": 1,
|
|
@@ -2913,5 +2916,5 @@
|
|
|
2913
2916
|
}
|
|
2914
2917
|
],
|
|
2915
2918
|
"compatibilityDigest": "sha256:cdf588422ec6b460bd6f631400efa6e361a045e052c8967d6c50fadd7aa4dd90",
|
|
2916
|
-
"contractDigest": "sha256:
|
|
2919
|
+
"contractDigest": "sha256:9d5bef7245674767352cc2746d507d556a11d685502120c00176f1a15bade2ba"
|
|
2917
2920
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"contract": "kungfu-buildchain-site-bundle",
|
|
4
|
-
"generatedAt": "2026-07-
|
|
5
|
-
"publishedAt": "2026-07-
|
|
4
|
+
"generatedAt": "2026-07-22T23:30:42.191Z",
|
|
5
|
+
"publishedAt": "2026-07-22T23:30:42.191Z",
|
|
6
6
|
"reproducible": true,
|
|
7
7
|
"timestampPolicy": "ci-injected",
|
|
8
8
|
"deterministicInputs": [
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"declared Buildchain surface manifest contract"
|
|
20
20
|
],
|
|
21
21
|
"sourceDateEpoch": "0",
|
|
22
|
-
"sourceRevision": "
|
|
22
|
+
"sourceRevision": "7c7ff64cd7cd3b34ad377999ed8aa22b1e1d8d93",
|
|
23
23
|
"timestampPolicyDetails": {
|
|
24
24
|
"contract": "kungfu-buildchain-surface-timestamp-policy",
|
|
25
25
|
"timestampFields": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"package": {
|
|
39
39
|
"name": "@kungfu-tech/buildchain",
|
|
40
|
-
"version": "2.14.
|
|
40
|
+
"version": "2.14.17-alpha.1",
|
|
41
41
|
"versionSource": "package.json#version"
|
|
42
42
|
},
|
|
43
43
|
"source": {
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"specifier": "@kungfu-tech/buildchain/buildchain-contract",
|
|
100
100
|
"export": "./buildchain-contract",
|
|
101
101
|
"target": "./packages/core/buildchain-contract.js",
|
|
102
|
-
"digest": "sha256:
|
|
102
|
+
"digest": "sha256:1e5f8a1741a0a98116e754ef0874337db4c1821bb7a153ab398009145509681c",
|
|
103
103
|
"summary": "Runtime contract world and compatibility digest APIs for floating-ref drift checks.",
|
|
104
104
|
"capabilityGroup": "governance-versioning",
|
|
105
105
|
"audience": [
|
|
@@ -307,7 +307,7 @@
|
|
|
307
307
|
"specifier": "@kungfu-tech/buildchain/publication-control-plane-audit",
|
|
308
308
|
"export": "./publication-control-plane-audit",
|
|
309
309
|
"target": "./packages/core/publication-control-plane-audit.js",
|
|
310
|
-
"digest": "sha256:
|
|
310
|
+
"digest": "sha256:8220ad9cdf7fb9d2f361cf7b066aad039412a378350676edfdb4c1f7019cda20",
|
|
311
311
|
"summary": "Read-only publication control-plane snapshot evaluation APIs.",
|
|
312
312
|
"capabilityGroup": "release-passport-trust",
|
|
313
313
|
"audience": [
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"contract": "kungfu-buildchain-publication-release-registry",
|
|
4
|
-
"generatedAt": "2026-07-
|
|
5
|
-
"publishedAt": "2026-07-
|
|
4
|
+
"generatedAt": "2026-07-22T23:30:42.191Z",
|
|
5
|
+
"publishedAt": "2026-07-22T23:30:42.191Z",
|
|
6
6
|
"reproducible": true,
|
|
7
7
|
"timestampPolicy": "ci-injected",
|
|
8
8
|
"deterministicInputs": [
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"declared Buildchain surface manifest contract"
|
|
20
20
|
],
|
|
21
21
|
"sourceDateEpoch": "0",
|
|
22
|
-
"sourceRevision": "
|
|
22
|
+
"sourceRevision": "7c7ff64cd7cd3b34ad377999ed8aa22b1e1d8d93",
|
|
23
23
|
"timestampPolicyDetails": {
|
|
24
24
|
"contract": "kungfu-buildchain-surface-timestamp-policy",
|
|
25
25
|
"timestampFields": [
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"package": {
|
|
34
34
|
"name": "@kungfu-tech/buildchain",
|
|
35
|
-
"version": "2.14.
|
|
35
|
+
"version": "2.14.17-alpha.1",
|
|
36
36
|
"versionSource": "package.json#version"
|
|
37
37
|
},
|
|
38
38
|
"sourceKind": "package-site-bundle",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"contract": "kungfu-buildchain-site-manifest",
|
|
4
|
-
"generatedAt": "2026-07-
|
|
5
|
-
"publishedAt": "2026-07-
|
|
4
|
+
"generatedAt": "2026-07-22T23:30:42.191Z",
|
|
5
|
+
"publishedAt": "2026-07-22T23:30:42.191Z",
|
|
6
6
|
"reproducible": true,
|
|
7
7
|
"timestampPolicy": "ci-injected",
|
|
8
8
|
"deterministicInputs": [
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"declared Buildchain surface manifest contract"
|
|
20
20
|
],
|
|
21
21
|
"sourceDateEpoch": "0",
|
|
22
|
-
"sourceRevision": "
|
|
22
|
+
"sourceRevision": "7c7ff64cd7cd3b34ad377999ed8aa22b1e1d8d93",
|
|
23
23
|
"timestampPolicyDetails": {
|
|
24
24
|
"contract": "kungfu-buildchain-surface-timestamp-policy",
|
|
25
25
|
"timestampFields": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"package": {
|
|
39
39
|
"name": "@kungfu-tech/buildchain",
|
|
40
|
-
"version": "2.14.
|
|
40
|
+
"version": "2.14.17-alpha.1",
|
|
41
41
|
"versionSource": "package.json#version"
|
|
42
42
|
},
|
|
43
43
|
"entrypoint": "buildchain-site.json",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kungfu-tech/buildchain",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.17-alpha.1",
|
|
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",
|
|
@@ -351,6 +351,9 @@ export function createBuildchainContractWorld({
|
|
|
351
351
|
"publish transactions can require a resolved publish-gate source lock to prevent floating-ref drift",
|
|
352
352
|
"semver GitHub Releases are created or updated only after transaction completion, with prerelease/latest metadata bound to the authoritative publication channel and tag syntax retained as the fallback for ordinary callers",
|
|
353
353
|
],
|
|
354
|
+
compatibleBreakingDigests: [
|
|
355
|
+
"sha256:a59f0910e6df842e7699139472e5dd69ac2fdd7f7213bf2cb346d1d622556874",
|
|
356
|
+
],
|
|
354
357
|
}),
|
|
355
358
|
surface(root, {
|
|
356
359
|
id: "report-buildchain-issue-action",
|
|
@@ -758,7 +761,11 @@ export function evaluateBuildchainContractLock({
|
|
|
758
761
|
reasons.push(`surface removed: ${oldSurface.id}`);
|
|
759
762
|
continue;
|
|
760
763
|
}
|
|
761
|
-
|
|
764
|
+
const compatibleBreakingDigests = new Set(nextSurface.compatibleBreakingDigests || []);
|
|
765
|
+
if (
|
|
766
|
+
nextSurface.breakingDigest !== oldSurface.breakingDigest
|
|
767
|
+
&& !compatibleBreakingDigests.has(oldSurface.breakingDigest)
|
|
768
|
+
) {
|
|
762
769
|
reasons.push(`surface breaking digest changed: ${oldSurface.id}`);
|
|
763
770
|
}
|
|
764
771
|
}
|
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
import { createPublicationControlPlaneAudit, publicationAuthorityDigest } from "./publication-authority.js";
|
|
2
2
|
|
|
3
|
+
export const BUILDCHAIN_RELEASE_RECONCILIATION_PATHS = Object.freeze([
|
|
4
|
+
".buildchain/release-impact.json",
|
|
5
|
+
"dist/site/buildchain-contract.json",
|
|
6
|
+
"dist/site/buildchain-site.json",
|
|
7
|
+
"dist/site/kfd-upstream-aggregate.json",
|
|
8
|
+
"dist/site/publication-registry.json",
|
|
9
|
+
"dist/site/site-manifest.json",
|
|
10
|
+
"package.json",
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
export function evaluateBuildchainReleaseReconciliation({
|
|
14
|
+
repository,
|
|
15
|
+
publicationVersion,
|
|
16
|
+
packageVersion,
|
|
17
|
+
message,
|
|
18
|
+
parentSha,
|
|
19
|
+
changedPaths,
|
|
20
|
+
} = {}) {
|
|
21
|
+
const normalizedPaths = Array.isArray(changedPaths) ? changedPaths.map(String) : [];
|
|
22
|
+
const allowedPaths = new Set(BUILDCHAIN_RELEASE_RECONCILIATION_PATHS);
|
|
23
|
+
return {
|
|
24
|
+
qualifying: repository === "kungfu-systems/buildchain" &&
|
|
25
|
+
/^\d+\.\d+\.\d+$/.test(String(publicationVersion || "")) &&
|
|
26
|
+
message === `chore(release): release v${publicationVersion}` &&
|
|
27
|
+
packageVersion === publicationVersion &&
|
|
28
|
+
normalizedPaths.length > 0 &&
|
|
29
|
+
normalizedPaths.every((entry) => allowedPaths.has(entry)) &&
|
|
30
|
+
/^[0-9a-f]{40}$/.test(String(parentSha || "")),
|
|
31
|
+
parentSha: String(parentSha || ""),
|
|
32
|
+
version: String(publicationVersion || ""),
|
|
33
|
+
packageVersion: String(packageVersion || ""),
|
|
34
|
+
message: String(message || ""),
|
|
35
|
+
changedPaths: normalizedPaths,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
3
39
|
function fact(id, pass, observed) {
|
|
4
40
|
return {
|
|
5
41
|
id,
|
|
@@ -77,6 +113,15 @@ export function evaluatePublicationControlPlaneSnapshot({
|
|
|
77
113
|
branchPolicy.requiredStatusCheckMatchCount === 1
|
|
78
114
|
)
|
|
79
115
|
);
|
|
116
|
+
const authorizationSha = branchPolicy.authorizationSha || branchPolicy.sourceSha;
|
|
117
|
+
const sourceAuthorizationPass = branchPolicy.sourceSha === authorizationSha || (
|
|
118
|
+
branchPolicy.releaseReconciliation?.qualifying === true &&
|
|
119
|
+
branchPolicy.releaseReconciliation.parentSha === authorizationSha &&
|
|
120
|
+
/^\d+\.\d+\.\d+$/.test(String(branchPolicy.releaseReconciliation.version || "")) &&
|
|
121
|
+
branchPolicy.releaseReconciliation.packageVersion === branchPolicy.releaseReconciliation.version &&
|
|
122
|
+
Array.isArray(branchPolicy.releaseReconciliation.changedPaths) &&
|
|
123
|
+
branchPolicy.releaseReconciliation.changedPaths.length > 0
|
|
124
|
+
);
|
|
80
125
|
const providerTransactionBranchPass = branchPolicy.ref === branch &&
|
|
81
126
|
branchPolicy.policyMode === "provider-enforced-transaction" &&
|
|
82
127
|
branchPolicy.protected === true &&
|
|
@@ -88,6 +133,7 @@ export function evaluatePublicationControlPlaneSnapshot({
|
|
|
88
133
|
/^[0-9a-f]{40}$/i.test(String(branchPolicy.requiredCheckSha || "")) &&
|
|
89
134
|
branchPolicy.requiredCheckSha === branchPolicy.pullRequestHeadSha &&
|
|
90
135
|
branchPolicy.sourceSha === branchPolicy.headSha &&
|
|
136
|
+
sourceAuthorizationPass &&
|
|
91
137
|
branchPolicy.mergedPullRequest === true &&
|
|
92
138
|
branchPolicy.baseRef === branch &&
|
|
93
139
|
branchPolicy.headRepository === repository &&
|
|
@@ -4,7 +4,10 @@ import fs from "node:fs";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
validateControllerPlan,
|
|
9
|
+
validateControllerReceipt,
|
|
10
|
+
} from "../packages/core/controller-evidence.js";
|
|
8
11
|
import {
|
|
9
12
|
createPublicationAdmission,
|
|
10
13
|
createPublicationGateDecision,
|
|
@@ -102,15 +105,23 @@ function main() {
|
|
|
102
105
|
const controllerRoot = path.join(evidenceRoot, "binary-controller");
|
|
103
106
|
const manifest = readJson(oneFile(passportRoot, "buildchain-release-bundle.json"));
|
|
104
107
|
const archivePath = oneFile(passportRoot, "buildchain-release-bundle.tar.gz");
|
|
108
|
+
const controllerPlan = readJson(oneFile(controllerRoot, "plan.json"));
|
|
105
109
|
const controllerReceipt = readJson(oneFile(controllerRoot, "receipt.json"));
|
|
106
110
|
validateBundle(manifest, archivePath, { sourceSha, releaseTag });
|
|
107
111
|
|
|
108
|
-
const
|
|
112
|
+
const authorityRuntimeSha = execFileSync("git", ["-C", runtimeRoot, "rev-parse", "HEAD"], { encoding: "utf8" })
|
|
109
113
|
.trim()
|
|
110
114
|
.toLowerCase();
|
|
115
|
+
if (!/^[0-9a-f]{40}$/.test(authorityRuntimeSha)) {
|
|
116
|
+
throw new Error("publication authority runtime SHA is invalid");
|
|
117
|
+
}
|
|
118
|
+
const controllerPlanValidation = validateControllerPlan(controllerPlan);
|
|
119
|
+
if (!controllerPlanValidation.ok || !controllerPlanValidation.qualifying) {
|
|
120
|
+
throw new Error(`binary distribution controller plan did not qualify: ${controllerPlanValidation.issues.join("; ")}`);
|
|
121
|
+
}
|
|
111
122
|
const controllerValidation = validateControllerReceipt(controllerReceipt, {
|
|
123
|
+
plan: controllerPlan,
|
|
112
124
|
expectedSourceSha: sourceSha,
|
|
113
|
-
expectedRuntimeSha: runtimeSha,
|
|
114
125
|
});
|
|
115
126
|
if (!controllerValidation.ok || !controllerValidation.qualifying) {
|
|
116
127
|
throw new Error(`binary distribution controller receipt did not qualify: ${controllerValidation.issues.join("; ")}`);
|
|
@@ -118,6 +129,7 @@ function main() {
|
|
|
118
129
|
if (controllerReceipt.controller?.id !== "binary-distribution") {
|
|
119
130
|
throw new Error("binary distribution controller receipt has the wrong controller id");
|
|
120
131
|
}
|
|
132
|
+
const runtimeSha = controllerReceipt.runtime.sha;
|
|
121
133
|
|
|
122
134
|
const controlPlaneAudit = readJson(required("BUILDCHAIN_CONTROL_PLANE_AUDIT_PATH"));
|
|
123
135
|
const registry = readJson(path.join(runtimeRoot, "dist/site/publication-authority-registry.json"));
|
|
@@ -3,7 +3,10 @@ import { spawnSync } from "node:child_process";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
evaluateBuildchainReleaseReconciliation,
|
|
8
|
+
evaluatePublicationControlPlaneSnapshot,
|
|
9
|
+
} from "../packages/core/publication-control-plane-audit.js";
|
|
7
10
|
|
|
8
11
|
function flag(name, fallback = "") {
|
|
9
12
|
const index = process.argv.indexOf(`--${name}`);
|
|
@@ -199,6 +202,8 @@ function main() {
|
|
|
199
202
|
const sourceSha = flag("source-sha").toLowerCase();
|
|
200
203
|
const packageName = flag("package", "@kungfu-tech/buildchain");
|
|
201
204
|
const publisherMode = flag("publisher-mode", "npm-trusted-publisher");
|
|
205
|
+
const publicationVersion = flag("publication-version");
|
|
206
|
+
const allowReleaseReconciliation = process.argv.includes("--allow-release-reconciliation");
|
|
202
207
|
if (!repository || !branch) throw new Error("--repository and --branch are required");
|
|
203
208
|
|
|
204
209
|
const encodedWorkflow = workflowPath.split("/").map(encodeURIComponent).join("/");
|
|
@@ -260,13 +265,51 @@ function main() {
|
|
|
260
265
|
if (!/^[0-9a-f]{40}$/.test(sourceSha)) {
|
|
261
266
|
throw new Error("--source-sha is required when detailed branch policy is not readable");
|
|
262
267
|
}
|
|
263
|
-
const
|
|
264
|
-
const
|
|
268
|
+
const sourceCommit = githubJson(`repos/${repository}/commits/${sourceSha}`, "source commit");
|
|
269
|
+
const sourceParents = Array.isArray(sourceCommit.parents) ? sourceCommit.parents.map((entry) => String(entry?.sha || "").toLowerCase()) : [];
|
|
270
|
+
const sourceChangedPaths = Array.isArray(sourceCommit.files) ? sourceCommit.files.map((entry) => String(entry?.filename || "")) : [];
|
|
271
|
+
const sourceMessage = String(sourceCommit.commit?.message || "").split("\n", 1)[0];
|
|
272
|
+
let authorizationSha = sourceSha;
|
|
273
|
+
let releaseReconciliation = {
|
|
274
|
+
qualifying: false,
|
|
275
|
+
parentSha: "",
|
|
276
|
+
version: publicationVersion,
|
|
277
|
+
message: sourceMessage,
|
|
278
|
+
changedPaths: sourceChangedPaths,
|
|
279
|
+
};
|
|
280
|
+
let pullRequests = githubJson(`repos/${repository}/commits/${authorizationSha}/pulls`, "source pull-request lineage");
|
|
281
|
+
let mergedPullRequest = (Array.isArray(pullRequests) ? pullRequests : []).find((entry) =>
|
|
265
282
|
entry?.merged_at &&
|
|
266
|
-
entry.merge_commit_sha ===
|
|
283
|
+
entry.merge_commit_sha === authorizationSha &&
|
|
267
284
|
entry.base?.ref === branch &&
|
|
268
285
|
entry.head?.repo?.full_name === repository
|
|
269
286
|
);
|
|
287
|
+
if (!mergedPullRequest && allowReleaseReconciliation) {
|
|
288
|
+
const packageFile = githubJson(
|
|
289
|
+
`repos/${repository}/contents/package.json?ref=${encodeURIComponent(sourceSha)}`,
|
|
290
|
+
"release reconciliation package metadata",
|
|
291
|
+
);
|
|
292
|
+
const packageJson = JSON.parse(Buffer.from(String(packageFile.content || ""), "base64").toString("utf8"));
|
|
293
|
+
const parentSha = sourceParents.length === 1 ? sourceParents[0] : "";
|
|
294
|
+
releaseReconciliation = evaluateBuildchainReleaseReconciliation({
|
|
295
|
+
repository,
|
|
296
|
+
publicationVersion,
|
|
297
|
+
packageVersion: packageJson.version,
|
|
298
|
+
message: sourceMessage,
|
|
299
|
+
parentSha,
|
|
300
|
+
changedPaths: sourceChangedPaths,
|
|
301
|
+
});
|
|
302
|
+
if (releaseReconciliation.qualifying) {
|
|
303
|
+
authorizationSha = parentSha;
|
|
304
|
+
pullRequests = githubJson(`repos/${repository}/commits/${authorizationSha}/pulls`, "release parent pull-request lineage");
|
|
305
|
+
mergedPullRequest = (Array.isArray(pullRequests) ? pullRequests : []).find((entry) =>
|
|
306
|
+
entry?.merged_at &&
|
|
307
|
+
entry.merge_commit_sha === authorizationSha &&
|
|
308
|
+
entry.base?.ref === branch &&
|
|
309
|
+
entry.head?.repo?.full_name === repository
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
270
313
|
const reviews = mergedPullRequest
|
|
271
314
|
? githubJson(`repos/${repository}/pulls/${mergedPullRequest.number}/reviews?per_page=100`, "source pull-request reviews")
|
|
272
315
|
: [];
|
|
@@ -316,7 +359,9 @@ function main() {
|
|
|
316
359
|
requiredCheckAppId: requiredCheckSource?.app_id || 0,
|
|
317
360
|
requiredCheckSha: pullRequestHeadSha,
|
|
318
361
|
sourceSha,
|
|
362
|
+
authorizationSha,
|
|
319
363
|
headSha: String(branchState.commit?.sha || "").toLowerCase(),
|
|
364
|
+
releaseReconciliation,
|
|
320
365
|
mergedPullRequest: Boolean(mergedPullRequest),
|
|
321
366
|
pullRequestNumber: mergedPullRequest?.number || 0,
|
|
322
367
|
pullRequestHeadSha,
|
|
@@ -354,7 +354,7 @@ function publicationImmutablePolicy({ artifactRoot, binding }) {
|
|
|
354
354
|
throw new Error(`declared immutable publication prefix does not exist in artifact: ${prefix}`);
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
|
-
const preservedRoots =
|
|
357
|
+
const preservedRoots = declaredPrefixes;
|
|
358
358
|
const files = preservedRoots
|
|
359
359
|
.flatMap((root) => listFiles(surfaceRoot, root))
|
|
360
360
|
.map((filePath) => ({
|
|
@@ -8,6 +8,7 @@ const TRUSTED_PERMISSIONS = new Set(["write", "maintain", "admin"]);
|
|
|
8
8
|
|
|
9
9
|
export function resolveWebSurfaceProductionDecision({
|
|
10
10
|
eventName,
|
|
11
|
+
eventAction = "",
|
|
11
12
|
refName,
|
|
12
13
|
repository,
|
|
13
14
|
sourceSha,
|
|
@@ -36,9 +37,11 @@ export function resolveWebSurfaceProductionDecision({
|
|
|
36
37
|
reason: trusted ? "trusted-manual-dispatch" : "manual-actor-permission-insufficient",
|
|
37
38
|
});
|
|
38
39
|
}
|
|
40
|
+
const reviewedReleaseEvent =
|
|
41
|
+
(eventName === "push" && refName === "main") ||
|
|
42
|
+
(eventName === "pull_request" && eventAction === "closed");
|
|
39
43
|
if (
|
|
40
|
-
|
|
41
|
-
refName === "main" &&
|
|
44
|
+
reviewedReleaseEvent &&
|
|
42
45
|
productionApply === true &&
|
|
43
46
|
productionReleaseOnMain === true &&
|
|
44
47
|
releaseApproved === true
|
|
@@ -103,9 +106,10 @@ async function main() {
|
|
|
103
106
|
}
|
|
104
107
|
const decision = resolveWebSurfaceProductionDecision({
|
|
105
108
|
eventName,
|
|
109
|
+
eventAction: process.env.GITHUB_EVENT_ACTION,
|
|
106
110
|
refName: process.env.GITHUB_REF_NAME,
|
|
107
111
|
repository,
|
|
108
|
-
sourceSha: process.env.GITHUB_SHA,
|
|
112
|
+
sourceSha: process.env.BUILDCHAIN_PRODUCTION_SOURCE_SHA || process.env.GITHUB_SHA,
|
|
109
113
|
actor,
|
|
110
114
|
productionApply: bool("BUILDCHAIN_PRODUCTION_APPLY"),
|
|
111
115
|
productionApproved: bool("BUILDCHAIN_PRODUCTION_APPROVED"),
|