@kungfu-tech/buildchain 2.12.7-alpha.18 → 2.12.7-alpha.2
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/actions/promote-buildchain-ref/README.md +1 -5
- package/dist/site/buildchain-contract.json +23 -48
- package/dist/site/buildchain-site.json +13 -13
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/controller-registry.json +3 -23
- package/dist/site/kfd-claims.json +8 -60
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +1 -1
- package/dist/site/node-api-registry.json +6 -6
- package/dist/site/page-registry.json +8 -8
- package/dist/site/public-surface-audit.json +9 -71
- package/dist/site/publication-authority-registry.json +1 -25
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +5 -5
- package/dist/site/workflow-registry.json +6 -71
- package/docs/publication-artifacts.md +20 -30
- package/docs/publication-authority.md +2 -11
- package/docs/shifu-gate-profiles.md +0 -6
- package/package.json +1 -1
- package/packages/core/buildchain-publication-authority.js +0 -1
- package/packages/core/controller-evidence.js +1 -1
- package/packages/core/index.js +0 -7
- package/packages/core/publication-authority.js +2 -41
- package/packages/core/publication-control-plane-audit.js +1 -3
- package/scripts/assemble-self-publication-admission.mjs +1 -2
- package/scripts/audit-publication-control-plane.mjs +2 -5
- package/scripts/check-inventory.mjs +0 -3
- package/scripts/workflow-friction-report.mjs +2 -13
- package/packages/core/publication-artifact-candidate.js +0 -128
- package/scripts/assemble-publication-artifact-admission.mjs +0 -190
- package/scripts/publication-artifact-candidate.mjs +0 -122
|
@@ -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-14T16:40:36.563Z",
|
|
5
|
+
"publishedAt": "2026-07-14T16:40:36.563Z",
|
|
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": "31f70f81cbdd542d9473651cf13cd6e8eb33cd74",
|
|
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.12.7-alpha.
|
|
35
|
+
"version": "2.12.7-alpha.2",
|
|
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-14T16:40:36.563Z",
|
|
5
|
+
"publishedAt": "2026-07-14T16:40:36.563Z",
|
|
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": "31f70f81cbdd542d9473651cf13cd6e8eb33cd74",
|
|
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.12.7-alpha.
|
|
40
|
+
"version": "2.12.7-alpha.2",
|
|
41
41
|
"versionSource": "package.json#version"
|
|
42
42
|
},
|
|
43
43
|
"entrypoint": "buildchain-site.json",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"path": "docs/publication-authority.md",
|
|
86
86
|
"plane": "verify",
|
|
87
87
|
"exists": true,
|
|
88
|
-
"digest": "sha256:
|
|
88
|
+
"digest": "sha256:fc08e6657a1b586b6b8b5618ca4f49dfaa85955687f5bba8e2e69e7513fe6c71"
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
"id": "release-candidate",
|
|
@@ -215,18 +215,14 @@
|
|
|
215
215
|
"reusable": true,
|
|
216
216
|
"inputs": [
|
|
217
217
|
"admission-json",
|
|
218
|
-
"authority-workflow-path",
|
|
219
218
|
"auto-admission",
|
|
220
|
-
"auto-admission-kind",
|
|
221
219
|
"buildchain-ref",
|
|
222
220
|
"buildchain-repository",
|
|
223
221
|
"control-plane-audit-json",
|
|
224
222
|
"dry-run",
|
|
225
|
-
"evidence-controller-artifact",
|
|
226
223
|
"evidence-manifest-pattern",
|
|
227
224
|
"evidence-passport-artifact",
|
|
228
225
|
"evidence-payload-pattern",
|
|
229
|
-
"evidence-publication-artifact",
|
|
230
226
|
"evidence-repository",
|
|
231
227
|
"evidence-run-id",
|
|
232
228
|
"evidence-summary-artifact",
|
|
@@ -235,15 +231,13 @@
|
|
|
235
231
|
"package-name",
|
|
236
232
|
"product",
|
|
237
233
|
"publication-target",
|
|
238
|
-
"publication-version",
|
|
239
234
|
"publisher-workflow-path",
|
|
240
|
-
"required-status-check",
|
|
241
235
|
"runner-provenance-json",
|
|
242
236
|
"source-sha",
|
|
243
237
|
"target-ref",
|
|
244
238
|
"used-nonces-json"
|
|
245
239
|
],
|
|
246
|
-
"inputCount":
|
|
240
|
+
"inputCount": 22,
|
|
247
241
|
"secrets": [],
|
|
248
242
|
"secretCount": 0,
|
|
249
243
|
"outputs": [
|
|
@@ -1030,54 +1024,6 @@
|
|
|
1030
1024
|
"capabilityGroup": "api-cli-reference",
|
|
1031
1025
|
"status": "active"
|
|
1032
1026
|
},
|
|
1033
|
-
{
|
|
1034
|
-
"id": "paper-release-sealed",
|
|
1035
|
-
"path": ".github/workflows/paper-release-sealed.yml",
|
|
1036
|
-
"reusable": true,
|
|
1037
|
-
"inputs": [
|
|
1038
|
-
"artifact-name",
|
|
1039
|
-
"artifact-paths",
|
|
1040
|
-
"artifact-retention-days",
|
|
1041
|
-
"branch-protection-bypass-apps",
|
|
1042
|
-
"branch-protection-bypass-teams",
|
|
1043
|
-
"branch-protection-bypass-users",
|
|
1044
|
-
"buildchain-contract-lock-path",
|
|
1045
|
-
"buildchain-ref",
|
|
1046
|
-
"buildchain-repository",
|
|
1047
|
-
"dry-run",
|
|
1048
|
-
"github-release",
|
|
1049
|
-
"github-release-notes",
|
|
1050
|
-
"github-release-title",
|
|
1051
|
-
"package-name",
|
|
1052
|
-
"publish-dist-tag",
|
|
1053
|
-
"publisher-workflow-path",
|
|
1054
|
-
"release-passport-impact-json",
|
|
1055
|
-
"release-passport-output-dir",
|
|
1056
|
-
"release-passport-product-name",
|
|
1057
|
-
"required-status-check",
|
|
1058
|
-
"target-ref",
|
|
1059
|
-
"target-sha",
|
|
1060
|
-
"toolchain-type",
|
|
1061
|
-
"verify-command",
|
|
1062
|
-
"working-directory"
|
|
1063
|
-
],
|
|
1064
|
-
"inputCount": 25,
|
|
1065
|
-
"secrets": [
|
|
1066
|
-
"BUILDCHAIN_PROMOTION_TOKEN"
|
|
1067
|
-
],
|
|
1068
|
-
"secretCount": 1,
|
|
1069
|
-
"outputs": [
|
|
1070
|
-
"github-release-url",
|
|
1071
|
-
"package-name",
|
|
1072
|
-
"package-version",
|
|
1073
|
-
"public-release-tag",
|
|
1074
|
-
"release-passport-path"
|
|
1075
|
-
],
|
|
1076
|
-
"outputCount": 5,
|
|
1077
|
-
"surface": "repository-workflow",
|
|
1078
|
-
"capabilityGroup": "api-cli-reference",
|
|
1079
|
-
"status": "active"
|
|
1080
|
-
},
|
|
1081
1027
|
{
|
|
1082
1028
|
"id": "paper-release",
|
|
1083
1029
|
"path": ".github/workflows/paper-release.yml",
|
|
@@ -1247,11 +1193,7 @@
|
|
|
1247
1193
|
"buildchain-ref",
|
|
1248
1194
|
"buildchain-repository",
|
|
1249
1195
|
"node-version",
|
|
1250
|
-
"package-name",
|
|
1251
|
-
"prepare-paper-package",
|
|
1252
|
-
"publish-dist-tag",
|
|
1253
1196
|
"setup-node",
|
|
1254
|
-
"target-ref",
|
|
1255
1197
|
"toolchain-command",
|
|
1256
1198
|
"toolchain-digest",
|
|
1257
1199
|
"toolchain-image",
|
|
@@ -1259,7 +1201,7 @@
|
|
|
1259
1201
|
"verify-command",
|
|
1260
1202
|
"working-directory"
|
|
1261
1203
|
],
|
|
1262
|
-
"inputCount":
|
|
1204
|
+
"inputCount": 17,
|
|
1263
1205
|
"secrets": [],
|
|
1264
1206
|
"secretCount": 0,
|
|
1265
1207
|
"outputs": [
|
|
@@ -1270,17 +1212,13 @@
|
|
|
1270
1212
|
"controller-receipt-digest",
|
|
1271
1213
|
"controller-receipt-json",
|
|
1272
1214
|
"controller-receipt-status",
|
|
1273
|
-
"package-name",
|
|
1274
|
-
"package-version",
|
|
1275
1215
|
"publication-artifact-name",
|
|
1276
1216
|
"publication-manifest-json",
|
|
1277
1217
|
"publication-manifest-path",
|
|
1278
1218
|
"publication-passport-path",
|
|
1279
|
-
"publication-registry-path"
|
|
1280
|
-
"publish-dist-tag",
|
|
1281
|
-
"runtime-sha"
|
|
1219
|
+
"publication-registry-path"
|
|
1282
1220
|
],
|
|
1283
|
-
"outputCount":
|
|
1221
|
+
"outputCount": 12,
|
|
1284
1222
|
"surface": "repository-workflow",
|
|
1285
1223
|
"capabilityGroup": "reusable-build",
|
|
1286
1224
|
"status": "active"
|
|
@@ -1351,12 +1289,11 @@
|
|
|
1351
1289
|
"BUILDCHAIN_ISSUE_APP_ID",
|
|
1352
1290
|
"BUILDCHAIN_ISSUE_APP_PRIVATE_KEY",
|
|
1353
1291
|
"BUILDCHAIN_ISSUE_TOKEN",
|
|
1354
|
-
"BUILDCHAIN_PROMOTION_TOKEN",
|
|
1355
1292
|
"buildchain-issue-app-id",
|
|
1356
1293
|
"buildchain-issue-app-private-key",
|
|
1357
1294
|
"buildchain-issue-token"
|
|
1358
1295
|
],
|
|
1359
|
-
"secretCount":
|
|
1296
|
+
"secretCount": 6,
|
|
1360
1297
|
"outputs": [
|
|
1361
1298
|
"built-source-sha",
|
|
1362
1299
|
"controller-plan-artifact",
|
|
@@ -1549,11 +1486,9 @@
|
|
|
1549
1486
|
"branch-protection-bypass-teams",
|
|
1550
1487
|
"branch-protection-bypass-users",
|
|
1551
1488
|
"dry-run",
|
|
1552
|
-
"expected-publication-version",
|
|
1553
1489
|
"generated-ref-update-token",
|
|
1554
1490
|
"generated-status-check-token",
|
|
1555
1491
|
"github-release",
|
|
1556
|
-
"github-release-artifact-paths",
|
|
1557
1492
|
"github-release-notes",
|
|
1558
1493
|
"github-release-title",
|
|
1559
1494
|
"promote-only-release-candidate",
|
|
@@ -1599,7 +1534,7 @@
|
|
|
1599
1534
|
"transaction-state-path",
|
|
1600
1535
|
"verification-command"
|
|
1601
1536
|
],
|
|
1602
|
-
"inputCount":
|
|
1537
|
+
"inputCount": 52,
|
|
1603
1538
|
"capabilityGroup": "release-passport-trust",
|
|
1604
1539
|
"status": "active"
|
|
1605
1540
|
},
|
|
@@ -182,42 +182,40 @@ on:
|
|
|
182
182
|
|
|
183
183
|
jobs:
|
|
184
184
|
paper-release:
|
|
185
|
-
uses: kungfu-systems/buildchain/.github/workflows/paper-release
|
|
185
|
+
uses: kungfu-systems/buildchain/.github/workflows/paper-release.yml@v2
|
|
186
186
|
permissions:
|
|
187
|
-
actions: read
|
|
188
187
|
checks: write
|
|
189
188
|
contents: write
|
|
190
189
|
id-token: write
|
|
191
190
|
issues: write
|
|
192
191
|
with:
|
|
193
192
|
buildchain-ref: ${{ inputs.buildchain-ref || '' }}
|
|
194
|
-
|
|
193
|
+
publication-admission-json: ${{ needs.authority.outputs.admission-json }}
|
|
194
|
+
publication-runner-provenance-json: ${{ needs.authority.outputs.runner-provenance-json }}
|
|
195
|
+
publication-control-plane-audit-json: ${{ needs.authority.outputs.control-plane-audit-json }}
|
|
196
|
+
publication-expected-json: ${{ needs.authority.outputs.expected-json }}
|
|
195
197
|
toolchain-type: config
|
|
196
198
|
verify-command: make check
|
|
197
|
-
artifact-paths: _build/paper-name.pdf
|
|
198
199
|
buildchain-contract-lock-path: .buildchain/contract-lock.json
|
|
199
|
-
secrets:
|
|
200
|
-
BUILDCHAIN_PROMOTION_TOKEN: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}
|
|
201
200
|
```
|
|
202
201
|
|
|
203
|
-
The
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
admitted candidate, recomputes the capability binding, and publishes without
|
|
212
|
-
executing consumer build commands. npm binds the OIDC identity to the consumer
|
|
213
|
-
workflow named by `publisher-workflow-path`.
|
|
202
|
+
The publication job does not accept a long-lived promotion token. The caller
|
|
203
|
+
must first produce a fresh sealed admission, runner provenance, external
|
|
204
|
+
control-plane audit, and exact expected bindings. The credential-free verifier
|
|
205
|
+
job checks those receipts; only then can the publication job use its short-lived
|
|
206
|
+
`github.token` and caller-bound OIDC trusted publisher identity. npm binds that
|
|
207
|
+
identity to the consumer workflow filename; an npm Environment restriction is
|
|
208
|
+
optional and must be represented explicitly when configured. The workflow fails
|
|
209
|
+
before the publication build when the target branch protection cannot be read.
|
|
214
210
|
|
|
215
211
|
The preset:
|
|
216
212
|
|
|
217
|
-
- resolves the floating Buildchain runtime
|
|
218
|
-
|
|
213
|
+
- resolves the same floating Buildchain runtime and contract lock as the build
|
|
214
|
+
workflow;
|
|
215
|
+
- verifies that the declared promotion authority can read the protected target
|
|
216
|
+
channel before starting the publication build;
|
|
219
217
|
- builds the PDF through the declared pinned LaTeX Docker toolchain or custom
|
|
220
|
-
command
|
|
218
|
+
command;
|
|
221
219
|
- verifies the paper repository;
|
|
222
220
|
- writes the publication manifest, publication passport, optional archive
|
|
223
221
|
registry, and source bundle;
|
|
@@ -228,22 +226,14 @@ The preset:
|
|
|
228
226
|
- creates a `publish-gate/<alpha|release>/.../<version>` source lock for the
|
|
229
227
|
channel commit and requires `promote-buildchain-ref` to verify that lock
|
|
230
228
|
before any publish side effect;
|
|
231
|
-
-
|
|
232
|
-
package through npm Trusted Publishing without rebuilding it;
|
|
229
|
+
- publishes the package through npm Trusted Publishing;
|
|
233
230
|
- writes Buildchain release/passport evidence; and
|
|
234
|
-
- creates or updates the exact-version GitHub Release by default
|
|
235
|
-
every file declared by `publication.primary_artifact` and
|
|
236
|
-
`publication.artifact_paths` alongside the release evidence.
|
|
231
|
+
- creates or updates the exact-version GitHub Release by default.
|
|
237
232
|
|
|
238
233
|
Consumers can opt out of the GitHub Release with `github-release: false`, but
|
|
239
234
|
the default is on so downstream release propagation can observe
|
|
240
235
|
`release.published` without hand-written `gh release` steps.
|
|
241
236
|
|
|
242
|
-
Declared publication artifacts are resolved from the generated publication
|
|
243
|
-
manifest rather than repeated in consumer workflow YAML. Publication fails
|
|
244
|
-
before upload if a declared artifact is missing or if its basename would
|
|
245
|
-
collide with another GitHub Release asset.
|
|
246
|
-
|
|
247
237
|
For npm Trusted Publishing, register the consumer workflow file that calls this
|
|
248
238
|
preset, for example `.github/workflows/paper-release.yml`, against the declared
|
|
249
239
|
package in npm. The trusted publisher is the consumer repository and workflow
|
|
@@ -8,11 +8,11 @@ confidence: high
|
|
|
8
8
|
sensitivity: public
|
|
9
9
|
evidence_grade: B
|
|
10
10
|
review_state: unreviewed
|
|
11
|
-
last_reviewed: 2026-07-
|
|
11
|
+
last_reviewed: 2026-07-14
|
|
12
12
|
ai_provenance:
|
|
13
13
|
model_family: GPT-5
|
|
14
14
|
product: Codex
|
|
15
|
-
generated_at: 2026-07-
|
|
15
|
+
generated_at: 2026-07-14
|
|
16
16
|
limits: Live provider configuration must be re-audited; no credential values are represented.
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -121,15 +121,6 @@ repositories, unknown refs, non-exact source SHAs, and any caller other than
|
|
|
121
121
|
`.github/workflows/buildchain-ref-promotion.yml`. Manual apply and external
|
|
122
122
|
consumer workflows still require their own explicit admission inputs.
|
|
123
123
|
|
|
124
|
-
Before authority verification, the reusable promotion controller runs the same
|
|
125
|
-
release transaction selector in read-only mode. That plan supplies one exact
|
|
126
|
-
publication version and tag to the admission verifier, the publish-gate source
|
|
127
|
-
lock, and the real promotion action. The verifier rejects a capability for a
|
|
128
|
-
different version, and the promotion action rechecks the planned version before
|
|
129
|
-
any publish transaction side effect. Release-candidate fixture versions are
|
|
130
|
-
artifact evidence only; they never name Buildchain's own source-lock or
|
|
131
|
-
publication capability.
|
|
132
|
-
|
|
133
124
|
Evidence publication is a separate authority class and never grants product
|
|
134
125
|
publication.
|
|
135
126
|
|
|
@@ -78,12 +78,6 @@ Every matrix job checks out the exact source SHA planned by Buildchain, invokes
|
|
|
78
78
|
then invokes `shifu gate receipt validate`. Buildchain uploads the original
|
|
79
79
|
receipt and validation result even when the run fails.
|
|
80
80
|
|
|
81
|
-
Before invoking the project-owned command, the workflow adds the runner
|
|
82
|
-
account's `~/.local/bin` directory to `PATH` on Windows, Linux, and macOS. This
|
|
83
|
-
keeps user-scoped tools such as `uv` available to strict Shifu cache profiles
|
|
84
|
-
without assuming an administrator-managed system installation. The consumer or
|
|
85
|
-
runner owner remains responsible for provisioning the declared tools.
|
|
86
|
-
|
|
87
81
|
The fixed `Gate profile / aggregate` job fails closed for missing receipts,
|
|
88
82
|
invalid or stale Shifu validation, dirty or mismatched source SHA, registry or
|
|
89
83
|
plan drift, missing required results, required failures/skips, or gate action
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kungfu-tech/buildchain",
|
|
3
|
-
"version": "2.12.7-alpha.
|
|
3
|
+
"version": "2.12.7-alpha.2",
|
|
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",
|
|
@@ -27,7 +27,6 @@ const DESCRIPTORS = Object.freeze([
|
|
|
27
27
|
[".github/workflows/buildchain-stable-candidate-patrol.yml", "governance-write"],
|
|
28
28
|
[".github/workflows/dev-pr-auto-merge.yml", "governance-write"],
|
|
29
29
|
[".github/workflows/npm-publish.yml", "dry-run-only"],
|
|
30
|
-
[".github/workflows/paper-release-sealed.yml", "product-publication", true, ["npm-publish", "github-release"], "trusted-publishing", "none", "fixed", "caller-bound"],
|
|
31
30
|
[".github/workflows/paper-release.yml", "product-publication", true, ["npm-publish", "github-release"], "trusted-publishing", "none", "fixed", "caller-bound"],
|
|
32
31
|
[".github/workflows/patrol-daily.yml", "governance-write"],
|
|
33
32
|
[".github/workflows/patrol-monthly.yml", "governance-write"],
|
|
@@ -303,7 +303,7 @@ function normalizeEvidence(entries = []) {
|
|
|
303
303
|
function receiptStatus(plan, stages) {
|
|
304
304
|
if (stages.some((stage) => stage.status === "failed")) return "failed";
|
|
305
305
|
if (stages.length > 0 && stages.every((stage) => stage.status === "skipped")) return "skipped";
|
|
306
|
-
if (stages.some((stage) => stage.status === "cancelled" ||
|
|
306
|
+
if (stages.some((stage) => stage.status === "cancelled" || stage.status === "missing")) return "partial";
|
|
307
307
|
const required = new Set(plan.expected.stages.filter((stage) => stage.required).map((stage) => stage.id));
|
|
308
308
|
if (stages.filter((stage) => required.has(stage.id)).every((stage) => stage.status === "passed")) return "passed";
|
|
309
309
|
return "partial";
|
package/packages/core/index.js
CHANGED
|
@@ -153,13 +153,6 @@ export {
|
|
|
153
153
|
verifyPublicationAdmission,
|
|
154
154
|
} from "./publication-authority.js";
|
|
155
155
|
|
|
156
|
-
export {
|
|
157
|
-
PUBLICATION_ARTIFACT_CANDIDATE_CONTRACT,
|
|
158
|
-
createPublicationArtifactCandidate,
|
|
159
|
-
publicationArtifactCandidateDigest,
|
|
160
|
-
resolvePublicationCandidateFile,
|
|
161
|
-
} from "./publication-artifact-candidate.js";
|
|
162
|
-
|
|
163
156
|
export {
|
|
164
157
|
buildchainPublicationAuthorityDescriptors,
|
|
165
158
|
createBuildchainPublicationAuthorityRegistry,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
|
|
3
3
|
import { validateControllerReceipt } from "./controller-evidence.js";
|
|
4
|
-
import { createPublicationArtifactCandidate } from "./publication-artifact-candidate.js";
|
|
5
4
|
import { sha256Json, validateReleaseCandidatePassport } from "./release-candidate.js";
|
|
6
5
|
|
|
7
6
|
export const PUBLICATION_AUTHORITY_REGISTRY_CONTRACT =
|
|
@@ -382,7 +381,6 @@ export function createPublicationArtifactManifestSet({
|
|
|
382
381
|
}
|
|
383
382
|
|
|
384
383
|
function validateGateAggregate(gateAggregate, { admission, passport }) {
|
|
385
|
-
const passportSourceSha = passport.source?.headSha || passport.source?.sha;
|
|
386
384
|
if (gateAggregate?.contract === "buildchain.shifu-gate-aggregate/v1") {
|
|
387
385
|
const { digest, ...payload } = gateAggregate;
|
|
388
386
|
const actualDigest = sha256Json(payload);
|
|
@@ -392,7 +390,7 @@ function validateGateAggregate(gateAggregate, { admission, passport }) {
|
|
|
392
390
|
if (gateAggregate.status !== "pass" || gateAggregate.qualifying !== true) {
|
|
393
391
|
throw new Error("gate aggregate is not qualifying");
|
|
394
392
|
}
|
|
395
|
-
if (![admission.sourceSha,
|
|
393
|
+
if (![admission.sourceSha, passport.source?.headSha].includes(gateAggregate.sourceSha)) {
|
|
396
394
|
throw new Error("gate aggregate source SHA mismatch");
|
|
397
395
|
}
|
|
398
396
|
normalizeDigest(gateAggregate.registry?.digest, "gateAggregate.registry.digest");
|
|
@@ -410,7 +408,7 @@ function validateGateAggregate(gateAggregate, { admission, passport }) {
|
|
|
410
408
|
if (gateAggregate.required !== false) {
|
|
411
409
|
throw new Error("a required Gate policy must supply a qualifying Shifu Gate aggregate");
|
|
412
410
|
}
|
|
413
|
-
if (![admission.sourceSha,
|
|
411
|
+
if (![admission.sourceSha, passport.source?.headSha].includes(gateAggregate.sourceSha)) {
|
|
414
412
|
throw new Error("publication Gate decision source SHA mismatch");
|
|
415
413
|
}
|
|
416
414
|
const normalizedPolicy = {
|
|
@@ -430,43 +428,6 @@ function validatePublicationEvidence(publicationEvidence, admission) {
|
|
|
430
428
|
if (!publicationEvidence || typeof publicationEvidence !== "object" || Array.isArray(publicationEvidence)) {
|
|
431
429
|
throw new Error("independent publication evidence is required");
|
|
432
430
|
}
|
|
433
|
-
if (publicationEvidence.publicationArtifactCandidate) {
|
|
434
|
-
const candidate = createPublicationArtifactCandidate(publicationEvidence.publicationArtifactCandidate);
|
|
435
|
-
const passport = publicationEvidence.publicationArtifactCandidate.passport;
|
|
436
|
-
const controllerReceipt = publicationEvidence.publicationArtifactCandidate.controllerReceipt;
|
|
437
|
-
const controllerReceiptDigest = normalizeDigest(controllerReceipt.digest, "controllerReceipt.digest");
|
|
438
|
-
if (controllerReceiptDigest !== normalizeDigest(admission.controllerReceiptDigest, "admission.controllerReceiptDigest")) {
|
|
439
|
-
throw new Error("controller receipt evidence binding mismatch");
|
|
440
|
-
}
|
|
441
|
-
const contractDigest = normalizeDigest(controllerReceipt.runtime?.contractDigest, "controllerReceipt.runtime.contractDigest");
|
|
442
|
-
if (contractDigest !== normalizeDigest(admission.contractDigest, "admission.contractDigest")) {
|
|
443
|
-
throw new Error("runtime contract evidence binding mismatch");
|
|
444
|
-
}
|
|
445
|
-
const gate = validateGateAggregate(publicationEvidence.gateAggregate, { admission, passport });
|
|
446
|
-
if (gate.gateAggregateDigest !== normalizeDigest(admission.gateAggregateDigest, "admission.gateAggregateDigest")) {
|
|
447
|
-
throw new Error("Gate aggregate evidence binding mismatch");
|
|
448
|
-
}
|
|
449
|
-
if (gate.policyDigest !== normalizeDigest(admission.policyDigest, "admission.policyDigest")) {
|
|
450
|
-
throw new Error("Gate policy evidence binding mismatch");
|
|
451
|
-
}
|
|
452
|
-
if (candidate.candidateDigest !== normalizeDigest(admission.artifactDigest, "admission.artifactDigest")) {
|
|
453
|
-
throw new Error("publication artifact candidate evidence binding mismatch");
|
|
454
|
-
}
|
|
455
|
-
return {
|
|
456
|
-
sourceTreeSha: candidate.sourceTreeSha,
|
|
457
|
-
controllerReceiptDigest,
|
|
458
|
-
contractDigest,
|
|
459
|
-
gateAggregateDigest: gate.gateAggregateDigest,
|
|
460
|
-
policyDigest: gate.policyDigest,
|
|
461
|
-
artifactDigest: candidate.candidateDigest,
|
|
462
|
-
evidenceDigest: publicationAuthorityDigest({
|
|
463
|
-
sourceTreeSha: candidate.sourceTreeSha,
|
|
464
|
-
controllerReceiptDigest,
|
|
465
|
-
gateAggregateDigest: gate.gateAggregateDigest,
|
|
466
|
-
artifactDigest: candidate.candidateDigest,
|
|
467
|
-
}),
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
431
|
const passport = publicationEvidence.releaseCandidatePassport;
|
|
471
432
|
const buildSummary = publicationEvidence.buildSummary;
|
|
472
433
|
const passportValidation = validateReleaseCandidatePassport({
|
|
@@ -16,7 +16,6 @@ export function evaluatePublicationControlPlaneSnapshot({
|
|
|
16
16
|
branch,
|
|
17
17
|
packageName,
|
|
18
18
|
publisherMode = "npm-trusted-publisher",
|
|
19
|
-
requiredStatusCheck = "check",
|
|
20
19
|
snapshot,
|
|
21
20
|
observedAt,
|
|
22
21
|
expiresAt,
|
|
@@ -73,8 +72,7 @@ export function evaluatePublicationControlPlaneSnapshot({
|
|
|
73
72
|
branchPolicy.protected === true &&
|
|
74
73
|
branchPolicy.enforcementLevel === "everyone" &&
|
|
75
74
|
Array.isArray(branchPolicy.requiredStatusChecks) &&
|
|
76
|
-
branchPolicy.
|
|
77
|
-
branchPolicy.requiredStatusChecks.includes(requiredStatusCheck) &&
|
|
75
|
+
branchPolicy.requiredStatusChecks.includes("check") &&
|
|
78
76
|
branchPolicy.requiredCheckPassed === true &&
|
|
79
77
|
branchPolicy.sourceSha === branchPolicy.headSha &&
|
|
80
78
|
branchPolicy.mergedPullRequest === true &&
|
|
@@ -137,7 +137,6 @@ async function main() {
|
|
|
137
137
|
isolation: "github-hosted-single-job",
|
|
138
138
|
});
|
|
139
139
|
const packageJson = JSON.parse(fs.readFileSync(path.join(runtimeRoot, "package.json"), "utf8"));
|
|
140
|
-
const publicationVersion = required("BUILDCHAIN_PUBLICATION_VERSION");
|
|
141
140
|
const issuedAt = new Date();
|
|
142
141
|
const admission = createPublicationAdmission({
|
|
143
142
|
registryDigest: registry.registryDigest,
|
|
@@ -155,7 +154,7 @@ async function main() {
|
|
|
155
154
|
environment: process.env.BUILDCHAIN_PUBLICATION_ENVIRONMENT || "none",
|
|
156
155
|
product: process.env.BUILDCHAIN_PUBLICATION_PRODUCT || "Buildchain",
|
|
157
156
|
target: process.env.BUILDCHAIN_PUBLICATION_TARGET || `npm:${packageJson.name}`,
|
|
158
|
-
version:
|
|
157
|
+
version: process.env.BUILDCHAIN_PUBLICATION_VERSION || packageJson.version,
|
|
159
158
|
channel: required("BUILDCHAIN_PUBLICATION_CHANNEL"),
|
|
160
159
|
artifactDigest: artifactSet.manifestSetDigest,
|
|
161
160
|
nonce: `${required("GITHUB_RUN_ID")}:${required("GITHUB_RUN_ATTEMPT")}:${sourceSha}`,
|
|
@@ -191,7 +191,6 @@ function main() {
|
|
|
191
191
|
const workflowPath = flag("workflow", ".github/workflows/release-candidate-promote.yml");
|
|
192
192
|
const workflowRef = flag("workflow-ref");
|
|
193
193
|
const publisherWorkflowPath = flag("publisher-workflow", workflowPath);
|
|
194
|
-
const requiredStatusCheck = flag("required-status-check", "check");
|
|
195
194
|
const jobId = flag("job", "promote");
|
|
196
195
|
const environment = flag("environment", "none");
|
|
197
196
|
const providerEnvironment = environment === "none" ? "" : environment;
|
|
@@ -281,16 +280,15 @@ function main() {
|
|
|
281
280
|
const checkRuns = githubJson(`repos/${repository}/commits/${sourceSha}/check-runs?per_page=100`, "source check runs");
|
|
282
281
|
const requiredStatusCheckPolicy = branchState.protection?.required_status_checks || {};
|
|
283
282
|
const requiredStatusChecks = requiredStatusCheckPolicy.contexts || [];
|
|
284
|
-
const requiredCheckSource = (requiredStatusCheckPolicy.checks || []).find((entry) => entry.context ===
|
|
283
|
+
const requiredCheckSource = (requiredStatusCheckPolicy.checks || []).find((entry) => entry.context === "check");
|
|
285
284
|
branchPolicy = {
|
|
286
285
|
ref: branch,
|
|
287
286
|
policyMode: "provider-enforced-transaction",
|
|
288
287
|
protected: branchState.protected === true,
|
|
289
288
|
enforcementLevel: branchState.protection?.required_status_checks?.enforcement_level || "",
|
|
290
289
|
requiredStatusChecks,
|
|
291
|
-
requiredStatusCheck,
|
|
292
290
|
requiredCheckPassed: (checkRuns.check_runs || []).some((entry) =>
|
|
293
|
-
entry.name ===
|
|
291
|
+
entry.name === "check" &&
|
|
294
292
|
entry.conclusion === "success" &&
|
|
295
293
|
(!requiredCheckSource?.app_id || entry.app?.id === requiredCheckSource.app_id)
|
|
296
294
|
),
|
|
@@ -352,7 +350,6 @@ function main() {
|
|
|
352
350
|
branch,
|
|
353
351
|
packageName,
|
|
354
352
|
publisherMode,
|
|
355
|
-
requiredStatusCheck,
|
|
356
353
|
observedAt: observedAt.toISOString(),
|
|
357
354
|
expiresAt: expiresAt.toISOString(),
|
|
358
355
|
snapshot: {
|
|
@@ -840,9 +840,6 @@ for (const requiredSnippet of [
|
|
|
840
840
|
"publish-source-ref: ${{ steps.publish-gate.outputs.ref }}",
|
|
841
841
|
"publish-source-sha: ${{ steps.publish-gate.outputs.sha }}",
|
|
842
842
|
"publish-source-locked: ${{ steps.publish-gate.outputs.locked }}",
|
|
843
|
-
"expected-publication-version: ${{ needs.publication-plan.outputs.version }}",
|
|
844
|
-
"publication-version: ${{ needs.publication-plan.outputs.version }}",
|
|
845
|
-
"name: Plan exact publication version",
|
|
846
843
|
"DRY_RUN: ${{ inputs.dry-run }}",
|
|
847
844
|
"if (dryRun) {",
|
|
848
845
|
"Enforce Buildchain stable release canary gate",
|
|
@@ -202,8 +202,6 @@ export async function classifyWorkflowFriction({
|
|
|
202
202
|
buildWorkflowName = DEFAULT_BUILD_WORKFLOW_NAME,
|
|
203
203
|
releaseCandidateOutcome = env("BUILDCHAIN_RC_RESOLVE_OUTCOME"),
|
|
204
204
|
releaseCandidateDiagnosis = env("BUILDCHAIN_RC_DIAGNOSIS"),
|
|
205
|
-
promotionOutcome = env("BUILDCHAIN_PROMOTION_OUTCOME"),
|
|
206
|
-
promotionDiagnosis = env("BUILDCHAIN_PROMOTION_DIAGNOSIS"),
|
|
207
205
|
runUrl = env("BUILDCHAIN_WORKFLOW_RUN_URL"),
|
|
208
206
|
outputDir = ".buildchain/workflow-friction",
|
|
209
207
|
fetchImpl = globalThis.fetch,
|
|
@@ -258,23 +256,14 @@ export async function classifyWorkflowFriction({
|
|
|
258
256
|
if (releaseCandidateOutcome === "failure") {
|
|
259
257
|
diagnosisParts.push("Promotion reached the post-Verify workflow before required PR-stage RC evidence could be resolved.");
|
|
260
258
|
}
|
|
261
|
-
if (
|
|
259
|
+
if (releaseCandidateDiagnosis) {
|
|
262
260
|
diagnosisParts.push(releaseCandidateDiagnosis);
|
|
263
261
|
}
|
|
264
|
-
if (promotionOutcome === "failure") {
|
|
265
|
-
diagnosisParts.push(
|
|
266
|
-
promotionDiagnosis
|
|
267
|
-
? `Promotion failed: ${promotionDiagnosis}`
|
|
268
|
-
: "Promotion failed after PR-stage release-candidate evidence resolved successfully.",
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
262
|
diagnosisParts.push(...workflowRunDiagnostics);
|
|
272
263
|
const diagnosis = diagnosisParts.join(" ") || "Buildchain ref promotion failed after Verify succeeded; inspect the classified evidence and keep the fix in Buildchain.";
|
|
273
264
|
const nextAction = frictionClass === "late-fail-fast"
|
|
274
265
|
? "Move the missing/stale RC evidence check earlier or make the promotion workflow consume the exact PR-stage RC passport before any publish side effect."
|
|
275
|
-
:
|
|
276
|
-
? "Deduplicate the PR/build path or tighten Buildchain workflow gates so the next channel promotion reaches publish exactly once."
|
|
277
|
-
: "Fix the concrete promotion failure above, then rerun through the protected channel workflow; do not treat successful RC resolution as the failure diagnosis.";
|
|
266
|
+
: "Deduplicate the PR/build path or tighten Buildchain workflow gates so the next channel promotion reaches publish exactly once.";
|
|
278
267
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
279
268
|
const bodyFile = path.join(outputDir, "issue-body.md");
|
|
280
269
|
const body = buildWorkflowFrictionBody({
|