@kungfu-tech/buildchain 2.12.7-alpha.22 → 2.12.7-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/actions/promote-buildchain-ref/README.md +1 -5
  2. package/dist/site/buildchain-contract.json +22 -47
  3. package/dist/site/buildchain-site.json +14 -14
  4. package/dist/site/capability-registry.json +1 -1
  5. package/dist/site/controller-registry.json +3 -23
  6. package/dist/site/kfd-claims.json +8 -59
  7. package/dist/site/kfd-upstream-aggregate.json +1 -1
  8. package/dist/site/manual-registry.json +2 -2
  9. package/dist/site/node-api-registry.json +6 -6
  10. package/dist/site/page-registry.json +8 -8
  11. package/dist/site/public-surface-audit.json +8 -68
  12. package/dist/site/publication-authority-registry.json +1 -25
  13. package/dist/site/publication-registry.json +4 -4
  14. package/dist/site/site-manifest.json +6 -6
  15. package/dist/site/workflow-registry.json +5 -68
  16. package/docs/publication-artifacts.md +19 -22
  17. package/docs/publication-authority.md +7 -10
  18. package/docs/release-candidate.md +0 -19
  19. package/package.json +1 -1
  20. package/packages/core/buildchain-publication-authority.js +0 -1
  21. package/packages/core/controller-evidence.js +1 -1
  22. package/packages/core/index.js +0 -7
  23. package/packages/core/publication-authority.js +2 -41
  24. package/packages/core/publication-control-plane-audit.js +1 -3
  25. package/scripts/assemble-self-publication-admission.mjs +8 -17
  26. package/scripts/audit-publication-control-plane.mjs +2 -5
  27. package/scripts/locked-source-checkout.mjs +13 -50
  28. package/packages/core/publication-artifact-candidate.js +0 -128
  29. package/scripts/assemble-publication-artifact-admission.mjs +0 -190
  30. package/scripts/publication-artifact-candidate.mjs +0 -122
@@ -215,19 +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
- "auto-no-gate",
222
219
  "buildchain-ref",
223
220
  "buildchain-repository",
224
221
  "control-plane-audit-json",
225
222
  "dry-run",
226
- "evidence-controller-artifact",
227
223
  "evidence-manifest-pattern",
228
224
  "evidence-passport-artifact",
229
225
  "evidence-payload-pattern",
230
- "evidence-publication-artifact",
231
226
  "evidence-repository",
232
227
  "evidence-run-id",
233
228
  "evidence-summary-artifact",
@@ -238,13 +233,12 @@
238
233
  "publication-target",
239
234
  "publication-version",
240
235
  "publisher-workflow-path",
241
- "required-status-check",
242
236
  "runner-provenance-json",
243
237
  "source-sha",
244
238
  "target-ref",
245
239
  "used-nonces-json"
246
240
  ],
247
- "inputCount": 29,
241
+ "inputCount": 23,
248
242
  "secrets": [],
249
243
  "secretCount": 0,
250
244
  "outputs": [
@@ -1031,54 +1025,6 @@
1031
1025
  "capabilityGroup": "api-cli-reference",
1032
1026
  "status": "active"
1033
1027
  },
1034
- {
1035
- "id": "paper-release-sealed",
1036
- "path": ".github/workflows/paper-release-sealed.yml",
1037
- "reusable": true,
1038
- "inputs": [
1039
- "artifact-name",
1040
- "artifact-paths",
1041
- "artifact-retention-days",
1042
- "branch-protection-bypass-apps",
1043
- "branch-protection-bypass-teams",
1044
- "branch-protection-bypass-users",
1045
- "buildchain-contract-lock-path",
1046
- "buildchain-ref",
1047
- "buildchain-repository",
1048
- "dry-run",
1049
- "github-release",
1050
- "github-release-notes",
1051
- "github-release-title",
1052
- "package-name",
1053
- "publish-dist-tag",
1054
- "publisher-workflow-path",
1055
- "release-passport-impact-json",
1056
- "release-passport-output-dir",
1057
- "release-passport-product-name",
1058
- "required-status-check",
1059
- "target-ref",
1060
- "target-sha",
1061
- "toolchain-type",
1062
- "verify-command",
1063
- "working-directory"
1064
- ],
1065
- "inputCount": 25,
1066
- "secrets": [
1067
- "BUILDCHAIN_PROMOTION_TOKEN"
1068
- ],
1069
- "secretCount": 1,
1070
- "outputs": [
1071
- "github-release-url",
1072
- "package-name",
1073
- "package-version",
1074
- "public-release-tag",
1075
- "release-passport-path"
1076
- ],
1077
- "outputCount": 5,
1078
- "surface": "repository-workflow",
1079
- "capabilityGroup": "api-cli-reference",
1080
- "status": "active"
1081
- },
1082
1028
  {
1083
1029
  "id": "paper-release",
1084
1030
  "path": ".github/workflows/paper-release.yml",
@@ -1248,11 +1194,7 @@
1248
1194
  "buildchain-ref",
1249
1195
  "buildchain-repository",
1250
1196
  "node-version",
1251
- "package-name",
1252
- "prepare-paper-package",
1253
- "publish-dist-tag",
1254
1197
  "setup-node",
1255
- "target-ref",
1256
1198
  "toolchain-command",
1257
1199
  "toolchain-digest",
1258
1200
  "toolchain-image",
@@ -1260,7 +1202,7 @@
1260
1202
  "verify-command",
1261
1203
  "working-directory"
1262
1204
  ],
1263
- "inputCount": 21,
1205
+ "inputCount": 17,
1264
1206
  "secrets": [],
1265
1207
  "secretCount": 0,
1266
1208
  "outputs": [
@@ -1271,17 +1213,13 @@
1271
1213
  "controller-receipt-digest",
1272
1214
  "controller-receipt-json",
1273
1215
  "controller-receipt-status",
1274
- "package-name",
1275
- "package-version",
1276
1216
  "publication-artifact-name",
1277
1217
  "publication-manifest-json",
1278
1218
  "publication-manifest-path",
1279
1219
  "publication-passport-path",
1280
- "publication-registry-path",
1281
- "publish-dist-tag",
1282
- "runtime-sha"
1220
+ "publication-registry-path"
1283
1221
  ],
1284
- "outputCount": 16,
1222
+ "outputCount": 12,
1285
1223
  "surface": "repository-workflow",
1286
1224
  "capabilityGroup": "reusable-build",
1287
1225
  "status": "active"
@@ -1310,7 +1248,6 @@
1310
1248
  "package-manager",
1311
1249
  "publication-admission-json",
1312
1250
  "publication-auto-admission",
1313
- "publication-auto-no-gate",
1314
1251
  "publication-control-plane-audit-json",
1315
1252
  "publication-expected-json",
1316
1253
  "publication-gate-aggregate-json",
@@ -1348,7 +1285,7 @@
1348
1285
  "target-sha",
1349
1286
  "trusted-publishing"
1350
1287
  ],
1351
- "inputCount": 56,
1288
+ "inputCount": 55,
1352
1289
  "secrets": [
1353
1290
  "BUILDCHAIN_ISSUE_APP_ID",
1354
1291
  "BUILDCHAIN_ISSUE_APP_PRIVATE_KEY",
@@ -182,42 +182,40 @@ on:
182
182
 
183
183
  jobs:
184
184
  paper-release:
185
- uses: kungfu-systems/buildchain/.github/workflows/paper-release-sealed.yml@v2
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
- publisher-workflow-path: .github/workflows/paper-release.yml
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 sealed preset does not use a long-lived token for npm publication. It may
204
- accept an optional `BUILDCHAIN_PROMOTION_TOKEN` only for machine-generated
205
- version-state updates on protected channel branches; npm publication remains
206
- bound to GitHub OIDC trusted publishing. The preset builds and packages the
207
- paper in a read-only job, then a credential-free authority job downloads that
208
- exact candidate, audits the external control plane, and seals a capability over
209
- the source tree, Buildchain runtime, controller receipt, PDF, and npm package
210
- bytes. Only the final job receives write and OIDC permissions; it downloads the
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 once and binds the exact SHA into the
218
- publication candidate and authority capability;
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 in a read-only job;
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,8 +226,7 @@ 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
- - verifies the complete candidate again after authority and publishes the
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
231
  - creates or updates the exact-version GitHub Release by default, uploading
235
232
  every file declared by `publication.primary_artifact` and
@@ -109,20 +109,17 @@ artifacts. The denial explicitly records that npm Trusted Publishing and OIDC
109
109
  were not evaluated, so downstream diagnostics cannot misclassify an admission
110
110
  assembly failure as an npm authentication failure.
111
111
 
112
- An explicitly opted-in managed `workflow_run` promotion lane may assemble those
113
- inputs from evidence owned by its caller repository. It downloads the exact prior RC passport,
112
+ Buildchain's own `workflow_run` promotion lane may assemble those inputs only
113
+ for `kungfu-systems/buildchain`. It downloads the exact prior RC passport,
114
114
  summary, referenced controller receipt, manifests, and product payloads; proves
115
115
  the admitted channel commit has the same Git tree as the RC; performs the live
116
116
  read-only control-plane audit; records the GitHub-hosted job as ephemeral runner
117
- provenance; and consumes either a caller-supplied Gate aggregate or an explicit
118
- caller no-Gate decision. The
117
+ provenance; and creates an explicit Buildchain-owned no-Gate decision. The
119
118
  independent verifier then recomputes every receipt and payload digest exactly as
120
- it does for externally supplied admission. Automatic assembly keeps Buildchain
121
- as the canonical authority repository, requires evidence to belong to the
122
- caller, binds a repository-local publisher workflow, and rejects unknown refs,
123
- non-exact source SHAs, package/target mismatches, or an undeclared Gate policy.
124
- Manual apply and consumers that do not opt in still require their own explicit
125
- admission inputs.
119
+ it does for externally supplied admission. The self-assembly mode rejects other
120
+ repositories, unknown refs, non-exact source SHAs, and any caller other than
121
+ `.github/workflows/buildchain-ref-promotion.yml`. Manual apply and external
122
+ consumer workflows still require their own explicit admission inputs.
126
123
 
127
124
  Before authority verification, the reusable promotion controller runs the same
128
125
  release transaction selector in read-only mode. That plan supplies one exact
@@ -116,22 +116,3 @@ KFD-1 source/artifact contract surfaces, audits KFD-2 public release claims, and
116
116
  compares KFD-3 declared shipped public surfaces with artifact-exposed public
117
117
  surfaces. The release passport records the results under `kfd-1`, `kfd-2`, and
118
118
  the KFD-provided `kfd-3` section.
119
-
120
- Managed consumers may also ask the promotion wrapper to assemble sealed
121
- publication evidence from the exact release candidate instead of producing
122
- short-lived admission JSON in repository-specific workflow code:
123
-
124
- ```yaml
125
- publication-auto-admission: true
126
- publication-auto-no-gate: true
127
- publication-publisher-workflow-path: .github/workflows/buildchain-ref-promotion.yml
128
- publication-product: Example Product
129
- publication-target: npm:@example/product
130
- publication-package-name: "@example/product"
131
- ```
132
-
133
- `publication-auto-no-gate` is an explicit consumer decision, not a default. A
134
- consumer with a Shifu Gate registry supplies `publication-gate-aggregate-json`
135
- instead. Buildchain still requires caller-owned RC evidence, an exact authority
136
- runtime and source SHA, a repository-local publisher workflow, matching npm
137
- target/package identity, and a qualifying control-plane audit.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "2.12.7-alpha.22",
3
+ "version": "2.12.7-alpha.4",
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" || (stage.required && stage.status === "missing"))) return "partial";
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";
@@ -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, passportSourceSha].includes(gateAggregate.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, passportSourceSha].includes(gateAggregate.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.requiredStatusCheck === requiredStatusCheck &&
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 &&
@@ -115,22 +115,13 @@ async function main() {
115
115
  manifests,
116
116
  payloads: manifests.map((manifest) => payloadFor(manifest, path.join(evidenceRoot, "payloads"))),
117
117
  });
118
- const suppliedGateAggregate = String(process.env.BUILDCHAIN_GATE_AGGREGATE_JSON || "").trim();
119
- let gateAggregate;
120
- if (suppliedGateAggregate) {
121
- gateAggregate = JSON.parse(suppliedGateAggregate);
122
- } else {
123
- if (process.env.BUILDCHAIN_ALLOW_NO_GATE !== "true") {
124
- throw new Error("managed release-candidate admission requires a Gate aggregate or explicit no-Gate decision");
125
- }
126
- gateAggregate = createPublicationGateDecision({
127
- sourceSha,
128
- profile: process.env.BUILDCHAIN_GATE_PROFILE || "managed-release-candidate-no-gate",
129
- required: false,
130
- rationale: process.env.BUILDCHAIN_GATE_RATIONALE || "The consumer explicitly declared no Shifu Gate registry for this publication transaction.",
131
- policy: { scope: "managed-release-candidate", repository },
132
- });
133
- }
118
+ const gateAggregate = createPublicationGateDecision({
119
+ sourceSha,
120
+ profile: process.env.BUILDCHAIN_GATE_PROFILE || "buildchain-self-publication",
121
+ required: false,
122
+ rationale: process.env.BUILDCHAIN_GATE_RATIONALE || "Buildchain self-publication has no consumer-owned Shifu Gate registry.",
123
+ policy: { scope: "buildchain-self-publication", repository },
124
+ });
134
125
  const runnerProvenance = createRunnerProvenance({
135
126
  runnerClass: "ephemeral",
136
127
  os: required("RUNNER_OS"),
@@ -187,6 +178,6 @@ async function main() {
187
178
  }
188
179
 
189
180
  main().catch((error) => {
190
- console.error(`assemble release-candidate admission: ${error.message}`);
181
+ console.error(`assemble self publication admission: ${error.message}`);
191
182
  process.exitCode = 1;
192
183
  });
@@ -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 === requiredStatusCheck);
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 === requiredStatusCheck &&
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: {
@@ -6,7 +6,6 @@ import path from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
 
8
8
  export const LOCKED_SOURCE_CHECKOUT_CONTRACT = "kungfu-buildchain-locked-source-checkout-cache";
9
- export const ISOLATED_GIT_GLOBAL_CONFIG = process.platform === "win32" ? "NUL" : "/dev/null";
10
9
 
11
10
  const GIT_SHA_PATTERN = /^[0-9a-f]{40}$/i;
12
11
 
@@ -134,24 +133,6 @@ function githubAuthEnv(token = "") {
134
133
  };
135
134
  }
136
135
 
137
- function isolatedGitFetchEnv(env = {}, targetPath) {
138
- const configuredCount = Number.parseInt(env.GIT_CONFIG_COUNT || "0", 10);
139
- const safeDirectoryIndex = Number.isInteger(configuredCount) && configuredCount >= 0
140
- ? configuredCount
141
- : 0;
142
- return {
143
- ...env,
144
- // Runner-global URL rewrites are shared mutable state. A concurrent job
145
- // may point the same repository URL at a different single-SHA bundle, so
146
- // network fetches must not consult the account-level Git config.
147
- GIT_CONFIG_GLOBAL: ISOLATED_GIT_GLOBAL_CONFIG,
148
- GIT_CONFIG_NOSYSTEM: "1",
149
- GIT_CONFIG_COUNT: String(safeDirectoryIndex + 1),
150
- [`GIT_CONFIG_KEY_${safeDirectoryIndex}`]: "safe.directory",
151
- [`GIT_CONFIG_VALUE_${safeDirectoryIndex}`]: path.resolve(targetPath),
152
- };
153
- }
154
-
155
136
  function markSafeDirectory(targetPath, timeoutMs) {
156
137
  try {
157
138
  git(["config", "--global", "--add", "safe.directory", path.resolve(targetPath)], {
@@ -222,32 +203,9 @@ export function fetchSourceCommit({
222
203
  sourceTreeSha = "",
223
204
  timeoutMs,
224
205
  env = {},
225
- allowFullFetchRetry = false,
226
206
  runGit = git,
227
207
  containsCommit = hasCommit,
228
208
  }) {
229
- const fetchEnv = isolatedGitFetchEnv(env, targetPath);
230
- const fetch = (refspec) => {
231
- const options = { cwd: targetPath, timeoutMs, env: fetchEnv };
232
- try {
233
- runGit(["fetch", "--no-tags", "--depth=1", remoteName, refspec], options);
234
- return "shallow";
235
- } catch (error) {
236
- if (
237
- !allowFullFetchRetry
238
- || !/dumb http transport does not support shallow capabilities/i.test(
239
- String(error?.message || error || ""),
240
- )
241
- ) {
242
- throw error;
243
- }
244
- // Dumb HTTP mirrors are intentionally simple static cache endpoints.
245
- // Retry only that explicit capability mismatch without --depth; all
246
- // network fallbacks remain shallow and bounded by their own policy.
247
- runGit(["fetch", "--no-tags", remoteName, refspec], options);
248
- return "full";
249
- }
250
- };
251
209
  try {
252
210
  runGit(["remote", "remove", remoteName], { cwd: targetPath, timeoutMs, stdio: "ignore" });
253
211
  } catch {
@@ -261,9 +219,13 @@ export function fetchSourceCommit({
261
219
 
262
220
  if (fetchRef) {
263
221
  try {
264
- const fetchMode = fetch(`+${fetchRef}:refs/buildchain/source-ref`);
222
+ runGit(["fetch", "--no-tags", "--depth=1", remoteName, `+${fetchRef}:refs/buildchain/source-ref`], {
223
+ cwd: targetPath,
224
+ timeoutMs,
225
+ env,
226
+ });
265
227
  if (containsCommit(targetPath, sha, timeoutMs)) {
266
- return { selector: "ref", checkoutSha: sha, fetchMode };
228
+ return { selector: "ref", checkoutSha: sha };
267
229
  }
268
230
  if (/^refs\/pull\/\d+\/merge$/.test(fetchRef) && sourceTreeSha) {
269
231
  const fetchedSha = runGit(["rev-parse", "refs/buildchain/source-ref^{commit}"], {
@@ -275,7 +237,7 @@ export function fetchSourceCommit({
275
237
  timeoutMs,
276
238
  });
277
239
  if (fetchedTree === sourceTreeSha) {
278
- return { selector: "ref-tree", checkoutSha: fetchedSha, fetchMode };
240
+ return { selector: "ref-tree", checkoutSha: fetchedSha };
279
241
  }
280
242
  }
281
243
  } catch (error) {
@@ -287,11 +249,15 @@ export function fetchSourceCommit({
287
249
  }
288
250
  }
289
251
 
290
- const fetchMode = fetch(`+${sha}:refs/buildchain/source`);
252
+ runGit(["fetch", "--no-tags", "--depth=1", remoteName, `+${sha}:refs/buildchain/source`], {
253
+ cwd: targetPath,
254
+ timeoutMs,
255
+ env,
256
+ });
291
257
  if (!containsCommit(targetPath, sha, timeoutMs)) {
292
258
  throw new Error(`fetched ${fetchRef || sha}, but ${sha} is not available`);
293
259
  }
294
- return { selector: "sha", checkoutSha: sha, fetchMode };
260
+ return { selector: "sha", checkoutSha: sha };
295
261
  }
296
262
 
297
263
  export function runBoundedFetch({ attempts = 1, fetch, onAttempt = () => {}, onRetry = () => {}, shouldRetry = () => true }) {
@@ -447,9 +413,7 @@ export function lockedSourceCheckout({
447
413
  fetchRef,
448
414
  sourceTreeSha: treeSha,
449
415
  timeoutMs,
450
- allowFullFetchRetry: true,
451
416
  });
452
- evidence.cache.fetchMode = fetchResult.fetchMode;
453
417
  checkoutSha = fetchResult.checkoutSha || sha;
454
418
  checkoutFetchedCommit(targetPath, checkoutSha, timeoutMs);
455
419
  } else {
@@ -494,7 +458,6 @@ export function lockedSourceCheckout({
494
458
  shouldRetry: retryableGitFetchError,
495
459
  });
496
460
  evidence.cache.githubFetchAttempts = fetchResult.attempts;
497
- evidence.cache.fetchMode = fetchResult.value.fetchMode;
498
461
  checkoutSha = fetchResult.value.checkoutSha || sha;
499
462
  } catch (error) {
500
463
  evidence.durationMs = Date.now() - startedAt;