@kungfu-tech/buildchain 2.14.18-alpha.4 → 2.14.18-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/promote-buildchain-ref/README.md +18 -10
- package/dist/site/buildchain-contract.json +9 -9
- package/dist/site/buildchain-site.json +12 -12
- package/dist/site/kfd-claims.json +4 -3
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +2 -2
- package/dist/site/page-registry.json +6 -6
- package/dist/site/public-surface-audit.json +4 -3
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +6 -6
- package/dist/site/workflow-registry.json +2 -1
- package/docs/github-governance-authority.md +8 -0
- package/docs/publish-transaction.md +15 -0
- package/package.json +1 -1
|
@@ -115,6 +115,14 @@ allowance only lets the named automation identity apply generated version-state
|
|
|
115
115
|
or channel bookkeeping without a second human review after the reviewed channel
|
|
116
116
|
PR has already merged.
|
|
117
117
|
|
|
118
|
+
GitHub may return either `403` or a deliberately opaque `404` when a
|
|
119
|
+
non-administrator token reads the full branch-protection endpoint. In that
|
|
120
|
+
case, promotion reads the provider's branch summary and accepts only an
|
|
121
|
+
already-protected branch that enforces the exact required check for everyone.
|
|
122
|
+
It does not interpret the opaque response as missing protection or try to
|
|
123
|
+
rewrite policy with a developer token. The independent publication-authority
|
|
124
|
+
audit remains responsible for the complete read-only governance proof.
|
|
125
|
+
|
|
118
126
|
## Publish Transactions
|
|
119
127
|
|
|
120
128
|
Promotion can also own external publish side effects. Enable this only from a
|
|
@@ -405,16 +413,16 @@ governance semantics:
|
|
|
405
413
|
with either the `verification-command` input or `buildchain.toml`
|
|
406
414
|
`lifecycle.verify` before any tags or channel refs move.
|
|
407
415
|
|
|
408
|
-
The promotion workflow
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
416
|
+
The reusable promotion workflow keeps governance reads, generated status checks,
|
|
417
|
+
and generated ref updates on the run-scoped `github.token`. When branch
|
|
418
|
+
protection rejects generated bookkeeping, it supplies `BUILDCHAIN_PROMOTION_TOKEN`
|
|
419
|
+
only through `generated-pull-request-token` so the same-repository recovery PR can
|
|
420
|
+
be listed or created without broadening the governance client. Protected branch
|
|
421
|
+
review and check rules guard human channel merges, while the reusable build trust
|
|
422
|
+
gate checks the source-lock channel HEAD and merged same-repository PR lineage
|
|
423
|
+
before heavy build runners start. This action still independently rechecks PR
|
|
424
|
+
lineage, alpha/release tree equivalence, and generated version-state verification
|
|
425
|
+
before moving channel refs and tags.
|
|
418
426
|
The reusable `release-candidate-promote.yml` wrapper defaults
|
|
419
427
|
`branch-protection-bypass-apps` to `github-actions`, so flow-internal promotion
|
|
420
428
|
can complete generated `dev`/`alpha`/`release` bookkeeping while ordinary human
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"product": {
|
|
5
5
|
"name": "Buildchain",
|
|
6
6
|
"package": "@kungfu-tech/buildchain",
|
|
7
|
-
"version": "2.14.18-alpha.
|
|
7
|
+
"version": "2.14.18-alpha.6",
|
|
8
8
|
"repository": "https://github.com/kungfu-systems/buildchain"
|
|
9
9
|
},
|
|
10
10
|
"majorLine": "v2",
|
|
@@ -212,7 +212,7 @@
|
|
|
212
212
|
"promotion reuses PR-stage release-candidate artifacts and does not run the heavy native build matrix"
|
|
213
213
|
],
|
|
214
214
|
"breakingDigest": "sha256:aa30f22e3af0a89841310bdbdc900844dd95a66974db173fa140a71bbd7e82c0",
|
|
215
|
-
"auditDigest": "sha256:
|
|
215
|
+
"auditDigest": "sha256:dd9c3179fd7ccd0736396f4924c297bf7ce3452ea6bb9c423d32f15455761c9e"
|
|
216
216
|
},
|
|
217
217
|
{
|
|
218
218
|
"contractVersion": 1,
|
|
@@ -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:063dfe24e1ccdd95b4ffbf89a154aa71197c8bd1cb98b4705d8663917c026366"
|
|
260
260
|
},
|
|
261
261
|
{
|
|
262
262
|
"contractVersion": 1,
|
|
@@ -327,7 +327,7 @@
|
|
|
327
327
|
"sha256:a59f0910e6df842e7699139472e5dd69ac2fdd7f7213bf2cb346d1d622556874"
|
|
328
328
|
],
|
|
329
329
|
"breakingDigest": "sha256:6147c0a8d5c36bfaa6021871574e1fc28192a3f1b8cfdae4d24ef3059ac1ebda",
|
|
330
|
-
"auditDigest": "sha256:
|
|
330
|
+
"auditDigest": "sha256:c23298988d29d6dbf99c65fd7d5567d704f012cc7a061c46a848c26814cab4b9"
|
|
331
331
|
},
|
|
332
332
|
{
|
|
333
333
|
"contractVersion": 1,
|
|
@@ -641,7 +641,7 @@
|
|
|
641
641
|
"manual entries carry source file digests so downstream sites and agents can detect stale hand-written documentation"
|
|
642
642
|
],
|
|
643
643
|
"breakingDigest": "sha256:7d0d2819e3a3e72989d9c57b5efe9d0bc0a79bc0f2c82a0c7b9d6c5a211a91f2",
|
|
644
|
-
"auditDigest": "sha256:
|
|
644
|
+
"auditDigest": "sha256:29b45afe77400b5b38872574cdf7ccfcf8abc93b7f78ad32d994a6636a4f9f68"
|
|
645
645
|
},
|
|
646
646
|
{
|
|
647
647
|
"contractVersion": 1,
|
|
@@ -2018,7 +2018,7 @@
|
|
|
2018
2018
|
"missing receipts are non-qualifying and must not be represented as a successful controller run"
|
|
2019
2019
|
],
|
|
2020
2020
|
"breakingDigest": "sha256:f14825324a16b51c2e9ed708ebe64e1932e05b6d5e0866f83aea8439decb4a27",
|
|
2021
|
-
"auditDigest": "sha256:
|
|
2021
|
+
"auditDigest": "sha256:063dfe24e1ccdd95b4ffbf89a154aa71197c8bd1cb98b4705d8663917c026366"
|
|
2022
2022
|
},
|
|
2023
2023
|
{
|
|
2024
2024
|
"contractVersion": 1,
|
|
@@ -2428,7 +2428,7 @@
|
|
|
2428
2428
|
"missing receipts are non-qualifying and must not be represented as a successful controller run"
|
|
2429
2429
|
],
|
|
2430
2430
|
"breakingDigest": "sha256:0eb318df455ef9cb737a7c2515a2411b685d34ed0bde7b5f5b173a7a42513114",
|
|
2431
|
-
"auditDigest": "sha256:
|
|
2431
|
+
"auditDigest": "sha256:fd939f9dcce745f3e1b8063b68715460cb8e1af6d2b813a96b37a741740122b9"
|
|
2432
2432
|
},
|
|
2433
2433
|
{
|
|
2434
2434
|
"contractVersion": 1,
|
|
@@ -2928,7 +2928,7 @@
|
|
|
2928
2928
|
"missing receipts are non-qualifying and must not be represented as a successful controller run"
|
|
2929
2929
|
],
|
|
2930
2930
|
"breakingDigest": "sha256:015d8de793adbd4c539416be7d7512e18cc92097e629b0203fa06d2c183e98bd",
|
|
2931
|
-
"auditDigest": "sha256:
|
|
2931
|
+
"auditDigest": "sha256:dd9c3179fd7ccd0736396f4924c297bf7ce3452ea6bb9c423d32f15455761c9e"
|
|
2932
2932
|
},
|
|
2933
2933
|
{
|
|
2934
2934
|
"contractVersion": 1,
|
|
@@ -3126,5 +3126,5 @@
|
|
|
3126
3126
|
}
|
|
3127
3127
|
],
|
|
3128
3128
|
"compatibilityDigest": "sha256:df13c3b8066068925ce847b31002201d533034d10d342542422db3a665c10475",
|
|
3129
|
-
"contractDigest": "sha256:
|
|
3129
|
+
"contractDigest": "sha256:b149b81946f402a29d00d3e20495a5a5beaf53b1662543688ae801655cdd5bdf"
|
|
3130
3130
|
}
|
|
@@ -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-24T13:47:59.986Z",
|
|
5
|
+
"publishedAt": "2026-07-24T13:47:59.986Z",
|
|
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": "f13e0810af995f59dd7e64752e0243454df80c7b",
|
|
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.18-alpha.
|
|
40
|
+
"version": "2.14.18-alpha.6",
|
|
41
41
|
"versionSource": "package.json#version"
|
|
42
42
|
},
|
|
43
43
|
"source": {
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
],
|
|
207
207
|
"maturity": "stable",
|
|
208
208
|
"sourcePath": "actions/promote-buildchain-ref/README.md",
|
|
209
|
-
"digest": "sha256:
|
|
209
|
+
"digest": "sha256:21d5ee78b10754a16fa71134f37c5e2442cc3395524dcbfabccc0a9cf94edf14",
|
|
210
210
|
"headings": [
|
|
211
211
|
{
|
|
212
212
|
"level": 1,
|
|
@@ -224,7 +224,7 @@
|
|
|
224
224
|
"anchor": "publish-transactions"
|
|
225
225
|
}
|
|
226
226
|
],
|
|
227
|
-
"markdown": "# promote-buildchain-ref\n\nInternal buildchain action for promoting verified buildchain release-line and\ncompatibility refs from buildchain release channels:\n\n- `alpha/v2/v2.0` creates or reuses the next exact prerelease tag such as\n `v2.0.1-alpha.0`, writes that version into package version state, points the\n alpha and dev channel branches at the version commit, then promotes\n `v2.0-alpha` and, when this is the highest published alpha minor, `v2-alpha`;\n- `release/v2/v2.0` creates or reuses the next exact release tag such as\n `v2.0.0`, writes that version into package version state, points the release\n channel branch and release tags at the release commit, then prepares a second\n source commit for the next exact prerelease tag such as `v2.0.1-alpha.0` and\n points the alpha/dev channel branches plus `v2.0-alpha` at that prerelease\n commit, and moves `v2-alpha` only if no higher v2 minor has published an alpha;\n- `publish-gate/major` accepts a reviewed PR from a production release line such\n as `release/v2/v2.0`, writes the next major production version such as\n `v3.0.0`, points `publish-gate/major`, `release/v3/v3.0`, `v3.0`, and `v3`\n at that release commit, then prepares `v3.0.1-alpha.0` for\n `alpha/v3/v3.0`, `dev/v3/v3.0`, `v3.0-alpha`, and `v3-alpha`. The older `major-gate`\n branch name is a compatibility alias only.\n\nThe release branch name defines the minor line. For example,\n`release/v2/v2.1` creates `v2.1.N`, promotes `v2.1`, and promotes `v2` only\nwhen the next minor tag such as `v2.2` does not already exist.\n\nThe action updates version state in `lerna.json`, root `package.json`, and\nworkspace package manifests discovered from package manager metadata\n(`package.json` workspaces, `lerna.json` packages, or `pnpm-workspace.yaml`).\nPackage manager detection is adaptive (`pnpm`, `npm`, or `yarn`) and is recorded\nin logs.\n\nRepositories can also provide `buildchain.toml` to declare version-state files\nand `lifecycle.verify`. TOML-configured version files take precedence over\npackage-manager discovery and can target JSON, TOML, or regex-based files. The\nversion commit itself is written through the GitHub Git Data API so the ref\ngraph is the durable source of truth. Repositories without any supported version\nstate degrade to ref-only promotion only when strict version state is disabled.\n\nJSON and TOML version entries whose declared key already matches the requested\nversion are treated as semantic no-ops. TOML changes use a parser-verified\nlossless key edit, so repository formatting is preserved and formatter-only\nrelease-preparation commits are not created. If a unique lossless edit cannot\nbe proven, promotion fails closed instead of rewriting the full TOML document.\n\n## Dry Run\n\nUse `dry-run: \"true\"` or the CLI `buildchain release --dry-run` before merging a\nchannel PR when you need to understand what Buildchain would do. This dry-run is\nat the Buildchain release-line level. It explains:\n\n- the legal source branch for the target channel;\n- exact release or alpha tags that would be created or reused;\n- floating tags and channel branches that would move;\n- version-state files and verification lifecycle that would apply;\n- branch protection, PR lineage, and release-from-alpha checks;\n- publish transaction behavior when `lifecycle.publish` or\n `publish-transaction` is enabled.\n\nIt does not move refs, move tags, write package files, run publish commands, or\npublish npm packages. The GitHub action dry-run still calls GitHub APIs to\nresolve the current target SHA and concrete pending ref updates, but every\nwrite is reported as a dry-run update.\n\nRepositories whose package version is anchored to an explicitly selected\nupstream release can opt into manual next-anchor behavior:\n\n```toml\n[version]\nrequired = true\nstrategy = \"anchored\"\nnext = \"manual\"\nmanifest = \"libnode.release.json\"\n```\n\nIn this mode, the action validates the configured version files and anchor\nmanifest through the repository's verify lifecycle, but it does not rewrite the\npackage version to match the Buildchain release tag. After a production\nrelease, it sets `next-anchor-required=true` and does not auto-create the next\nalpha branch or tag. The repository must create the next upstream anchor line\nexplicitly, then run the normal channel promotion flow for that line.\n\nWhen branch protection requires pull requests, generated version-state commits\nstill run through promotion automation first. The action updates\nBuildchain-managed channel protection before generated bookkeeping, admits only\nthe exact `github-actions` App to the target-bound bypass allowlist, creates\nevery configured required check on the exact generated version-state commit, then\ntries to apply that commit directly. If GitHub still rejects release\nfinalization bookkeeping, Buildchain creates or reuses a same-repository\n`buildchain/version-state/*` PR based on the current target channel head and\nreturns `finalization-needed=true`; a later idempotent promotion run can resume\nfrom the durable transaction state. Strict alpha uses the same protected\nversion-state PR recovery for its target and dev bookkeeping, and does not move\ntags until those provider-enforced transactions land. Reusable wrapper callers\nshould allow `checks: write` so the generated checks are owned by GitHub Actions\nand match the managed branch protection rule.\n\nStable promotion also protects concurrent development work. The reusable\nwrapper checks out the exact current `dev/vN/vN.M` head as a reconciliation\nworkspace. If next-alpha bookkeeping cannot fast-forward that branch, the\naction reruns the declared version-state generation and verification from that\ndev tree, creates a two-parent reconciliation commit from the regenerated\nfiles, and fails closed if the checkout moved before the mutation boundary.\nThis prevents generated projections from an older release tree from replacing\ncapabilities that reached dev while the release was in progress.\n\nFor Buildchain-owned automation, callers may pass\n`branch-protection-bypass-apps: github-actions`. The action rejects every other\nApp slug and all user or team bypass actors. It configures managed\n`dev/vN/vN.M`, `alpha/vN/vN.M`, and `release/vN/vN.M` branches with one\nrequired approving review, Code Owner review, stale-review dismissal,\nlatest-push approval, exact App-bound GitHub Actions checks, admin enforcement,\nconversation resolution, no force pushes, and no deletions; the bypass\nallowance only lets the named automation identity apply generated version-state\nor channel bookkeeping without a second human review after the reviewed channel\nPR has already merged.\n\n## Publish Transactions\n\nPromotion can also own external publish side effects. Enable this only from a\ntrusted channel workflow:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n generated-ref-update-token: ${{ github.token }}\n sha: ${{ github.sha }}\n target-ref: release/v2/v2.0\n publish-transaction: \"true\"\n publish-mode: publish-final-version\n publish-auth: trusted-publishing\n publish-required-artifacts-json: >-\n [\n {\"kind\":\"npm\",\"name\":\"@kungfu-tech/buildchain\",\"ref\":\"2.0.0\",\"digest\":\"sha256:...\"}\n ]\n```\n\nFor anchored/manual package repositories that build through the reusable\nworkflow, keep the publish entrypoint on the `publish-gate/*` source-lock\ncontract:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n sha: ${{ needs.build.outputs.publish-source-sha }}\n target-ref: release/v22/v22.22\n require-publish-source-lock: \"true\"\n publish-source-ref: ${{ needs.build.outputs.publish-source-ref }}\n publish-source-sha: ${{ needs.build.outputs.publish-source-sha }}\n publish-source-locked: ${{ needs.build.outputs.publish-source-locked }}\n publish-transaction: \"true\"\n publish-mode: publish-final-version\n publish-auth: trusted-publishing\n```\n\n`target-ref` remains the channel promotion target that must point at `sha`.\n`publish-source-ref` is the reviewed source-lock branch that authorized this\nspecific package publication. Direct `alpha/*` or `release/*` channel refs are\nnot valid publish source locks when `require-publish-source-lock` is enabled,\nand a mismatched `publish-source-sha` fails before any promotion or publish side effects begin.\n\nConsumers that opt in to a product-owned final predicate set\n`require-publication-qualification: \"true\"` and pass the exact sealed\n`publication-capability-json`, complete `publication-gate-aggregate-json`, and\n`publication-qualification-receipt-json`. The action validates their canonical\ndigests, predicate identity, freshness, nonce, source, version, channel, target,\nand evidence bindings both before provider access and immediately before the\npublish transaction. Missing or drifted receipts fail before mutation. The\nreusable `release-candidate-promote.yml` workflow creates these values in a\nseparate credentialless consumer job; direct callers must preserve the same\ncontract and may pass previously consumed nonces through\n`publication-used-qualification-nonces-json`.\n\nThe reusable promote workflow serializes non-dry-run promotion intents per\nrepository and re-reads `target-ref` before checkout, dependency installation,\nrelease-candidate resolution, or publish-gate writes. If a queued intent asks\nfor an older SHA after the protected channel has advanced, the workflow records\nthe requested/current SHA pair, verifies that the current target is ahead of\nthe requested commit, and exits successfully as a superseded no-op. Diverged,\nbehind, or unreadable comparisons still fail closed.\nAfter queued-intent revalidation, the reusable workflow runs the canonical\nrelease-candidate resolver in metadata-only mode before installing candidate\ndependencies or starting the full promotion job. The full job resolves and\ndownloads the evidence again before any publish-gate or publication mutation.\nThis preserves the final exact-evidence trust check while making missing or\nstale PR-stage evidence fail early.\nThe action repeats that check at its mutation boundary for governed promotion\ncalls, closing the race between workflow preflight and action start. Direct\nnon-governed calls and dry-runs keep the strict target mismatch error so local\ndiagnostics cannot silently reinterpret a stale request.\nExpected manual dry-run failures remain visible in the workflow result and do\nnot create automated workflow-friction issues; issue reporting is reserved for\nnon-dry-run promotion failures.\nThe reusable build workflow performs the cheaper channel-ref preflight earlier:\nafter source-lock resolution and before the build matrix, it requires the target\nchannel ref such as `alpha/v22/v22.22` or `release/v22/v22.22` to already point\nat the locked `publish-source-sha`. If not, maintainers should merge the source\ncommit through the channel PR first.\n\nFor promote-only release candidates, attach the PR-stage reusable build evidence\nand fail before publish-gate side effects if it no longer matches:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n sha: ${{ needs.build.outputs.publish-source-sha }}\n target-ref: alpha/v22/v22.22\n promote-only-release-candidate: \"true\"\n release-candidate-passport-path: .buildchain/artifacts/release-candidate-passport.json\n release-candidate-build-summary-path: .buildchain/artifacts/build-summary.json\n```\n\nThe action validates repository, channel, source identity, platform matrix, and\nthe aggregate build-summary hash before it writes version state, opens\nrelease-state, runs publish transaction logic, or moves tags/branches. Source\nidentity accepts the exact source SHA, the PR merge ref SHA, or the promoted\nchannel HEAD's Git tree SHA matching the passport tree hash. If validation\nfails, run or attach the verified channel PR build first instead of promoting a\nstale or unproven artifact set.\n\nWhen enabled, the action creates or resumes a release transaction keyed by\nrepository, version, source SHA, and target ref. It persists that transaction to\na machine-managed branch under `buildchain/release-state/<version>`, with\n`state.json` and, once available, `evidence.json`. Fresh GitHub runners read\nthat durable ref before running publish, so reruns do not depend on a previous\nrunner's local `.buildchain` directory.\n\nConsumers whose publish lifecycle only assembles local release assets or\nPassport inputs may set `publish-rematerialize-on-resume: true`. After\nBuildchain restores and validates durable publish evidence, it replays that\nconsumer-owned lifecycle with the original transaction environment before\nPassport collection. This is explicit opt-in because registry publication and\nother provider mutations must not be replayed blindly; the option rejects\n`promote-existing-version`.\n\nThe action runs `lifecycle.publish` from `buildchain.toml` or the explicit\n`publish-command` input, then validates publish evidence before exact tags and\nfloating refs move. If durable state persistence fails, the action fails closed\nbefore publish or public ref finalization.\n\n`publish-mode` defaults to `publish-final-version`, the token-free path for\nnormal npm Trusted Publishing. Same-version alpha-to-latest recovery must be\ndeclared as `publish-mode: promote-existing-version` and\n`publish-auth: npm-token`; Buildchain runs `npm whoami` before it creates\nrelease-state or moves any `npm dist-tag`. The Trusted Publishing mode is not\nallowed to perform `npm dist-tag add`.\n\nBuildchain itself uses this path for npm. Its `lifecycle.publish` runs\n`node scripts/npm-publish-transaction.mjs`, which publishes\n`@kungfu-tech/buildchain` through npm Trusted Publishing and writes npm\nartifact evidence into the transaction before release refs move. The separate\n`.github/workflows/npm-publish.yml` workflow is dry-run only.\n\nPublish lifecycle environment:\n\n```text\nBUILDCHAIN_VERSION\nBUILDCHAIN_CHANNEL\nBUILDCHAIN_SOURCE_SHA\nBUILDCHAIN_TARGET_REF\nBUILDCHAIN_RELEASE_STATE\nBUILDCHAIN_EVIDENCE_DIR\nBUILDCHAIN_RELEASE_SHA\nBUILDCHAIN_RELEASE_MATERIAL_SHA\nBUILDCHAIN_PUBLISH_TOOLING_SHA\nBUILDCHAIN_PUBLISH_EVIDENCE\nBUILDCHAIN_REQUIRED_ARTIFACTS\n```\n\n`BUILDCHAIN_REQUIRED_ARTIFACTS` is the normalized requirement array after the\naction resolves a missing artifact `ref` to `BUILDCHAIN_VERSION`, or expands an\noptional `ref_template` containing exactly one `{version}`, and binds any\ndeclared provenance to the current release coordinate. Template expansion\nhappens after exact version selection; ambiguous or unsupported templates fail\nbefore `lifecycle.publish`. Requirement descriptors may omit `digest`; final\npublish evidence may not.\n\nThe action outputs `transaction-id`, `transaction-state`,\n`transaction-exact-tag`, `public-release-tag`, `transaction-release-sha`,\n`transaction-state-ref`, `transaction-state-sha`, `transaction-state-path`,\n`publish-evidence-path`, and `release-passport-path`, `release-passport-output-dir`,\n`release-passport-state-sha`, and `finalization-needed`.\n`transaction-state-ref` is the durable recovery location.\n`release-passport-state-sha` is the durable ref commit after the generated\n`release-passport/*` files have been uploaded into that recovery ref.\n`finalization-needed=true` means publish evidence is valid, but protected branch\nor ref finalization needs a later idempotent promotion run. For release\nfinalization, Buildchain may create a same-repository generated version-state\nPR when GitHub rejects the direct protected ref update; that PR is Buildchain\nbookkeeping, not a consumer-authored release change.\nSet `github-release: \"true\"` when the semver promotion should also publish the\npublic GitHub Release. After the release transaction reaches `complete` and\n`finalization-needed` is false, the action creates or updates the GitHub Release\nfor `public-release-tag`, applies deterministic metadata from the authoritative\npublication channel (`alpha` is a prerelease and never latest; `release`,\n`stable`, and `major` are stable and latest), and uploads the publish evidence\nfile plus generated release passport assets. Tag syntax remains the fallback for\nordinary callers that do not supply publication intent. For anchored/manual\npackage releases, `public-release-tag` is derived\nfrom the published package version, while `transaction-exact-tag` remains the\ninternal Buildchain transaction ref for recovery and audit. If the transaction is\nnot complete yet, the action defers GitHub Release publication to the next\nidempotent promotion run.\n\nAfter a publish transaction reaches `complete`, the action generates the unified\n`buildchain-release-passport` in `.buildchain/release-passport` by default and\npersists those files under `release-passport/` in the durable release-state ref.\nSet `release-passport-product-name` to record the consumer product name, for\nexample `Libnode`, instead of the default `Buildchain`.\nSet `release-passport-kfd-1-witness-jsons` to newline-separated KFD-1\ncontract-world witness JSON paths when released artifacts must prove\nbyte-for-byte KFD contract surfaces. Buildchain imports the KFD metadata from\n`@kungfu-tech/kfd`, freezes the witness, verifies artifact bytes, and writes the\nresult under the KFD-provided `kfd-1` passport section.\nSet `release-passport-kfd-2-claim-jsons` to newline-separated KFD-2 public\nrelease trust claim JSON paths when a release makes additional human/agent\nvisible claims. Buildchain requires each public claim to bind declared sources,\nmachine-readable evidence, hashes, artifact coordinates, verification results,\naudit boundary, responsibility state, and residual risk. Unbound claims fail\npassport verification; prose-only claims downgrade the KFD-2 audit.\nSet `release-passport-kfd-3-prebuild-witness-jsons` to newline-separated KFD-3\ncollaboration-interface pre-build witness paths, then provide artifact-side\nevidence with `release-passport-kfd-3-artifact-witness-jsons` or a\nproduct-owned `release-passport-kfd-3-artifact-verify-command` such as\n`kungfu agent verify --json`. Buildchain compares declared shipped public\nsurfaces with artifact-exposed public surfaces and writes the result under the\nKFD-provided `kfd-3` passport section.\nSet `release-passport-invariant-passport-jsons` to one or more product-owned\ninvariant Passport paths, or set `release-passport-invariant-passport-command`\nto a command that emits one canonical Passport JSON document. Buildchain does\nnot reinterpret product invariants: it verifies the declared semantic root,\nrequires a `verified` verdict, complete platform coverage, a clean exact source\nrevision, and then binds the result into `buildchain.release.json`. Missing,\nstale, falsified, incomplete, dirty, or tampered Passport evidence fails the\nrelease transaction closed.\nBuildchain's own release workflow sets `release-passport-buildchain-self-kfd:\n\"true\"`. In that mode the action generates Buildchain-owned KFD-1/2/3 witnesses\ninside the final version-state workspace, after the release transaction has\nmaterialized generated files such as `package.json` and `dist/site/*`. This\nkeeps self-hosted KFD witness hashes bound to the exact published package\ninstead of to a pre-promotion checkout.\nWhen present, the passport includes the aggregate build summary, platform\nartifact manifests, npm publish evidence, dist-tag promotion evidence, the\nrelease-state ref, trusted publishing metadata, and the Buildchain transaction\nresult. After the first passport upload, Buildchain backfills the durable\nrelease-state SHA into `buildchain.release.json` and persists the passport\nagain, so the consumer-side passport is a complete audit entrypoint. Set\n`release-passport: \"false\"` only for a controlled recovery run that must skip\npassport generation.\n\nFinalization recovery is anchored to the durable transaction, not to a single\nworkflow run SHA. After generated version-state bookkeeping is applied, the\ncurrent channel head can be the generated version-state commit or a historical\nmerge commit that contains or corresponds to the recorded `release_material_sha`;\nit does not have to equal the original `source_sha` or the transaction\n`release_sha`. Reruns accept exact tags that already point at the transaction\nrelease/material SHA or the finalized channel head, and continue moving any\nmissing floating tags or dev/alpha refs before marking the transaction\n`complete`.\n\nNormal reruns accept already-published artifacts only when evidence matches.\nMissing required artifacts can be published on the next run. Conflicting\nrefs, digests, or declared provenance put the transaction into\n`repair_required`; `abandoned` and\n`failed_permanently` also fail closed unless `publish-transaction-override` is\nset for a controlled repair. The same override may replace a stale transaction\nonly when its version, exact tag, target ref, and channel are unchanged, the\ntransaction is not complete, and it contains no published artifacts or\nevidence. This lets a newly admitted source retry a previously failed paper\npublication without weakening already-published facts.\n\nIn strict buildchain promotion, ref movement is also gated by the old ABV\ngovernance semantics:\n\n- when detailed target branch protection is readable, it must enforce\n protection for administrators and require approving PR review plus the strict\n `check` job from the `Verify` workflow; when GitHub withholds that\n administration endpoint from the workflow token, the exact transaction must\n instead prove a protected current head, same-repository merged PR,\n independent approval, and the required successful `check` from its configured\n GitHub App;\n- post-publish channel reconciliation reuses an already qualifying\n provider-enforced policy when the workflow token cannot read or rewrite the\n administrative protection document, and fails closed if the public branch\n summary no longer carries the required check for everyone;\n- alpha promotion must come from a merged same-repository PR\n `dev/vN/vN.M -> alpha/vN/vN.M`, or from a strict same-line\n `publish-gate/alpha/vN/vN.M/<version> -> alpha/vN/vN.M` source-lock PR;\n- release promotion must come from a merged same-repository PR\n `alpha/vN/vN.M -> release/vN/vN.M`, or from a strict same-line\n `publish-gate/release/vN/vN.M/<version> -> release/vN/vN.M` source-lock PR;\n- major promotion must come from a merged same-repository PR\n `release/vN/vN.M -> publish-gate/major`;\n- release promotion must have an exact alpha tag for the same patch line, and\n the release source tree must match that alpha tag tree, so release does not\n introduce new code after alpha;\n- anchored/manual release promotion may differ from that alpha tree only in\n declared `version.files` and the configured anchor manifest, and only when the\n checked-out release material has passed `lifecycle.verify` or the explicit\n `verification-command`;\n- generated release and next-alpha version-state trees can be verified locally\n with either the `verification-command` input or `buildchain.toml`\n `lifecycle.verify` before any tags or channel refs move.\n\nThe promotion workflow should use `BUILDCHAIN_PROMOTION_TOKEN` for non-dry-run\npromotion. The token is the buildchain equivalent of the old ABV runner release\nauthority: protected branch review and check rules guard human channel merges,\nwhile the reusable build trust gate now checks the source-lock channel HEAD and\nmerged same-repository PR lineage before heavy build runners start. This action\nstill independently rechecks PR lineage, alpha/release tree equivalence, and\ngenerated version-state verification before moving channel refs and tags.\nGenerated version-state direct ref updates can use a separate\n`generated-ref-update-token`; the reusable wrapper binds it to the run-scoped\n`github.token`.\nThe reusable `release-candidate-promote.yml` wrapper defaults\n`branch-protection-bypass-apps` to `github-actions`, so flow-internal promotion\ncan complete generated `dev`/`alpha`/`release` bookkeeping while ordinary human\npushes and PR merges remain governed by the one-review branch protection rule.\nThe promotion action rejects alternate App slugs and every user or team bypass,\nso the mutation path cannot widen the authority descriptor.\n\nThe tag names intentionally follow the old ABV release semantics:\nexact release tags are `vX.Y.Z`, exact alpha tags are `vX.Y.Z-alpha.N`, floating\nrelease tags are minor/major tags such as `v2.0` and `v2`, and floating alpha\ntags are minor-line tags such as `v2.0-alpha` plus cross-minor major tags such\nas `v2-alpha`. A major alpha tag only moves for the highest minor in that major\nwith a published alpha, so older-line maintenance cannot roll consumers back.\nBare tags such as `1.0.0` are not\nmaintained as buildchain release entrypoints.\n\nRepository rulesets should protect exact tags, not every `v*` tag. A ruleset\nsuch as `refs/tags/v*` also protects floating channel tags like `v2.0-alpha` and `v2-alpha`,\nwhich Buildchain must update after exact tags and publish evidence are durable.\nUse an exact-tag rule such as `refs/tags/v*.*.*` for immutable evidence tags and\nleave floating channel tags mutable for the promotion token."
|
|
227
|
+
"markdown": "# promote-buildchain-ref\n\nInternal buildchain action for promoting verified buildchain release-line and\ncompatibility refs from buildchain release channels:\n\n- `alpha/v2/v2.0` creates or reuses the next exact prerelease tag such as\n `v2.0.1-alpha.0`, writes that version into package version state, points the\n alpha and dev channel branches at the version commit, then promotes\n `v2.0-alpha` and, when this is the highest published alpha minor, `v2-alpha`;\n- `release/v2/v2.0` creates or reuses the next exact release tag such as\n `v2.0.0`, writes that version into package version state, points the release\n channel branch and release tags at the release commit, then prepares a second\n source commit for the next exact prerelease tag such as `v2.0.1-alpha.0` and\n points the alpha/dev channel branches plus `v2.0-alpha` at that prerelease\n commit, and moves `v2-alpha` only if no higher v2 minor has published an alpha;\n- `publish-gate/major` accepts a reviewed PR from a production release line such\n as `release/v2/v2.0`, writes the next major production version such as\n `v3.0.0`, points `publish-gate/major`, `release/v3/v3.0`, `v3.0`, and `v3`\n at that release commit, then prepares `v3.0.1-alpha.0` for\n `alpha/v3/v3.0`, `dev/v3/v3.0`, `v3.0-alpha`, and `v3-alpha`. The older `major-gate`\n branch name is a compatibility alias only.\n\nThe release branch name defines the minor line. For example,\n`release/v2/v2.1` creates `v2.1.N`, promotes `v2.1`, and promotes `v2` only\nwhen the next minor tag such as `v2.2` does not already exist.\n\nThe action updates version state in `lerna.json`, root `package.json`, and\nworkspace package manifests discovered from package manager metadata\n(`package.json` workspaces, `lerna.json` packages, or `pnpm-workspace.yaml`).\nPackage manager detection is adaptive (`pnpm`, `npm`, or `yarn`) and is recorded\nin logs.\n\nRepositories can also provide `buildchain.toml` to declare version-state files\nand `lifecycle.verify`. TOML-configured version files take precedence over\npackage-manager discovery and can target JSON, TOML, or regex-based files. The\nversion commit itself is written through the GitHub Git Data API so the ref\ngraph is the durable source of truth. Repositories without any supported version\nstate degrade to ref-only promotion only when strict version state is disabled.\n\nJSON and TOML version entries whose declared key already matches the requested\nversion are treated as semantic no-ops. TOML changes use a parser-verified\nlossless key edit, so repository formatting is preserved and formatter-only\nrelease-preparation commits are not created. If a unique lossless edit cannot\nbe proven, promotion fails closed instead of rewriting the full TOML document.\n\n## Dry Run\n\nUse `dry-run: \"true\"` or the CLI `buildchain release --dry-run` before merging a\nchannel PR when you need to understand what Buildchain would do. This dry-run is\nat the Buildchain release-line level. It explains:\n\n- the legal source branch for the target channel;\n- exact release or alpha tags that would be created or reused;\n- floating tags and channel branches that would move;\n- version-state files and verification lifecycle that would apply;\n- branch protection, PR lineage, and release-from-alpha checks;\n- publish transaction behavior when `lifecycle.publish` or\n `publish-transaction` is enabled.\n\nIt does not move refs, move tags, write package files, run publish commands, or\npublish npm packages. The GitHub action dry-run still calls GitHub APIs to\nresolve the current target SHA and concrete pending ref updates, but every\nwrite is reported as a dry-run update.\n\nRepositories whose package version is anchored to an explicitly selected\nupstream release can opt into manual next-anchor behavior:\n\n```toml\n[version]\nrequired = true\nstrategy = \"anchored\"\nnext = \"manual\"\nmanifest = \"libnode.release.json\"\n```\n\nIn this mode, the action validates the configured version files and anchor\nmanifest through the repository's verify lifecycle, but it does not rewrite the\npackage version to match the Buildchain release tag. After a production\nrelease, it sets `next-anchor-required=true` and does not auto-create the next\nalpha branch or tag. The repository must create the next upstream anchor line\nexplicitly, then run the normal channel promotion flow for that line.\n\nWhen branch protection requires pull requests, generated version-state commits\nstill run through promotion automation first. The action updates\nBuildchain-managed channel protection before generated bookkeeping, admits only\nthe exact `github-actions` App to the target-bound bypass allowlist, creates\nevery configured required check on the exact generated version-state commit, then\ntries to apply that commit directly. If GitHub still rejects release\nfinalization bookkeeping, Buildchain creates or reuses a same-repository\n`buildchain/version-state/*` PR based on the current target channel head and\nreturns `finalization-needed=true`; a later idempotent promotion run can resume\nfrom the durable transaction state. Strict alpha uses the same protected\nversion-state PR recovery for its target and dev bookkeeping, and does not move\ntags until those provider-enforced transactions land. Reusable wrapper callers\nshould allow `checks: write` so the generated checks are owned by GitHub Actions\nand match the managed branch protection rule.\n\nStable promotion also protects concurrent development work. The reusable\nwrapper checks out the exact current `dev/vN/vN.M` head as a reconciliation\nworkspace. If next-alpha bookkeeping cannot fast-forward that branch, the\naction reruns the declared version-state generation and verification from that\ndev tree, creates a two-parent reconciliation commit from the regenerated\nfiles, and fails closed if the checkout moved before the mutation boundary.\nThis prevents generated projections from an older release tree from replacing\ncapabilities that reached dev while the release was in progress.\n\nFor Buildchain-owned automation, callers may pass\n`branch-protection-bypass-apps: github-actions`. The action rejects every other\nApp slug and all user or team bypass actors. It configures managed\n`dev/vN/vN.M`, `alpha/vN/vN.M`, and `release/vN/vN.M` branches with one\nrequired approving review, Code Owner review, stale-review dismissal,\nlatest-push approval, exact App-bound GitHub Actions checks, admin enforcement,\nconversation resolution, no force pushes, and no deletions; the bypass\nallowance only lets the named automation identity apply generated version-state\nor channel bookkeeping without a second human review after the reviewed channel\nPR has already merged.\n\nGitHub may return either `403` or a deliberately opaque `404` when a\nnon-administrator token reads the full branch-protection endpoint. In that\ncase, promotion reads the provider's branch summary and accepts only an\nalready-protected branch that enforces the exact required check for everyone.\nIt does not interpret the opaque response as missing protection or try to\nrewrite policy with a developer token. The independent publication-authority\naudit remains responsible for the complete read-only governance proof.\n\n## Publish Transactions\n\nPromotion can also own external publish side effects. Enable this only from a\ntrusted channel workflow:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n generated-ref-update-token: ${{ github.token }}\n sha: ${{ github.sha }}\n target-ref: release/v2/v2.0\n publish-transaction: \"true\"\n publish-mode: publish-final-version\n publish-auth: trusted-publishing\n publish-required-artifacts-json: >-\n [\n {\"kind\":\"npm\",\"name\":\"@kungfu-tech/buildchain\",\"ref\":\"2.0.0\",\"digest\":\"sha256:...\"}\n ]\n```\n\nFor anchored/manual package repositories that build through the reusable\nworkflow, keep the publish entrypoint on the `publish-gate/*` source-lock\ncontract:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n sha: ${{ needs.build.outputs.publish-source-sha }}\n target-ref: release/v22/v22.22\n require-publish-source-lock: \"true\"\n publish-source-ref: ${{ needs.build.outputs.publish-source-ref }}\n publish-source-sha: ${{ needs.build.outputs.publish-source-sha }}\n publish-source-locked: ${{ needs.build.outputs.publish-source-locked }}\n publish-transaction: \"true\"\n publish-mode: publish-final-version\n publish-auth: trusted-publishing\n```\n\n`target-ref` remains the channel promotion target that must point at `sha`.\n`publish-source-ref` is the reviewed source-lock branch that authorized this\nspecific package publication. Direct `alpha/*` or `release/*` channel refs are\nnot valid publish source locks when `require-publish-source-lock` is enabled,\nand a mismatched `publish-source-sha` fails before any promotion or publish side effects begin.\n\nConsumers that opt in to a product-owned final predicate set\n`require-publication-qualification: \"true\"` and pass the exact sealed\n`publication-capability-json`, complete `publication-gate-aggregate-json`, and\n`publication-qualification-receipt-json`. The action validates their canonical\ndigests, predicate identity, freshness, nonce, source, version, channel, target,\nand evidence bindings both before provider access and immediately before the\npublish transaction. Missing or drifted receipts fail before mutation. The\nreusable `release-candidate-promote.yml` workflow creates these values in a\nseparate credentialless consumer job; direct callers must preserve the same\ncontract and may pass previously consumed nonces through\n`publication-used-qualification-nonces-json`.\n\nThe reusable promote workflow serializes non-dry-run promotion intents per\nrepository and re-reads `target-ref` before checkout, dependency installation,\nrelease-candidate resolution, or publish-gate writes. If a queued intent asks\nfor an older SHA after the protected channel has advanced, the workflow records\nthe requested/current SHA pair, verifies that the current target is ahead of\nthe requested commit, and exits successfully as a superseded no-op. Diverged,\nbehind, or unreadable comparisons still fail closed.\nAfter queued-intent revalidation, the reusable workflow runs the canonical\nrelease-candidate resolver in metadata-only mode before installing candidate\ndependencies or starting the full promotion job. The full job resolves and\ndownloads the evidence again before any publish-gate or publication mutation.\nThis preserves the final exact-evidence trust check while making missing or\nstale PR-stage evidence fail early.\nThe action repeats that check at its mutation boundary for governed promotion\ncalls, closing the race between workflow preflight and action start. Direct\nnon-governed calls and dry-runs keep the strict target mismatch error so local\ndiagnostics cannot silently reinterpret a stale request.\nExpected manual dry-run failures remain visible in the workflow result and do\nnot create automated workflow-friction issues; issue reporting is reserved for\nnon-dry-run promotion failures.\nThe reusable build workflow performs the cheaper channel-ref preflight earlier:\nafter source-lock resolution and before the build matrix, it requires the target\nchannel ref such as `alpha/v22/v22.22` or `release/v22/v22.22` to already point\nat the locked `publish-source-sha`. If not, maintainers should merge the source\ncommit through the channel PR first.\n\nFor promote-only release candidates, attach the PR-stage reusable build evidence\nand fail before publish-gate side effects if it no longer matches:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n sha: ${{ needs.build.outputs.publish-source-sha }}\n target-ref: alpha/v22/v22.22\n promote-only-release-candidate: \"true\"\n release-candidate-passport-path: .buildchain/artifacts/release-candidate-passport.json\n release-candidate-build-summary-path: .buildchain/artifacts/build-summary.json\n```\n\nThe action validates repository, channel, source identity, platform matrix, and\nthe aggregate build-summary hash before it writes version state, opens\nrelease-state, runs publish transaction logic, or moves tags/branches. Source\nidentity accepts the exact source SHA, the PR merge ref SHA, or the promoted\nchannel HEAD's Git tree SHA matching the passport tree hash. If validation\nfails, run or attach the verified channel PR build first instead of promoting a\nstale or unproven artifact set.\n\nWhen enabled, the action creates or resumes a release transaction keyed by\nrepository, version, source SHA, and target ref. It persists that transaction to\na machine-managed branch under `buildchain/release-state/<version>`, with\n`state.json` and, once available, `evidence.json`. Fresh GitHub runners read\nthat durable ref before running publish, so reruns do not depend on a previous\nrunner's local `.buildchain` directory.\n\nConsumers whose publish lifecycle only assembles local release assets or\nPassport inputs may set `publish-rematerialize-on-resume: true`. After\nBuildchain restores and validates durable publish evidence, it replays that\nconsumer-owned lifecycle with the original transaction environment before\nPassport collection. This is explicit opt-in because registry publication and\nother provider mutations must not be replayed blindly; the option rejects\n`promote-existing-version`.\n\nThe action runs `lifecycle.publish` from `buildchain.toml` or the explicit\n`publish-command` input, then validates publish evidence before exact tags and\nfloating refs move. If durable state persistence fails, the action fails closed\nbefore publish or public ref finalization.\n\n`publish-mode` defaults to `publish-final-version`, the token-free path for\nnormal npm Trusted Publishing. Same-version alpha-to-latest recovery must be\ndeclared as `publish-mode: promote-existing-version` and\n`publish-auth: npm-token`; Buildchain runs `npm whoami` before it creates\nrelease-state or moves any `npm dist-tag`. The Trusted Publishing mode is not\nallowed to perform `npm dist-tag add`.\n\nBuildchain itself uses this path for npm. Its `lifecycle.publish` runs\n`node scripts/npm-publish-transaction.mjs`, which publishes\n`@kungfu-tech/buildchain` through npm Trusted Publishing and writes npm\nartifact evidence into the transaction before release refs move. The separate\n`.github/workflows/npm-publish.yml` workflow is dry-run only.\n\nPublish lifecycle environment:\n\n```text\nBUILDCHAIN_VERSION\nBUILDCHAIN_CHANNEL\nBUILDCHAIN_SOURCE_SHA\nBUILDCHAIN_TARGET_REF\nBUILDCHAIN_RELEASE_STATE\nBUILDCHAIN_EVIDENCE_DIR\nBUILDCHAIN_RELEASE_SHA\nBUILDCHAIN_RELEASE_MATERIAL_SHA\nBUILDCHAIN_PUBLISH_TOOLING_SHA\nBUILDCHAIN_PUBLISH_EVIDENCE\nBUILDCHAIN_REQUIRED_ARTIFACTS\n```\n\n`BUILDCHAIN_REQUIRED_ARTIFACTS` is the normalized requirement array after the\naction resolves a missing artifact `ref` to `BUILDCHAIN_VERSION`, or expands an\noptional `ref_template` containing exactly one `{version}`, and binds any\ndeclared provenance to the current release coordinate. Template expansion\nhappens after exact version selection; ambiguous or unsupported templates fail\nbefore `lifecycle.publish`. Requirement descriptors may omit `digest`; final\npublish evidence may not.\n\nThe action outputs `transaction-id`, `transaction-state`,\n`transaction-exact-tag`, `public-release-tag`, `transaction-release-sha`,\n`transaction-state-ref`, `transaction-state-sha`, `transaction-state-path`,\n`publish-evidence-path`, and `release-passport-path`, `release-passport-output-dir`,\n`release-passport-state-sha`, and `finalization-needed`.\n`transaction-state-ref` is the durable recovery location.\n`release-passport-state-sha` is the durable ref commit after the generated\n`release-passport/*` files have been uploaded into that recovery ref.\n`finalization-needed=true` means publish evidence is valid, but protected branch\nor ref finalization needs a later idempotent promotion run. For release\nfinalization, Buildchain may create a same-repository generated version-state\nPR when GitHub rejects the direct protected ref update; that PR is Buildchain\nbookkeeping, not a consumer-authored release change.\nSet `github-release: \"true\"` when the semver promotion should also publish the\npublic GitHub Release. After the release transaction reaches `complete` and\n`finalization-needed` is false, the action creates or updates the GitHub Release\nfor `public-release-tag`, applies deterministic metadata from the authoritative\npublication channel (`alpha` is a prerelease and never latest; `release`,\n`stable`, and `major` are stable and latest), and uploads the publish evidence\nfile plus generated release passport assets. Tag syntax remains the fallback for\nordinary callers that do not supply publication intent. For anchored/manual\npackage releases, `public-release-tag` is derived\nfrom the published package version, while `transaction-exact-tag` remains the\ninternal Buildchain transaction ref for recovery and audit. If the transaction is\nnot complete yet, the action defers GitHub Release publication to the next\nidempotent promotion run.\n\nAfter a publish transaction reaches `complete`, the action generates the unified\n`buildchain-release-passport` in `.buildchain/release-passport` by default and\npersists those files under `release-passport/` in the durable release-state ref.\nSet `release-passport-product-name` to record the consumer product name, for\nexample `Libnode`, instead of the default `Buildchain`.\nSet `release-passport-kfd-1-witness-jsons` to newline-separated KFD-1\ncontract-world witness JSON paths when released artifacts must prove\nbyte-for-byte KFD contract surfaces. Buildchain imports the KFD metadata from\n`@kungfu-tech/kfd`, freezes the witness, verifies artifact bytes, and writes the\nresult under the KFD-provided `kfd-1` passport section.\nSet `release-passport-kfd-2-claim-jsons` to newline-separated KFD-2 public\nrelease trust claim JSON paths when a release makes additional human/agent\nvisible claims. Buildchain requires each public claim to bind declared sources,\nmachine-readable evidence, hashes, artifact coordinates, verification results,\naudit boundary, responsibility state, and residual risk. Unbound claims fail\npassport verification; prose-only claims downgrade the KFD-2 audit.\nSet `release-passport-kfd-3-prebuild-witness-jsons` to newline-separated KFD-3\ncollaboration-interface pre-build witness paths, then provide artifact-side\nevidence with `release-passport-kfd-3-artifact-witness-jsons` or a\nproduct-owned `release-passport-kfd-3-artifact-verify-command` such as\n`kungfu agent verify --json`. Buildchain compares declared shipped public\nsurfaces with artifact-exposed public surfaces and writes the result under the\nKFD-provided `kfd-3` passport section.\nSet `release-passport-invariant-passport-jsons` to one or more product-owned\ninvariant Passport paths, or set `release-passport-invariant-passport-command`\nto a command that emits one canonical Passport JSON document. Buildchain does\nnot reinterpret product invariants: it verifies the declared semantic root,\nrequires a `verified` verdict, complete platform coverage, a clean exact source\nrevision, and then binds the result into `buildchain.release.json`. Missing,\nstale, falsified, incomplete, dirty, or tampered Passport evidence fails the\nrelease transaction closed.\nBuildchain's own release workflow sets `release-passport-buildchain-self-kfd:\n\"true\"`. In that mode the action generates Buildchain-owned KFD-1/2/3 witnesses\ninside the final version-state workspace, after the release transaction has\nmaterialized generated files such as `package.json` and `dist/site/*`. This\nkeeps self-hosted KFD witness hashes bound to the exact published package\ninstead of to a pre-promotion checkout.\nWhen present, the passport includes the aggregate build summary, platform\nartifact manifests, npm publish evidence, dist-tag promotion evidence, the\nrelease-state ref, trusted publishing metadata, and the Buildchain transaction\nresult. After the first passport upload, Buildchain backfills the durable\nrelease-state SHA into `buildchain.release.json` and persists the passport\nagain, so the consumer-side passport is a complete audit entrypoint. Set\n`release-passport: \"false\"` only for a controlled recovery run that must skip\npassport generation.\n\nFinalization recovery is anchored to the durable transaction, not to a single\nworkflow run SHA. After generated version-state bookkeeping is applied, the\ncurrent channel head can be the generated version-state commit or a historical\nmerge commit that contains or corresponds to the recorded `release_material_sha`;\nit does not have to equal the original `source_sha` or the transaction\n`release_sha`. Reruns accept exact tags that already point at the transaction\nrelease/material SHA or the finalized channel head, and continue moving any\nmissing floating tags or dev/alpha refs before marking the transaction\n`complete`.\n\nNormal reruns accept already-published artifacts only when evidence matches.\nMissing required artifacts can be published on the next run. Conflicting\nrefs, digests, or declared provenance put the transaction into\n`repair_required`; `abandoned` and\n`failed_permanently` also fail closed unless `publish-transaction-override` is\nset for a controlled repair. The same override may replace a stale transaction\nonly when its version, exact tag, target ref, and channel are unchanged, the\ntransaction is not complete, and it contains no published artifacts or\nevidence. This lets a newly admitted source retry a previously failed paper\npublication without weakening already-published facts.\n\nIn strict buildchain promotion, ref movement is also gated by the old ABV\ngovernance semantics:\n\n- when detailed target branch protection is readable, it must enforce\n protection for administrators and require approving PR review plus the strict\n `check` job from the `Verify` workflow; when GitHub withholds that\n administration endpoint from the workflow token, the exact transaction must\n instead prove a protected current head, same-repository merged PR,\n independent approval, and the required successful `check` from its configured\n GitHub App;\n- post-publish channel reconciliation reuses an already qualifying\n provider-enforced policy when the workflow token cannot read or rewrite the\n administrative protection document, and fails closed if the public branch\n summary no longer carries the required check for everyone;\n- alpha promotion must come from a merged same-repository PR\n `dev/vN/vN.M -> alpha/vN/vN.M`, or from a strict same-line\n `publish-gate/alpha/vN/vN.M/<version> -> alpha/vN/vN.M` source-lock PR;\n- release promotion must come from a merged same-repository PR\n `alpha/vN/vN.M -> release/vN/vN.M`, or from a strict same-line\n `publish-gate/release/vN/vN.M/<version> -> release/vN/vN.M` source-lock PR;\n- major promotion must come from a merged same-repository PR\n `release/vN/vN.M -> publish-gate/major`;\n- release promotion must have an exact alpha tag for the same patch line, and\n the release source tree must match that alpha tag tree, so release does not\n introduce new code after alpha;\n- anchored/manual release promotion may differ from that alpha tree only in\n declared `version.files` and the configured anchor manifest, and only when the\n checked-out release material has passed `lifecycle.verify` or the explicit\n `verification-command`;\n- generated release and next-alpha version-state trees can be verified locally\n with either the `verification-command` input or `buildchain.toml`\n `lifecycle.verify` before any tags or channel refs move.\n\nThe reusable promotion workflow keeps governance reads, generated status checks,\nand generated ref updates on the run-scoped `github.token`. When branch\nprotection rejects generated bookkeeping, it supplies `BUILDCHAIN_PROMOTION_TOKEN`\nonly through `generated-pull-request-token` so the same-repository recovery PR can\nbe listed or created without broadening the governance client. Protected branch\nreview and check rules guard human channel merges, while the reusable build trust\ngate checks the source-lock channel HEAD and merged same-repository PR lineage\nbefore heavy build runners start. This action still independently rechecks PR\nlineage, alpha/release tree equivalence, and generated version-state verification\nbefore moving channel refs and tags.\nThe reusable `release-candidate-promote.yml` wrapper defaults\n`branch-protection-bypass-apps` to `github-actions`, so flow-internal promotion\ncan complete generated `dev`/`alpha`/`release` bookkeeping while ordinary human\npushes and PR merges remain governed by the one-review branch protection rule.\nThe promotion action rejects alternate App slugs and every user or team bypass,\nso the mutation path cannot widen the authority descriptor.\n\nThe tag names intentionally follow the old ABV release semantics:\nexact release tags are `vX.Y.Z`, exact alpha tags are `vX.Y.Z-alpha.N`, floating\nrelease tags are minor/major tags such as `v2.0` and `v2`, and floating alpha\ntags are minor-line tags such as `v2.0-alpha` plus cross-minor major tags such\nas `v2-alpha`. A major alpha tag only moves for the highest minor in that major\nwith a published alpha, so older-line maintenance cannot roll consumers back.\nBare tags such as `1.0.0` are not\nmaintained as buildchain release entrypoints.\n\nRepository rulesets should protect exact tags, not every `v*` tag. A ruleset\nsuch as `refs/tags/v*` also protects floating channel tags like `v2.0-alpha` and `v2-alpha`,\nwhich Buildchain must update after exact tags and publish evidence are durable.\nUse an exact-tag rule such as `refs/tags/v*.*.*` for immutable evidence tags and\nleave floating channel tags mutable for the promotion token."
|
|
228
228
|
},
|
|
229
229
|
{
|
|
230
230
|
"id": "action:report-buildchain-issue",
|
|
@@ -600,7 +600,7 @@
|
|
|
600
600
|
],
|
|
601
601
|
"maturity": "preview",
|
|
602
602
|
"sourcePath": "docs/github-governance-authority.md",
|
|
603
|
-
"digest": "sha256:
|
|
603
|
+
"digest": "sha256:8484b18d5b0fe6d61d102d6b9cb9e18beac9f47ecb516d430fb5427518e2931f",
|
|
604
604
|
"headings": [
|
|
605
605
|
{
|
|
606
606
|
"level": 1,
|
|
@@ -633,7 +633,7 @@
|
|
|
633
633
|
"anchor": "mutation-and-rollback-boundary"
|
|
634
634
|
}
|
|
635
635
|
],
|
|
636
|
-
"markdown": "---\nstatus: draft\nperiod: ongoing\ntheme: github-governance-authority\ndoc_type: protocol\nsource_level: local-files\nconfidence: high\nsensitivity: public\nevidence_grade: B\nreview_state: unreviewed\nlast_reviewed: 2026-07-24\nai_provenance:\n model_family: GPT-5\n product: Codex\n generated_at: 2026-07-24\n limits: Live GitHub state and account recovery remain provider-controlled and must be re-audited.\n---\n\n# GitHub Governance Authority\n\nBuildchain treats GitHub governance as an independently verified, fail-closed\nauthority boundary. A green CI run, a CODEOWNERS file, an API success response,\nor an administrator's assertion is not sufficient by itself. The verifier\ncombines the exact CODEOWNERS bytes from the target base branch, classic branch\nprotection, every applicable repository or organization ruleset, account role\nclasses, plan capability, required checks, and provider-read completeness into\none short-lived immutable receipt.\n\nThe machine contract is\n`@kungfu-tech/buildchain/github-governance-authority`. Its policy root covers\nthe managed-zone repository and target-ref admission rules, the exact\nrequired-check context/App bindings and strict-update semantics for every\npublic authoritative target, the dual-account authority split, protected\nverifier paths, native review requirements, break-glass constraints, and the\nexplicit trust boundary.\n\n## Trust boundary and non-claims\n\nThe trusted computing base contains GitHub service integrity, retained\norganization-owner recovery custody, the `kungfu-origin` review/governance\nidentity, the exact Buildchain verifier, and official publication identities.\nThe protocol does not claim resistance to compromise of GitHub itself,\ncompromise of all retained owner and recovery anchors, or malicious control of\nall independent trust anchors. A governance receipt grants no GitHub\npermission and is not a bearer credential.\n\n`dongkeren` is the development and pull-request author identity.\n`kungfu-origin` is the independent Code Owner and governance identity. A\nqualifying receipt requires the development identity to be active without an\nadministrator or maintainer role and requires the review identity to retain the\nadmitted governance role. Account recovery and retained root custody remain\noutside normal contributor and workflow paths.\n\n## Effective policy\n\nThe verifier evaluates native provider layers together. Every authoritative\ntarget must require:\n\n- a pull request, at least one independent Code Owner approval, and a fresh\n approval after the latest reviewable push;\n- administrator enforcement, resolved review conversations, and a non-empty\n required-check set whose exact contexts, GitHub App producer identities, and\n strict-update setting match the versioned target policy;\n- no unapproved bypass actor, force push, or protected-ref deletion. Managed\n dev/alpha/release ref bookkeeping may admit only the exact GitHub Actions App\n identity versioned for that target; user and team bypass actors remain\n non-qualifying;\n- exact last-match ownership of CODEOWNERS and the governance descriptor,\n collector, rollout planner, and scheduled audit workflow;\n- complete readable GitHub API evidence. Missing, forbidden, ambiguous, or\n malformed provider state is non-qualifying.\n\nRepository and organization rulesets are additive to classic branch\nprotection. Inspecting only one layer is insufficient because an applicable\nbypass or weaker update path in another layer can invalidate the effective\npolicy.\n\n## Repository and plan admission\n\nThe 2026-07-24 baseline contains 16 managed repositories: 13 public and three\nprivate. Public repository names are versioned in the descriptor. Private\nrepository names are never emitted in public evidence; their identities are\nrepresented by stable roots derived from the GitHub provider repository ID,\nindependent of the governance policy root. This prevents a policy revision from\nchanging repository identity or creating a circular admission dependency. A\nnewly discovered repository or target ref is non-authoritative until explicitly\nadmitted.\n\nThe descriptor also versions every active public merge target. The full audit\nevaluates one receipt per authoritative target rather than assuming the default\nbranch represents dev, alpha, release, or major publish-gate branches. The live\ndefault branch is always included even if it drifts outside the registry, in\nwhich case it is non-qualifying. Retained historical channels and generated\nper-release publish-gate refs are not silently deleted or promoted to current\nauthority; they require an explicit registry revision before they can qualify.\n\nFor an admitted private repository, the active target set is the current\ndefault branch plus existing alpha/release siblings on the same version line.\nIts required-check bindings remain non-qualifying until their sanitized binding\nroots are sealed into the private identity entry after supported native\nprotection exists.\n\nPublic repositories can qualify on supported Free, Team, or Enterprise\nenforcement. Private repositories and organization-wide rules require Team or\nEnterprise capability. On an unsupported plan they remain explicitly\n`non-authoritative-plan-capability-required` and publication-ineligible. The\nverifier does not replace missing native enforcement with CI or documentation,\nand the implementation never makes a private repository public as a\nworkaround.\n\n## Read-only audit\n\nRun the organization audit without mutation:\n\n```bash\nbuildchain audit github-governance \\\n --organization kungfu-systems \\\n --output github-governance.json \\\n --json\n```\n\nLimit a canary to one repository:\n\n```bash\nbuildchain audit github-governance \\\n --repository kungfu-systems/buildchain \\\n --target-ref dev/v2/v2.14 \\\n --require-qualifying \\\n --json\n```\n\nProtected merge and publication consumers verify the receipt against the exact\nrepository, target base ref, policy root, freshness window, and exact\nBuildchain verifier source revision. Non-dry-run publication does not trust a\ncaller-supplied JSON hash: it mints a bounded token for the dedicated read-only\ngovernance auditor GitHub App, recollects live provider state with the exact\nBuildchain runtime, requires the resulting single-repository/single-target\naudit to qualify, and consumes that independently generated receipt. Missing\nApp configuration or unreadable provider state denies publication before\nprovider mutation. The publication authority workflow is itself an explicit\nCode Owner path.\n\nThe output is sanitized. Public repositories retain their public identity.\nPrivate repositories expose only an identity root, visibility class, target\nref, sanitized required-check bindings and fact roots, and a qualifying or\nnon-qualifying decision. Tokens, cookies, recovery material, private\nCODEOWNERS bytes, raw permission payloads, and credential-bearing URLs are\nnever included.\n\n## Mutation and rollback boundary\n\nLive role, ruleset, branch-protection, Actions, Environment, or repository\nchanges are separate from audit. Every mutation starts from a read-only\ninventory and a frozen rollback snapshot. A rollout plan binds both roots and\nlists the exact API operation, impact, expected observation, and inverse\noperation. Apply must stop on the first unexplained drift and must perform a\npost-change read-back before continuing to the next bounded canary.\n\nPlan one exact branch without mutation:\n\n```bash\nbuildchain github-governance plan \\\n --repository kungfu-systems/buildchain \\\n --branch dev/v2/v2.14 \\\n --required-check check \\\n --required-check-app-id check=15368 \\\n --required-approvals 1 \\\n --snapshot-output rollback.json \\\n --plan-output rollout.json\n```\n\nAn already protected check preserves its observed GitHub App binding. Every new\nrequired check must declare `--required-check-app-id <context>=<app-id>`;\ncontext-only replacement is rejected because it would broaden which producer\ncan satisfy the gate.\n\nClassic branch-protection bypass allowances and ruleset bypass actors are both\npart of the effective policy. Reconciliation writes explicit empty user, team,\nand App bypass lists and verifies those lists after apply; omitting the provider\nfield is not treated as removal because GitHub may preserve the prior value.\n\nThe plan prints a `planRoot`. Apply requires that exact root and stops if live\nprotection no longer matches the frozen inventory:\n\n```bash\nbuildchain github-governance apply \\\n --plan-json rollout.json \\\n --confirm-plan-root sha256:...\n```\n\nRollback is separately explicit and root-bound:\n\n```bash\nbuildchain github-governance rollback \\\n --plan-json rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nFor an admitted exact target, classic branch protection can also be compiled\ndirectly from the authority descriptor. This mode preserves both App-bound\nchecks and intentionally unbound check contexts such as Kungfu alpha's\n`build`, rather than guessing a provider App identity.\n\n```bash\nbuildchain github-governance protection-policy-plan \\\n --repository kungfu-systems/kungfu \\\n --branch alpha/v4/v4.0 \\\n --snapshot-output protection-rollback.json \\\n --plan-output protection-rollout.json\n\nbuildchain github-governance protection-policy-apply \\\n --plan-json protection-rollout.json \\\n --confirm-plan-root sha256:...\n\nbuildchain github-governance protection-policy-rollback \\\n --plan-json protection-rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nFor an admitted exact target, repository ruleset reconciliation compiles the\ntarget descriptor into the provider body. It replaces bypass actors with the\nexact provider-admitted desired set, requires fresh Code Owner approval and\nresolved review threads, and binds required checks plus strict-update semantics\nto the target policy. Newly synthesized managed rules include GitHub's explicit\ncanonical defaults so the frozen expected root matches provider read-back.\nRepository rulesets default to no bypass actors. The\ndescriptor's target-bound GitHub Actions allowance is an upper bound on\neffective provider state, not a requirement to add that actor to every\nprotection layer; when needed, the built-in App allowance is expressed by\nclassic branch protection. The target condition must contain exactly one\nbranch; unrelated rules and conditions are preserved in place.\n\n```bash\nbuildchain github-governance ruleset-policy-plan \\\n --repository kungfu-systems/buildchain \\\n --branch alpha/v2/v2.14 \\\n --ruleset-id 19518955 \\\n --snapshot-output ruleset-rollback.json \\\n --plan-output ruleset-rollout.json\n\nbuildchain github-governance ruleset-policy-apply \\\n --plan-json ruleset-rollout.json \\\n --confirm-plan-root sha256:...\n\nbuildchain github-governance ruleset-policy-rollback \\\n --plan-json ruleset-rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nThe narrower `ruleset-plan` mode changes only `bypass_actors`; it remains\navailable for a bypass-only canary, but it cannot prove that an effective\nruleset matches the target descriptor. Both modes require the frozen ruleset\nsnapshot root for rollback.\n\nPaid-plan purchase, billing, legal/account-owner decisions, and any operation\nthat could remove the last recoverable owner remain external human gates.\nBreak-glass is disabled by default and, if ever admitted, must be separately\nauthenticated, reason-bound, time-bounded, independently receipted, and\nfollowed by mandatory restoration and root comparison."
|
|
636
|
+
"markdown": "---\nstatus: draft\nperiod: ongoing\ntheme: github-governance-authority\ndoc_type: protocol\nsource_level: local-files\nconfidence: high\nsensitivity: public\nevidence_grade: B\nreview_state: unreviewed\nlast_reviewed: 2026-07-24\nai_provenance:\n model_family: GPT-5\n product: Codex\n generated_at: 2026-07-24\n limits: Live GitHub state and account recovery remain provider-controlled and must be re-audited.\n---\n\n# GitHub Governance Authority\n\nBuildchain treats GitHub governance as an independently verified, fail-closed\nauthority boundary. A green CI run, a CODEOWNERS file, an API success response,\nor an administrator's assertion is not sufficient by itself. The verifier\ncombines the exact CODEOWNERS bytes from the target base branch, classic branch\nprotection, every applicable repository or organization ruleset, account role\nclasses, plan capability, required checks, and provider-read completeness into\none short-lived immutable receipt.\n\nThe machine contract is\n`@kungfu-tech/buildchain/github-governance-authority`. Its policy root covers\nthe managed-zone repository and target-ref admission rules, the exact\nrequired-check context/App bindings and strict-update semantics for every\npublic authoritative target, the dual-account authority split, protected\nverifier paths, native review requirements, break-glass constraints, and the\nexplicit trust boundary.\n\n## Trust boundary and non-claims\n\nThe trusted computing base contains GitHub service integrity, retained\norganization-owner recovery custody, the `kungfu-origin` review/governance\nidentity, the exact Buildchain verifier, and official publication identities.\nThe protocol does not claim resistance to compromise of GitHub itself,\ncompromise of all retained owner and recovery anchors, or malicious control of\nall independent trust anchors. A governance receipt grants no GitHub\npermission and is not a bearer credential.\n\n`dongkeren` is the development and pull-request author identity.\n`kungfu-origin` is the independent Code Owner and governance identity. A\nqualifying receipt requires the development identity to be active without an\nadministrator or maintainer role and requires the review identity to retain the\nadmitted governance role. Account recovery and retained root custody remain\noutside normal contributor and workflow paths.\n\n## Effective policy\n\nThe verifier evaluates native provider layers together. Every authoritative\ntarget must require:\n\n- a pull request, at least one independent Code Owner approval, and a fresh\n approval after the latest reviewable push;\n- administrator enforcement, resolved review conversations, and a non-empty\n required-check set whose exact contexts, GitHub App producer identities, and\n strict-update setting match the versioned target policy;\n- no unapproved bypass actor, force push, or protected-ref deletion. Managed\n dev/alpha/release ref bookkeeping may admit only the exact GitHub Actions App\n identity versioned for that target; user and team bypass actors remain\n non-qualifying;\n- exact last-match ownership of CODEOWNERS and the governance descriptor,\n collector, rollout planner, and scheduled audit workflow;\n- complete readable GitHub API evidence. Missing, forbidden, ambiguous, or\n malformed provider state is non-qualifying.\n\nRepository and organization rulesets are additive to classic branch\nprotection. Inspecting only one layer is insufficient because an applicable\nbypass or weaker update path in another layer can invalidate the effective\npolicy.\n\n## Repository and plan admission\n\nThe 2026-07-24 baseline contains 16 managed repositories: 13 public and three\nprivate. Public repository names are versioned in the descriptor. Private\nrepository names are never emitted in public evidence; their identities are\nrepresented by stable roots derived from the GitHub provider repository ID,\nindependent of the governance policy root. This prevents a policy revision from\nchanging repository identity or creating a circular admission dependency. A\nnewly discovered repository or target ref is non-authoritative until explicitly\nadmitted.\n\nThe descriptor also versions every active public merge target. The full audit\nevaluates one receipt per authoritative target rather than assuming the default\nbranch represents dev, alpha, release, or major publish-gate branches. The live\ndefault branch is always included even if it drifts outside the registry, in\nwhich case it is non-qualifying. Retained historical channels and generated\nper-release publish-gate refs are not silently deleted or promoted to current\nauthority; they require an explicit registry revision before they can qualify.\n\nFor an admitted private repository, the active target set is the current\ndefault branch plus existing alpha/release siblings on the same version line.\nIts required-check bindings remain non-qualifying until their sanitized binding\nroots are sealed into the private identity entry after supported native\nprotection exists.\n\nPublic repositories can qualify on supported Free, Team, or Enterprise\nenforcement. Private repositories and organization-wide rules require Team or\nEnterprise capability. On an unsupported plan they remain explicitly\n`non-authoritative-plan-capability-required` and publication-ineligible. The\nverifier does not replace missing native enforcement with CI or documentation,\nand the implementation never makes a private repository public as a\nworkaround.\n\n## Read-only audit\n\nRun the organization audit without mutation:\n\n```bash\nbuildchain audit github-governance \\\n --organization kungfu-systems \\\n --output github-governance.json \\\n --json\n```\n\nLimit a canary to one repository:\n\n```bash\nbuildchain audit github-governance \\\n --repository kungfu-systems/buildchain \\\n --target-ref dev/v2/v2.14 \\\n --require-qualifying \\\n --json\n```\n\nProtected merge and publication consumers verify the receipt against the exact\nrepository, target base ref, policy root, freshness window, and exact\nBuildchain verifier source revision. Non-dry-run publication does not trust a\ncaller-supplied JSON hash: it mints a bounded token for the dedicated read-only\ngovernance auditor GitHub App, recollects live provider state with the exact\nBuildchain runtime, requires the resulting single-repository/single-target\naudit to qualify, and consumes that independently generated receipt. Missing\nApp configuration or unreadable provider state denies publication before\nprovider mutation. The publication authority workflow is itself an explicit\nCode Owner path.\n\nThe publication authority job and every reusable-workflow caller grant the\nbuilt-in `GITHUB_TOKEN` only `actions: read`, `checks: read`, `contents: read`,\nand `pull-requests: read`. The dedicated auditor App independently recollects\nthe organization-wide governance receipt, while these job-scoped permissions\nallow the exact publication transaction audit to resolve required check runs\nand merged pull-request review lineage. Omitting either read permission makes\nthe transaction evidence incomplete and therefore non-qualifying.\n\nThe output is sanitized. Public repositories retain their public identity.\nPrivate repositories expose only an identity root, visibility class, target\nref, sanitized required-check bindings and fact roots, and a qualifying or\nnon-qualifying decision. Tokens, cookies, recovery material, private\nCODEOWNERS bytes, raw permission payloads, and credential-bearing URLs are\nnever included.\n\n## Mutation and rollback boundary\n\nLive role, ruleset, branch-protection, Actions, Environment, or repository\nchanges are separate from audit. Every mutation starts from a read-only\ninventory and a frozen rollback snapshot. A rollout plan binds both roots and\nlists the exact API operation, impact, expected observation, and inverse\noperation. Apply must stop on the first unexplained drift and must perform a\npost-change read-back before continuing to the next bounded canary.\n\nPlan one exact branch without mutation:\n\n```bash\nbuildchain github-governance plan \\\n --repository kungfu-systems/buildchain \\\n --branch dev/v2/v2.14 \\\n --required-check check \\\n --required-check-app-id check=15368 \\\n --required-approvals 1 \\\n --snapshot-output rollback.json \\\n --plan-output rollout.json\n```\n\nAn already protected check preserves its observed GitHub App binding. Every new\nrequired check must declare `--required-check-app-id <context>=<app-id>`;\ncontext-only replacement is rejected because it would broaden which producer\ncan satisfy the gate.\n\nClassic branch-protection bypass allowances and ruleset bypass actors are both\npart of the effective policy. Reconciliation writes explicit empty user, team,\nand App bypass lists and verifies those lists after apply; omitting the provider\nfield is not treated as removal because GitHub may preserve the prior value.\n\nThe plan prints a `planRoot`. Apply requires that exact root and stops if live\nprotection no longer matches the frozen inventory:\n\n```bash\nbuildchain github-governance apply \\\n --plan-json rollout.json \\\n --confirm-plan-root sha256:...\n```\n\nRollback is separately explicit and root-bound:\n\n```bash\nbuildchain github-governance rollback \\\n --plan-json rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nFor an admitted exact target, classic branch protection can also be compiled\ndirectly from the authority descriptor. This mode preserves both App-bound\nchecks and intentionally unbound check contexts such as Kungfu alpha's\n`build`, rather than guessing a provider App identity.\n\n```bash\nbuildchain github-governance protection-policy-plan \\\n --repository kungfu-systems/kungfu \\\n --branch alpha/v4/v4.0 \\\n --snapshot-output protection-rollback.json \\\n --plan-output protection-rollout.json\n\nbuildchain github-governance protection-policy-apply \\\n --plan-json protection-rollout.json \\\n --confirm-plan-root sha256:...\n\nbuildchain github-governance protection-policy-rollback \\\n --plan-json protection-rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nFor an admitted exact target, repository ruleset reconciliation compiles the\ntarget descriptor into the provider body. It replaces bypass actors with the\nexact provider-admitted desired set, requires fresh Code Owner approval and\nresolved review threads, and binds required checks plus strict-update semantics\nto the target policy. Newly synthesized managed rules include GitHub's explicit\ncanonical defaults so the frozen expected root matches provider read-back.\nRepository rulesets default to no bypass actors. The\ndescriptor's target-bound GitHub Actions allowance is an upper bound on\neffective provider state, not a requirement to add that actor to every\nprotection layer; when needed, the built-in App allowance is expressed by\nclassic branch protection. The target condition must contain exactly one\nbranch; unrelated rules and conditions are preserved in place.\n\n```bash\nbuildchain github-governance ruleset-policy-plan \\\n --repository kungfu-systems/buildchain \\\n --branch alpha/v2/v2.14 \\\n --ruleset-id 19518955 \\\n --snapshot-output ruleset-rollback.json \\\n --plan-output ruleset-rollout.json\n\nbuildchain github-governance ruleset-policy-apply \\\n --plan-json ruleset-rollout.json \\\n --confirm-plan-root sha256:...\n\nbuildchain github-governance ruleset-policy-rollback \\\n --plan-json ruleset-rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nThe narrower `ruleset-plan` mode changes only `bypass_actors`; it remains\navailable for a bypass-only canary, but it cannot prove that an effective\nruleset matches the target descriptor. Both modes require the frozen ruleset\nsnapshot root for rollback.\n\nPaid-plan purchase, billing, legal/account-owner decisions, and any operation\nthat could remove the last recoverable owner remain external human gates.\nBreak-glass is disabled by default and, if ever admitted, must be separately\nauthenticated, reason-bound, time-bounded, independently receipted, and\nfollowed by mandatory restoration and root comparison."
|
|
637
637
|
},
|
|
638
638
|
{
|
|
639
639
|
"id": "manual:homebrew",
|
|
@@ -1324,7 +1324,7 @@
|
|
|
1324
1324
|
],
|
|
1325
1325
|
"maturity": "stable",
|
|
1326
1326
|
"sourcePath": "docs/publish-transaction.md",
|
|
1327
|
-
"digest": "sha256:
|
|
1327
|
+
"digest": "sha256:cde5256d5f6443a6d32b47783900a0677e973855266af5a360db8d4d112bb677",
|
|
1328
1328
|
"headings": [
|
|
1329
1329
|
{
|
|
1330
1330
|
"level": 1,
|
|
@@ -1387,7 +1387,7 @@
|
|
|
1387
1387
|
"anchor": "build-images-follow-up"
|
|
1388
1388
|
}
|
|
1389
1389
|
],
|
|
1390
|
-
"markdown": "# Publish Transaction\n\nBuildchain release promotion is not just tag movement. A release can also publish\nexternal artifacts: npm packages, Python wheels, OCI images, binary archives,\nmetadata manifests, or site deployment records. Those side effects are harder\nthan Git refs because most registries are append-only: a failed rerun must know\nwhich artifacts already exist, which are still missing, and whether any existing\nartifact conflicts with the release material.\n\nBuildchain v2 models that work as a release transaction.\n\n## Why This Exists\n\nThe old ABV workflow made Git refs the visible release authority. That was\nenough when \"release\" meant \"create a version commit, move tags, and let\ndownstream jobs react.\" It is not enough when a single publish run must also\nupload packages and images.\n\nThe failure mode to avoid is:\n\n1. publish an external artifact;\n2. fail before moving the exact release tag or floating channel refs;\n3. rerun from a new job id with no memory of the artifact;\n4. either republish something different or move refs without proving the\n already-published artifact matches the release.\n\nThe transaction gives reruns a stable identity and a machine-readable state so\nBuildchain can resume safely. The identity is:\n\n```text\nrepository + version + source_sha + target_ref\n```\n\nIt is not the GitHub Actions run id.\n\n## Durable State\n\n`actions/promote-buildchain-ref` stores release transaction state in a\nmachine-managed Git branch:\n\n```text\nrefs/heads/buildchain/release-state/<version>\n```\n\nThe branch contains:\n\n```text\nstate.json\nevidence.json # present after publish evidence exists\n```\n\nThe local `.buildchain/release-state/...` and\n`.buildchain/release-evidence/...` files are working copies. They are useful for\nlocal inspection and lifecycle commands, but they are not the durable truth for\nGitHub-hosted reruns. On action startup, Buildchain reads the durable state ref\nfirst, restores the local working copies, and only then decides whether to\npublish, repair, or finalize.\n\nEvery meaningful state transition is written to the durable ref before public\nrelease refs move. Release-state GitHub API reads and writes use retry/backoff\nfor transient service failures such as HTTP 5xx responses, connection resets,\ntimeouts, and \"other side closed\" socket failures. If the durable write still\ncannot be persisted after retries, the action fails closed.\n\nDurable release-state refs reserve their exact version even when the public exact\ntag was never created. If a later machine run sees a failed or repair-required\nstate for `vX.Y.Z-alpha.N` and cannot resume it with the same transaction\nidentity, alpha version selection must advance to the next prerelease instead\nof reusing or overwriting that failed transaction slot.\n\n## Lifecycle\n\nRepositories declare publish work in `.buildchain/buildchain.toml`:\n\n```toml\n[publish]\nmode = \"publish-final-version\"\nauth = \"trusted-publishing\"\ndist_tag = \"latest\"\npackage_set_order = \"platforms-first-main-last\"\nmain_package = \"@kungfu-tech/libnode\"\n\n[lifecycle.publish]\ncommands = [\n \"python scripts/publish_wheels.py\",\n \"node scripts/publish-images.mjs\",\n \"node scripts/write-publish-evidence.mjs\",\n]\n```\n\n`actions/promote-buildchain-ref` runs `lifecycle.publish` only when\n`publish-transaction: \"true\"` is set or when a `publish-command` input is\nprovided. The action sets:\n\n```text\nBUILDCHAIN_VERSION\nBUILDCHAIN_CHANNEL\nBUILDCHAIN_SOURCE_SHA\nBUILDCHAIN_TARGET_REF\nBUILDCHAIN_RELEASE_STATE\nBUILDCHAIN_EVIDENCE_DIR\nBUILDCHAIN_RELEASE_SHA\nBUILDCHAIN_RELEASE_MATERIAL_SHA\nBUILDCHAIN_PUBLISH_TOOLING_SHA\nBUILDCHAIN_PUBLISH_EVIDENCE\nBUILDCHAIN_REQUIRED_ARTIFACTS\nBUILDCHAIN_PUBLISH_MODE\nBUILDCHAIN_PUBLISH_AUTH\nBUILDCHAIN_NPM_DIST_TAG\nBUILDCHAIN_PACKAGE_SET_ORDER\nBUILDCHAIN_PACKAGE_SET_MAIN_PACKAGE\n```\n\nBuildchain itself uses this contract for npm publishing:\n\n```toml\n[lifecycle.publish]\ncommand = \"node scripts/npm-publish-transaction.mjs\"\n```\n\nThat script validates that `package.json` matches `BUILDCHAIN_VERSION`, runs\n`npm publish --access public --tag <BUILDCHAIN_NPM_DIST_TAG>` through npm Trusted\nPublishing, and writes npm artifact evidence before the promotion action moves\npublic refs.\n\n`BUILDCHAIN_RELEASE_MATERIAL_SHA` is the source material whose artifacts must\nmatch. `BUILDCHAIN_PUBLISH_TOOLING_SHA` identifies the publishing code. A repair\nrun may change tooling, but material drift fails closed.\n\n## Post-Publish Requirements And Artifact Provenance\n\n`publish-required-artifacts-json` is a pre-publish family declaration, not a\nrequest to guess registry digests. A descriptor must include `kind + name`; it\nmay omit `ref` and `digest`. The action resolves a missing `ref` to the exact\n`BUILDCHAIN_VERSION`. Registries whose exact refs add a stable prefix or suffix\nmay instead declare a `ref_template` containing exactly one `{version}`, such\nas `v{version}`. The template is expanded only after exact version selection,\nso a resumed alpha transaction receives the newly selected prerelease rather\nthan the checked-out version. Declaring both `ref` and `ref_template`, using\nanother placeholder, or leaving unmatched braces fails before\n`lifecycle.publish`. The action exports the normalized exact refs as\n`BUILDCHAIN_REQUIRED_ARTIFACTS`, runs `lifecycle.publish`, and then requires the\nfinal evidence to contain every exact member with a non-empty digest. Existing\ncallers may continue supplying exact refs and digests.\n\nOCI publishers can opt into strict per-artifact provenance by adding\n`action: built` or `action: reused`. Those artifacts carry two separate\ncoordinates:\n\n- `content`: the version, ref, source SHA, and material SHA that produced the\n immutable content;\n- `release`: the exact current version/ref, target ref, source SHA, and release\n material SHA that bind that content into this release.\n\nThis distinction permits truthful cross-version reuse without claiming that an\nold OCI config was rebuilt from current material. For an OCI artifact with an\naction, final evidence also requires `platform`, positive `contract_major`, and\n`verification` containing a public manifest result, exact ref and digest,\nplatform, contract major, optional parent digest, evidence location, and a\npassed named smoke policy. Buildchain cross-checks those values against the\nartifact and current transaction. Missing family members and ref, digest,\ncontent, release, or verification conflicts enter `repair_required` before\npublic refs move.\n\nExample reused OCI evidence entry (the pre-publish requirement may omit\n`ref`, `digest`, `release`, and the observed verification values):\n\n```json\n{\n \"group\": \"image\",\n \"kind\": \"oci\",\n \"name\": \"ghcr.io/kungfu-systems/base-linux\",\n \"ref\": \"1.2.0-alpha.3\",\n \"digest\": \"sha256:...\",\n \"action\": \"reused\",\n \"platform\": \"linux/amd64\",\n \"contract_major\": 1,\n \"content\": {\n \"version\": \"1.1.9\",\n \"ref\": \"1.1.9\",\n \"source_sha\": \"<source-sha>\",\n \"material_sha\": \"<material-sha>\"\n },\n \"release\": {\n \"version\": \"1.2.0-alpha.3\",\n \"ref\": \"1.2.0-alpha.3\",\n \"target_ref\": \"alpha/v1/v1.2\",\n \"source_sha\": \"<current-source-sha>\",\n \"material_sha\": \"<current-material-sha>\"\n },\n \"verification\": {\n \"public_manifest\": true,\n \"ref\": \"1.2.0-alpha.3\",\n \"digest\": \"sha256:...\",\n \"platform\": \"linux/amd64\",\n \"contract_major\": 1,\n \"evidence\": \"registry-inspect.json\",\n \"smoke\": {\n \"policy\": \"manifest-contract\",\n \"passed\": true,\n \"evidence\": \"smoke.json\"\n }\n }\n}\n```\n\n## Release Modes And Auth\n\nBuildchain distinguishes two npm release modes:\n\n| Mode | Use | Auth | npm operation |\n| --- | --- | --- | --- |\n| `publish-final-version` | normal alpha or stable publication | `trusted-publishing` | `npm publish --tag <alpha|vX.Y-alpha|latest>` |\n| `promote-existing-version` | same-version alpha-to-latest recovery | `npm-token` | `npm dist-tag add <pkg>@<version> latest` |\n\nThe normal libnode path is `publish-final-version`: publish an alpha package set\nsuch as `22.22.3-kf.3-alpha.0` with the `alpha` dist-tag, then publish a\ndistinct final package set such as `22.22.3-kf.3` with the `latest` dist-tag.\nGitHub-hosted npm Trusted Publishing can authorize those `npm publish` calls\nwhen the workflow grants `id-token: write`.\n\n`promote-existing-version` is deliberately separate. npm Trusted Publishing does\nnot authorize arbitrary registry-management operations such as `npm dist-tag\nadd`; it authorizes publish-time package provenance. Therefore same-version\npromotion must declare `auth = \"npm-token\"`. Buildchain runs an npm token\npreflight with `npm whoami` before it writes any release transaction state or\nmoves a dist-tag. Missing token auth fails early with a contract error instead\nof a late `E401` after publish evidence has started to move.\n\nFor package sets, `package_set_order = \"platforms-first-main-last\"` makes the\nmain package the visibility gate. Platform package side effects are planned or\nretried first, and the main package or main dist-tag move happens last.\n\nWhen the transaction reaches `complete`, `actions/promote-buildchain-ref`\ngenerates `.buildchain/release-passport/buildchain.release.json` and persists\nthe `release-passport/*` files into the durable `buildchain/release-state/...`\nref. The passport is the stable release artifact for agents and people: it\nlinks the package set, npm publish evidence, dist-tag evidence, build summary,\nplatform artifact manifests, trusted publishing metadata, release-state ref,\ndurable release-state SHA, and transaction result in one schema. Consumer\nrepositories can set `release-passport-product-name` so the passport names their\nproduct instead of the Buildchain default.\n\n## Evidence\n\nThe publish lifecycle must write JSON evidence. Buildchain validates common\nfields and required artifact identities before final refs move.\n\n```json\n{\n \"schema\": 1,\n \"version\": \"2.0.11\",\n \"channel\": \"release\",\n \"source_sha\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"release_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"target_ref\": \"release/v2/v2.0\",\n \"release_material_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"publish_tooling_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"artifacts\": [\n {\n \"group\": \"node\",\n \"kind\": \"npm\",\n \"name\": \"@kungfu-systems/example\",\n \"ref\": \"2.0.11\",\n \"digest\": \"sha256:...\"\n },\n {\n \"group\": \"image\",\n \"kind\": \"oci\",\n \"name\": \"ghcr.io/kungfu-systems/example\",\n \"ref\": \"2.0.11\",\n \"digest\": \"sha256:...\"\n }\n ]\n}\n```\n\nThe generic contract is intentionally small:\n\n- `version`, `channel`, `source_sha`, `release_sha`, and `target_ref` must match\n the promotion run;\n- dist-tag promotion evidence is written beside the publish evidence as\n `dist-tag-evidence.json` and is referenced from the generated passport;\n- required artifacts must appear in evidence;\n- evidence used by a GitHub-hosted rerun must either be stored in the durable\n state ref or be reconstructed by a machine-verifiable consumer command;\n- existing artifacts with the same identity and digest are accepted on rerun;\n- missing artifacts can be published by the next run;\n- an existing artifact with a different digest puts the transaction into\n `repair_required`.\n\nArtifact identity is `group + kind + name + ref`. A required artifact that omits\n`group` matches any group with the same `kind + name + ref`.\n\n## Registry Truth Contract\n\nBuildchain owns transaction orchestration, finalization ordering, durable state,\nand generic evidence validation. It does not embed registry clients for npm,\nPyPI, GHCR/OCI, GitHub Releases, S3, Conan, CMake packaging, or project-specific\ndownload pages.\n\nConsumer `lifecycle.publish` commands own registry truth. A valid consumer stage\nmust be idempotent and machine-verifiable:\n\n- inspect the target registry before publishing;\n- accept an existing exact artifact only when version, identity, digest, and\n release-source binding match;\n- publish missing required artifacts;\n- reject conflicting existing artifacts and write evidence that lets Buildchain\n move the transaction to `repair_required`;\n- write `BUILDCHAIN_PUBLISH_EVIDENCE` after every successful inspect/publish\n cycle;\n- leave floating aliases such as npm dist-tags, PyPI stable markers, OCI\n floating tags, GitHub Release \"published\" status, or download-page stable\n links to a finalization step after Buildchain evidence validation.\n\nThe first-class adapter surface is command-based. Projects may wrap npm, PyPI,\nGHCR/OCI, GitHub Release assets, archives, SBOMs, provenance, or checksums\nhowever they need, as long as they emit the common evidence contract.\n\n## States\n\nThe state machine is:\n\n```text\nprepared -> publishing -> published -> finalizing -> complete\n | | |\n v v v\n publish_failed repair_required failed_permanently\n |\n v\n abandoned\n```\n\nSupported states:\n\n| State | Meaning |\n| --- | --- |\n| `prepared` | Transaction identity was created, but publish has not started. |\n| `publishing` | Publish lifecycle is running or may have been interrupted. |\n| `publish_failed` | Publish command failed before valid evidence was produced. |\n| `published` | Evidence is valid; refs have not necessarily finalized. |\n| `finalizing` | Buildchain is moving exact/floating refs or needs a later run to do it. |\n| `complete` | Required evidence is valid and refs have finalized. |\n| `repair_required` | Existing evidence or artifact state conflicts with expected release material. |\n| `abandoned` | A human or controlled process abandoned this transaction, usually because a newer version supersedes it. |\n| `failed_permanently` | Recovery should not continue without explicit override. |\n\n`repair_required`, `abandoned`, and `failed_permanently` fail closed unless the\noperator passes an explicit override. That override is for controlled repair\nruns, not normal retry behavior.\n\n## Ref Ordering\n\nWhen publish transactions are enabled, promotion order is:\n\n1. verify target source and governance;\n2. create or reuse the version-state release commit;\n3. acquire or resume the release transaction;\n4. run `lifecycle.publish` or accept already-valid evidence;\n5. validate evidence and required artifacts;\n6. move exact release/prerelease tag;\n7. move floating tags and channel refs;\n8. mark the transaction `complete`.\n\nConsumer products that expose a signed well-known channel can opt into one\nadditional, deliberately final step with `publication-commit-command`. Before\nthat command runs, Buildchain has already completed the transaction, created\nthe public GitHub Release, and uploaded every release-passport file plus the\nexplicit PR-stage payload files selected by\n`github-release-payload-patterns`. The command is therefore a commit point for\ndiscovery authority, not another artifact publisher.\n\nThe command receives the exact version, source SHA, release SHA, release tag,\nrelease passport path, and downloaded payload directory through\n`BUILDCHAIN_PUBLICATION_COMMIT_*`. Optional consumer-owned dispatch/API\ncredentials and private signing material are exposed separately as\n`BUILDCHAIN_PUBLICATION_COMMIT_TOKEN` and\n`BUILDCHAIN_PUBLICATION_COMMIT_SIGNING_KEY`; Buildchain never logs, persists,\nor interprets either value. The command must write\n`.buildchain/publication-commit/evidence.json` (or another declared path below\n`.buildchain/`) with this contract:\n\n```json\n{\n \"schema\": \"kungfu-buildchain-publication-commit-evidence/v1\",\n \"status\": \"passed\",\n \"identity\": {\n \"version\": \"4.0.0-alpha.2\",\n \"sourceSha\": \"<source-sha>\",\n \"releaseSha\": \"<release-sha>\",\n \"releaseTag\": \"v4.0.0-alpha.2\"\n },\n \"publication\": {\n \"url\": \"https://example.test/.well-known/product/alpha.json\",\n \"payloadRoot\": \"sha256:<64-lowercase-hex>\"\n },\n \"readback\": {\n \"status\": \"passed\",\n \"url\": \"https://example.test/.well-known/product/alpha.json\",\n \"payloadRoot\": \"sha256:<same-root>\"\n },\n \"recovery\": {\n \"previousAuthority\": \"preserved\",\n \"rollbackReference\": \"sha256:<previous-root>\"\n }\n}\n```\n\nBuildchain rejects stale evidence, identity drift, non-public or mutable URLs,\nread-back root drift, and missing recovery evidence. It also rejects\n`standalone-binary-distribution=true` with a final commit command because that\nwould queue product mutations after the authority moved. On any command or\nread-back failure, the consumer must leave the previous well-known document\nauthoritative; Buildchain does not retry the command behind a successful\nreceipt.\n\nIf protected branch finalization is interrupted after publish evidence is\nvalid, the transaction can stop in `finalizing` and output\n`finalization-needed=true`. A later run resumes from the same transaction state\nand completes ref movement without republishing matching artifacts. New\nBuildchain-managed promotions first try to finish generated version-state\nbookkeeping with the promotion token directly. Before patching a protected\ngenerated bookkeeping ref, Buildchain emits every configured required check on\nthe exact generated version-state commit so branch protection can\nvalidate the automation path without a second build, then uses the generated\nref update token for the protected ref PATCH. If release finalization\nbookkeeping is still rejected, Buildchain creates or reuses a same-repository\n`buildchain/version-state/*` PR and leaves the transaction resumable with\n`finalization-needed=true`. Strict alpha uses the same protected PR fallback\nfor both its target channel and subsequent dev reconciliation. A later\nidempotent run continues only after the provider shows that the PR reached the\nprotected branch. The reusable wrapper binds that token to the run-scoped\n`github.token` and rejects user, team, or alternate App bypass actors.\n\nIf finalization fails after an exact Git tag, a channel branch, or dev/alpha\nsync ref has already moved, the next run reads the durable `finalizing` state\nand continues from the recorded transaction. The current workflow SHA may be a\ngenerated version-state commit, or a historical version-state merge commit, that\ncontains or corresponds to the transaction's `release_material_sha`; it does not\nhave to equal the original `source_sha` or the transaction `release_sha`. Exact\ntags are accepted when they already point at the transaction release/material\nSHA or the finalized channel head. Floating\nchannel tags and dev/alpha refs are then retried idempotently, and the\ntransaction is marked `complete` only after those public refs are consistent.\nWriting `complete` clears any stale `failure` value from earlier attempts, so\nthe durable `state.json` represents the successful final state instead of the\nlast transient error seen before a rerun.\nAn exact tag at an unrelated SHA is still a material conflict and blocks\nrecovery.\n\nFor anchored package versions, the package version and internal line tag are\nseparate transaction coordinates. A retry can correct a stale internal tag on\nan unfinished `published` or `finalizing` transaction only when its validated\nevidence and complete artifact set match the same package version, source,\nrelease material, and target. Buildchain additionally requires that the stale\ntag does not already point at the transaction and that the newly selected tag\nis unclaimed or already points at accepted release material. No registry publish\ncommand is rerun during this exact-tag rebind.\n\nGoverned retries distinguish unrelated channel advancement from advancement\nmade by their own durable transaction. An unrelated descendant remains an\nauditable `superseded-promotion` no-op. When the target ref is exactly the\nrecorded `release_sha` for the requested source, target, and expected version,\nBuildchain resumes finalization, restores publish evidence, and emits the\nrelease-passport paths needed by downstream controller receipts.\n\nPublication authority planning applies the same occupied-version rule as the\nlater mutation step. If a current alpha transaction already contains published\nmaterial and regenerating version state would create new release material, the\nplanner advances to the next alpha before sealing authority. It never seals the\nold published version and then lets the publisher discover a different version\ninside the mutation boundary.\n\nIf finalization fails after an exact Git tag is created, the next run reads the\ndurable `finalizing` state, verifies the exact tag points at the recorded\nrelease SHA, and retries the remaining floating refs. An exact tag at a\ndifferent SHA is a material conflict and blocks recovery.\n\n## CLI Recovery\n\nLocal recovery commands operate on the same state/evidence files:\n\n```bash\nnode scripts/release-transaction.mjs inspect --version v2.0.11\nnode scripts/release-transaction.mjs recover --version v2.0.11\nnode scripts/release-transaction.mjs finalize --version v2.0.11\nnode scripts/release-transaction.mjs abort --version v2.0.11 --superseded-by v2.0.12\n```\n\nThe CLI is a diagnostic and local repair surface. It reports the durable\n`state_ref`, but remote durable-ref writes and public Git ref finalization are\nowned by `actions/promote-buildchain-ref`, because that action runs inside the\nsame governed GitHub permissions and branch-protection checks as release\npromotion. In other words, CLI `finalize` can mark the local transaction state\ncomplete after valid evidence; the machine-operated public finalization path is\nto rerun the promotion action.\n\nWhen no state file exists, creation commands also require:\n\n```bash\n--repository kungfu-systems/buildchain \\\n--source-sha <sha> \\\n--release-sha <sha> \\\n--target-ref release/v2/v2.0 \\\n--channel release\n```\n\n## Build-Images Follow-Up\n\n`build-images` should consume this contract rather than inventing a separate\nworkflow rule. The expected integration shape is:\n\n- image build writes OCI digests into publish evidence;\n- required image families are passed through `publish-required-artifacts-json`\n before their final digests are known;\n- mixed built/reused evidence preserves content provenance separately from the\n current release binding;\n- reruns check GHCR or the target registry and accept existing images only when\n tag and digest match;\n- preview or alpha image tags remain non-stable until the transaction evidence\n validates;\n- production image aliases move only after all required image artifacts are\n present and the Buildchain exact release tag has finalized."
|
|
1390
|
+
"markdown": "# Publish Transaction\n\nBuildchain release promotion is not just tag movement. A release can also publish\nexternal artifacts: npm packages, Python wheels, OCI images, binary archives,\nmetadata manifests, or site deployment records. Those side effects are harder\nthan Git refs because most registries are append-only: a failed rerun must know\nwhich artifacts already exist, which are still missing, and whether any existing\nartifact conflicts with the release material.\n\nBuildchain v2 models that work as a release transaction.\n\n## Why This Exists\n\nThe old ABV workflow made Git refs the visible release authority. That was\nenough when \"release\" meant \"create a version commit, move tags, and let\ndownstream jobs react.\" It is not enough when a single publish run must also\nupload packages and images.\n\nThe failure mode to avoid is:\n\n1. publish an external artifact;\n2. fail before moving the exact release tag or floating channel refs;\n3. rerun from a new job id with no memory of the artifact;\n4. either republish something different or move refs without proving the\n already-published artifact matches the release.\n\nThe transaction gives reruns a stable identity and a machine-readable state so\nBuildchain can resume safely. The identity is:\n\n```text\nrepository + version + source_sha + target_ref\n```\n\nIt is not the GitHub Actions run id.\n\n## Durable State\n\n`actions/promote-buildchain-ref` stores release transaction state in a\nmachine-managed Git branch:\n\n```text\nrefs/heads/buildchain/release-state/<version>\n```\n\nThe branch contains:\n\n```text\nstate.json\nevidence.json # present after publish evidence exists\n```\n\nThe local `.buildchain/release-state/...` and\n`.buildchain/release-evidence/...` files are working copies. They are useful for\nlocal inspection and lifecycle commands, but they are not the durable truth for\nGitHub-hosted reruns. On action startup, Buildchain reads the durable state ref\nfirst, restores the local working copies, and only then decides whether to\npublish, repair, or finalize.\n\nEvery meaningful state transition is written to the durable ref before public\nrelease refs move. Release-state GitHub API reads and writes use retry/backoff\nfor transient service failures such as HTTP 5xx responses, connection resets,\ntimeouts, and \"other side closed\" socket failures. If the durable write still\ncannot be persisted after retries, the action fails closed.\n\nDurable release-state refs reserve their exact version even when the public exact\ntag was never created. If a later machine run sees a failed or repair-required\nstate for `vX.Y.Z-alpha.N` and cannot resume it with the same transaction\nidentity, alpha version selection must advance to the next prerelease instead\nof reusing or overwriting that failed transaction slot.\n\n## Lifecycle\n\nRepositories declare publish work in `.buildchain/buildchain.toml`:\n\n```toml\n[publish]\nmode = \"publish-final-version\"\nauth = \"trusted-publishing\"\ndist_tag = \"latest\"\npackage_set_order = \"platforms-first-main-last\"\nmain_package = \"@kungfu-tech/libnode\"\n\n[lifecycle.publish]\ncommands = [\n \"python scripts/publish_wheels.py\",\n \"node scripts/publish-images.mjs\",\n \"node scripts/write-publish-evidence.mjs\",\n]\n```\n\n`actions/promote-buildchain-ref` runs `lifecycle.publish` only when\n`publish-transaction: \"true\"` is set or when a `publish-command` input is\nprovided. The action sets:\n\n```text\nBUILDCHAIN_VERSION\nBUILDCHAIN_CHANNEL\nBUILDCHAIN_SOURCE_SHA\nBUILDCHAIN_TARGET_REF\nBUILDCHAIN_RELEASE_STATE\nBUILDCHAIN_EVIDENCE_DIR\nBUILDCHAIN_RELEASE_SHA\nBUILDCHAIN_RELEASE_MATERIAL_SHA\nBUILDCHAIN_PUBLISH_TOOLING_SHA\nBUILDCHAIN_PUBLISH_EVIDENCE\nBUILDCHAIN_REQUIRED_ARTIFACTS\nBUILDCHAIN_PUBLISH_MODE\nBUILDCHAIN_PUBLISH_AUTH\nBUILDCHAIN_NPM_DIST_TAG\nBUILDCHAIN_PACKAGE_SET_ORDER\nBUILDCHAIN_PACKAGE_SET_MAIN_PACKAGE\n```\n\nBuildchain itself uses this contract for npm publishing:\n\n```toml\n[lifecycle.publish]\ncommand = \"node scripts/npm-publish-transaction.mjs\"\n```\n\nThat script validates that `package.json` matches `BUILDCHAIN_VERSION`, runs\n`npm publish --access public --tag <BUILDCHAIN_NPM_DIST_TAG>` through npm Trusted\nPublishing, and writes npm artifact evidence before the promotion action moves\npublic refs.\n\n`BUILDCHAIN_RELEASE_MATERIAL_SHA` is the source material whose artifacts must\nmatch. `BUILDCHAIN_PUBLISH_TOOLING_SHA` identifies the publishing code. A repair\nrun may change tooling, but material drift fails closed.\n\n## Post-Publish Requirements And Artifact Provenance\n\n`publish-required-artifacts-json` is a pre-publish family declaration, not a\nrequest to guess registry digests. A descriptor must include `kind + name`; it\nmay omit `ref` and `digest`. The action resolves a missing `ref` to the exact\n`BUILDCHAIN_VERSION`. Registries whose exact refs add a stable prefix or suffix\nmay instead declare a `ref_template` containing exactly one `{version}`, such\nas `v{version}`. The template is expanded only after exact version selection,\nso a resumed alpha transaction receives the newly selected prerelease rather\nthan the checked-out version. Declaring both `ref` and `ref_template`, using\nanother placeholder, or leaving unmatched braces fails before\n`lifecycle.publish`. The action exports the normalized exact refs as\n`BUILDCHAIN_REQUIRED_ARTIFACTS`, runs `lifecycle.publish`, and then requires the\nfinal evidence to contain every exact member with a non-empty digest. Existing\ncallers may continue supplying exact refs and digests.\n\nOCI publishers can opt into strict per-artifact provenance by adding\n`action: built` or `action: reused`. Those artifacts carry two separate\ncoordinates:\n\n- `content`: the version, ref, source SHA, and material SHA that produced the\n immutable content;\n- `release`: the exact current version/ref, target ref, source SHA, and release\n material SHA that bind that content into this release.\n\nThis distinction permits truthful cross-version reuse without claiming that an\nold OCI config was rebuilt from current material. For an OCI artifact with an\naction, final evidence also requires `platform`, positive `contract_major`, and\n`verification` containing a public manifest result, exact ref and digest,\nplatform, contract major, optional parent digest, evidence location, and a\npassed named smoke policy. Buildchain cross-checks those values against the\nartifact and current transaction. Missing family members and ref, digest,\ncontent, release, or verification conflicts enter `repair_required` before\npublic refs move.\n\nExample reused OCI evidence entry (the pre-publish requirement may omit\n`ref`, `digest`, `release`, and the observed verification values):\n\n```json\n{\n \"group\": \"image\",\n \"kind\": \"oci\",\n \"name\": \"ghcr.io/kungfu-systems/base-linux\",\n \"ref\": \"1.2.0-alpha.3\",\n \"digest\": \"sha256:...\",\n \"action\": \"reused\",\n \"platform\": \"linux/amd64\",\n \"contract_major\": 1,\n \"content\": {\n \"version\": \"1.1.9\",\n \"ref\": \"1.1.9\",\n \"source_sha\": \"<source-sha>\",\n \"material_sha\": \"<material-sha>\"\n },\n \"release\": {\n \"version\": \"1.2.0-alpha.3\",\n \"ref\": \"1.2.0-alpha.3\",\n \"target_ref\": \"alpha/v1/v1.2\",\n \"source_sha\": \"<current-source-sha>\",\n \"material_sha\": \"<current-material-sha>\"\n },\n \"verification\": {\n \"public_manifest\": true,\n \"ref\": \"1.2.0-alpha.3\",\n \"digest\": \"sha256:...\",\n \"platform\": \"linux/amd64\",\n \"contract_major\": 1,\n \"evidence\": \"registry-inspect.json\",\n \"smoke\": {\n \"policy\": \"manifest-contract\",\n \"passed\": true,\n \"evidence\": \"smoke.json\"\n }\n }\n}\n```\n\n## Release Modes And Auth\n\nBuildchain distinguishes two npm release modes:\n\n| Mode | Use | Auth | npm operation |\n| --- | --- | --- | --- |\n| `publish-final-version` | normal alpha or stable publication | `trusted-publishing` | `npm publish --tag <alpha|vX.Y-alpha|latest>` |\n| `promote-existing-version` | same-version alpha-to-latest recovery | `npm-token` | `npm dist-tag add <pkg>@<version> latest` |\n\nThe normal libnode path is `publish-final-version`: publish an alpha package set\nsuch as `22.22.3-kf.3-alpha.0` with the `alpha` dist-tag, then publish a\ndistinct final package set such as `22.22.3-kf.3` with the `latest` dist-tag.\nGitHub-hosted npm Trusted Publishing can authorize those `npm publish` calls\nwhen the workflow grants `id-token: write`.\n\n`promote-existing-version` is deliberately separate. npm Trusted Publishing does\nnot authorize arbitrary registry-management operations such as `npm dist-tag\nadd`; it authorizes publish-time package provenance. Therefore same-version\npromotion must declare `auth = \"npm-token\"`. Buildchain runs an npm token\npreflight with `npm whoami` before it writes any release transaction state or\nmoves a dist-tag. Missing token auth fails early with a contract error instead\nof a late `E401` after publish evidence has started to move.\n\nFor package sets, `package_set_order = \"platforms-first-main-last\"` makes the\nmain package the visibility gate. Platform package side effects are planned or\nretried first, and the main package or main dist-tag move happens last.\n\nWhen the transaction reaches `complete`, `actions/promote-buildchain-ref`\ngenerates `.buildchain/release-passport/buildchain.release.json` and persists\nthe `release-passport/*` files into the durable `buildchain/release-state/...`\nref. The passport is the stable release artifact for agents and people: it\nlinks the package set, npm publish evidence, dist-tag evidence, build summary,\nplatform artifact manifests, trusted publishing metadata, release-state ref,\ndurable release-state SHA, and transaction result in one schema. Consumer\nrepositories can set `release-passport-product-name` so the passport names their\nproduct instead of the Buildchain default.\n\n## Evidence\n\nThe publish lifecycle must write JSON evidence. Buildchain validates common\nfields and required artifact identities before final refs move.\n\n```json\n{\n \"schema\": 1,\n \"version\": \"2.0.11\",\n \"channel\": \"release\",\n \"source_sha\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"release_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"target_ref\": \"release/v2/v2.0\",\n \"release_material_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"publish_tooling_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"artifacts\": [\n {\n \"group\": \"node\",\n \"kind\": \"npm\",\n \"name\": \"@kungfu-systems/example\",\n \"ref\": \"2.0.11\",\n \"digest\": \"sha256:...\"\n },\n {\n \"group\": \"image\",\n \"kind\": \"oci\",\n \"name\": \"ghcr.io/kungfu-systems/example\",\n \"ref\": \"2.0.11\",\n \"digest\": \"sha256:...\"\n }\n ]\n}\n```\n\nThe generic contract is intentionally small:\n\n- `version`, `channel`, `source_sha`, `release_sha`, and `target_ref` must match\n the promotion run;\n- dist-tag promotion evidence is written beside the publish evidence as\n `dist-tag-evidence.json` and is referenced from the generated passport;\n- required artifacts must appear in evidence;\n- evidence used by a GitHub-hosted rerun must either be stored in the durable\n state ref or be reconstructed by a machine-verifiable consumer command;\n- existing artifacts with the same identity and digest are accepted on rerun;\n- missing artifacts can be published by the next run;\n- an existing artifact with a different digest puts the transaction into\n `repair_required`.\n\nArtifact identity is `group + kind + name + ref`. A required artifact that omits\n`group` matches any group with the same `kind + name + ref`.\n\n## Registry Truth Contract\n\nBuildchain owns transaction orchestration, finalization ordering, durable state,\nand generic evidence validation. It does not embed registry clients for npm,\nPyPI, GHCR/OCI, GitHub Releases, S3, Conan, CMake packaging, or project-specific\ndownload pages.\n\nConsumer `lifecycle.publish` commands own registry truth. A valid consumer stage\nmust be idempotent and machine-verifiable:\n\n- inspect the target registry before publishing;\n- accept an existing exact artifact only when version, identity, digest, and\n release-source binding match;\n- publish missing required artifacts;\n- reject conflicting existing artifacts and write evidence that lets Buildchain\n move the transaction to `repair_required`;\n- write `BUILDCHAIN_PUBLISH_EVIDENCE` after every successful inspect/publish\n cycle;\n- leave floating aliases such as npm dist-tags, PyPI stable markers, OCI\n floating tags, GitHub Release \"published\" status, or download-page stable\n links to a finalization step after Buildchain evidence validation.\n\nThe first-class adapter surface is command-based. Projects may wrap npm, PyPI,\nGHCR/OCI, GitHub Release assets, archives, SBOMs, provenance, or checksums\nhowever they need, as long as they emit the common evidence contract.\n\n## States\n\nThe state machine is:\n\n```text\nprepared -> publishing -> published -> finalizing -> complete\n | | |\n v v v\n publish_failed repair_required failed_permanently\n |\n v\n abandoned\n```\n\nSupported states:\n\n| State | Meaning |\n| --- | --- |\n| `prepared` | Transaction identity was created, but publish has not started. |\n| `publishing` | Publish lifecycle is running or may have been interrupted. |\n| `publish_failed` | Publish command failed before valid evidence was produced. |\n| `published` | Evidence is valid; refs have not necessarily finalized. |\n| `finalizing` | Buildchain is moving exact/floating refs or needs a later run to do it. |\n| `complete` | Required evidence is valid and refs have finalized. |\n| `repair_required` | Existing evidence or artifact state conflicts with expected release material. |\n| `abandoned` | A human or controlled process abandoned this transaction, usually because a newer version supersedes it. |\n| `failed_permanently` | Recovery should not continue without explicit override. |\n\n`repair_required`, `abandoned`, and `failed_permanently` fail closed unless the\noperator passes an explicit override. That override is for controlled repair\nruns, not normal retry behavior.\n\n## Ref Ordering\n\nWhen publish transactions are enabled, promotion order is:\n\n1. verify target source and governance;\n2. create or reuse the version-state release commit;\n3. acquire or resume the release transaction;\n4. run `lifecycle.publish` or accept already-valid evidence;\n5. validate evidence and required artifacts;\n6. move exact release/prerelease tag;\n7. move floating tags and channel refs;\n8. mark the transaction `complete`.\n\nWhen a protected channel requires a generated version-state pull request, the\nfirst run can stop at `finalizing` after registry publication. If the reviewed\nmerge commit later contains that exact transaction release material but the\nexact tag is still absent, a retry performs finalization only: it reloads the\nsame durable source, release material, tooling, evidence, version, and target\nbindings; creates the exact and floating tags at the transaction release SHA;\nand completes the passport from the transaction source tree. It does not rerun\nthe provider mutation and does not authorize the newer composite channel tree\nas published material. A different source tree still requires a new version and\na fresh release candidate.\n\nDeferred binary dispatch, controller-evidence bundling, and any consumer\npublication commit are skipped while `finalization-needed=true`. They run only\nafter the exact public tag and complete release passport exist.\n\nConsumer products that expose a signed well-known channel can opt into one\nadditional, deliberately final step with `publication-commit-command`. Before\nthat command runs, Buildchain has already completed the transaction, created\nthe public GitHub Release, and uploaded every release-passport file plus the\nexplicit PR-stage payload files selected by\n`github-release-payload-patterns`. The command is therefore a commit point for\ndiscovery authority, not another artifact publisher.\n\nThe command receives the exact version, source SHA, release SHA, release tag,\nrelease passport path, and downloaded payload directory through\n`BUILDCHAIN_PUBLICATION_COMMIT_*`. Optional consumer-owned dispatch/API\ncredentials and private signing material are exposed separately as\n`BUILDCHAIN_PUBLICATION_COMMIT_TOKEN` and\n`BUILDCHAIN_PUBLICATION_COMMIT_SIGNING_KEY`; Buildchain never logs, persists,\nor interprets either value. The command must write\n`.buildchain/publication-commit/evidence.json` (or another declared path below\n`.buildchain/`) with this contract:\n\n```json\n{\n \"schema\": \"kungfu-buildchain-publication-commit-evidence/v1\",\n \"status\": \"passed\",\n \"identity\": {\n \"version\": \"4.0.0-alpha.2\",\n \"sourceSha\": \"<source-sha>\",\n \"releaseSha\": \"<release-sha>\",\n \"releaseTag\": \"v4.0.0-alpha.2\"\n },\n \"publication\": {\n \"url\": \"https://example.test/.well-known/product/alpha.json\",\n \"payloadRoot\": \"sha256:<64-lowercase-hex>\"\n },\n \"readback\": {\n \"status\": \"passed\",\n \"url\": \"https://example.test/.well-known/product/alpha.json\",\n \"payloadRoot\": \"sha256:<same-root>\"\n },\n \"recovery\": {\n \"previousAuthority\": \"preserved\",\n \"rollbackReference\": \"sha256:<previous-root>\"\n }\n}\n```\n\nBuildchain rejects stale evidence, identity drift, non-public or mutable URLs,\nread-back root drift, and missing recovery evidence. It also rejects\n`standalone-binary-distribution=true` with a final commit command because that\nwould queue product mutations after the authority moved. On any command or\nread-back failure, the consumer must leave the previous well-known document\nauthoritative; Buildchain does not retry the command behind a successful\nreceipt.\n\nIf protected branch finalization is interrupted after publish evidence is\nvalid, the transaction can stop in `finalizing` and output\n`finalization-needed=true`. A later run resumes from the same transaction state\nand completes ref movement without republishing matching artifacts. New\nBuildchain-managed promotions first try to finish generated version-state\nbookkeeping with the promotion token directly. Before patching a protected\ngenerated bookkeeping ref, Buildchain emits every configured required check on\nthe exact generated version-state commit so branch protection can\nvalidate the automation path without a second build, then uses the generated\nref update token for the protected ref PATCH. If release finalization\nbookkeeping is still rejected, Buildchain creates or reuses a same-repository\n`buildchain/version-state/*` PR and leaves the transaction resumable with\n`finalization-needed=true`. Strict alpha uses the same protected PR fallback\nfor both its target channel and subsequent dev reconciliation. A later\nidempotent run continues only after the provider shows that the PR reached the\nprotected branch. The reusable wrapper binds that token to the run-scoped\n`github.token` and rejects user, team, or alternate App bypass actors.\n\nIf finalization fails after an exact Git tag, a channel branch, or dev/alpha\nsync ref has already moved, the next run reads the durable `finalizing` state\nand continues from the recorded transaction. The current workflow SHA may be a\ngenerated version-state commit, or a historical version-state merge commit, that\ncontains or corresponds to the transaction's `release_material_sha`; it does not\nhave to equal the original `source_sha` or the transaction `release_sha`. Exact\ntags are accepted when they already point at the transaction release/material\nSHA or the finalized channel head. Floating\nchannel tags and dev/alpha refs are then retried idempotently, and the\ntransaction is marked `complete` only after those public refs are consistent.\nWriting `complete` clears any stale `failure` value from earlier attempts, so\nthe durable `state.json` represents the successful final state instead of the\nlast transient error seen before a rerun.\nAn exact tag at an unrelated SHA is still a material conflict and blocks\nrecovery.\n\nFor anchored package versions, the package version and internal line tag are\nseparate transaction coordinates. A retry can correct a stale internal tag on\nan unfinished `published` or `finalizing` transaction only when its validated\nevidence and complete artifact set match the same package version, source,\nrelease material, and target. Buildchain additionally requires that the stale\ntag does not already point at the transaction and that the newly selected tag\nis unclaimed or already points at accepted release material. No registry publish\ncommand is rerun during this exact-tag rebind.\n\nGoverned retries distinguish unrelated channel advancement from advancement\nmade by their own durable transaction. An unrelated descendant remains an\nauditable `superseded-promotion` no-op. When the target ref is exactly the\nrecorded `release_sha` for the requested source, target, and expected version,\nBuildchain resumes finalization, restores publish evidence, and emits the\nrelease-passport paths needed by downstream controller receipts.\n\nPublication authority planning applies the same occupied-version rule as the\nlater mutation step. If a current alpha transaction already contains published\nmaterial and regenerating version state would create new release material, the\nplanner advances to the next alpha before sealing authority. It never seals the\nold published version and then lets the publisher discover a different version\ninside the mutation boundary.\n\nIf finalization fails after an exact Git tag is created, the next run reads the\ndurable `finalizing` state, verifies the exact tag points at the recorded\nrelease SHA, and retries the remaining floating refs. An exact tag at a\ndifferent SHA is a material conflict and blocks recovery.\n\n## CLI Recovery\n\nLocal recovery commands operate on the same state/evidence files:\n\n```bash\nnode scripts/release-transaction.mjs inspect --version v2.0.11\nnode scripts/release-transaction.mjs recover --version v2.0.11\nnode scripts/release-transaction.mjs finalize --version v2.0.11\nnode scripts/release-transaction.mjs abort --version v2.0.11 --superseded-by v2.0.12\n```\n\nThe CLI is a diagnostic and local repair surface. It reports the durable\n`state_ref`, but remote durable-ref writes and public Git ref finalization are\nowned by `actions/promote-buildchain-ref`, because that action runs inside the\nsame governed GitHub permissions and branch-protection checks as release\npromotion. In other words, CLI `finalize` can mark the local transaction state\ncomplete after valid evidence; the machine-operated public finalization path is\nto rerun the promotion action.\n\nWhen no state file exists, creation commands also require:\n\n```bash\n--repository kungfu-systems/buildchain \\\n--source-sha <sha> \\\n--release-sha <sha> \\\n--target-ref release/v2/v2.0 \\\n--channel release\n```\n\n## Build-Images Follow-Up\n\n`build-images` should consume this contract rather than inventing a separate\nworkflow rule. The expected integration shape is:\n\n- image build writes OCI digests into publish evidence;\n- required image families are passed through `publish-required-artifacts-json`\n before their final digests are known;\n- mixed built/reused evidence preserves content provenance separately from the\n current release binding;\n- reruns check GHCR or the target registry and accept existing images only when\n tag and digest match;\n- preview or alpha image tags remain non-stable until the transaction evidence\n validates;\n- production image aliases move only after all required image artifacts are\n present and the Buildchain exact release tag has finalized."
|
|
1391
1391
|
},
|
|
1392
1392
|
{
|
|
1393
1393
|
"id": "manual:readme-badges",
|
|
@@ -2706,7 +2706,7 @@
|
|
|
2706
2706
|
"path": "docs/github-governance-authority.md",
|
|
2707
2707
|
"plane": "verify",
|
|
2708
2708
|
"exists": true,
|
|
2709
|
-
"digest": "sha256:
|
|
2709
|
+
"digest": "sha256:8484b18d5b0fe6d61d102d6b9cb9e18beac9f47ecb516d430fb5427518e2931f"
|
|
2710
2710
|
},
|
|
2711
2711
|
{
|
|
2712
2712
|
"id": "release-candidate",
|
|
@@ -2858,7 +2858,7 @@
|
|
|
2858
2858
|
"path": "docs/publish-transaction.md",
|
|
2859
2859
|
"plane": "verify",
|
|
2860
2860
|
"exists": true,
|
|
2861
|
-
"digest": "sha256:
|
|
2861
|
+
"digest": "sha256:cde5256d5f6443a6d32b47783900a0677e973855266af5a360db8d4d112bb677"
|
|
2862
2862
|
},
|
|
2863
2863
|
{
|
|
2864
2864
|
"id": "release-governance",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"contract": "kungfu-buildchain-public-surface-reverse-audit",
|
|
22
22
|
"path": "dist/site/public-surface-audit.json",
|
|
23
23
|
"status": "passed",
|
|
24
|
-
"sha256": "
|
|
24
|
+
"sha256": "e2ed3df53a48587531486466e02c82f044920fb629a77b0880e9b9aaa762adac",
|
|
25
25
|
"summary": {
|
|
26
26
|
"cliCommandCount": 87,
|
|
27
27
|
"workflowCount": 52,
|
|
@@ -228,7 +228,7 @@
|
|
|
228
228
|
"contract": "kungfu-buildchain-public-surface-reverse-audit",
|
|
229
229
|
"path": "dist/site/public-surface-audit.json",
|
|
230
230
|
"status": "passed",
|
|
231
|
-
"sha256": "
|
|
231
|
+
"sha256": "e2ed3df53a48587531486466e02c82f044920fb629a77b0880e9b9aaa762adac",
|
|
232
232
|
"summary": {
|
|
233
233
|
"cliCommandCount": 87,
|
|
234
234
|
"workflowCount": 52,
|
|
@@ -4203,7 +4203,7 @@
|
|
|
4203
4203
|
"visibility": "public",
|
|
4204
4204
|
"participantFacing": true,
|
|
4205
4205
|
"public": true,
|
|
4206
|
-
"inputCount":
|
|
4206
|
+
"inputCount": 64,
|
|
4207
4207
|
"inputs": [
|
|
4208
4208
|
"allow-repository",
|
|
4209
4209
|
"branch-protection-bypass-apps",
|
|
@@ -4211,6 +4211,7 @@
|
|
|
4211
4211
|
"branch-protection-bypass-users",
|
|
4212
4212
|
"dry-run",
|
|
4213
4213
|
"expected-publication-version",
|
|
4214
|
+
"generated-pull-request-token",
|
|
4214
4215
|
"generated-ref-update-token",
|
|
4215
4216
|
"generated-status-check-token",
|
|
4216
4217
|
"github-release",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"title": "GitHub governance authority",
|
|
80
80
|
"path": "docs/github-governance-authority.md",
|
|
81
81
|
"plane": "verify",
|
|
82
|
-
"digest": "sha256:
|
|
82
|
+
"digest": "sha256:8484b18d5b0fe6d61d102d6b9cb9e18beac9f47ecb516d430fb5427518e2931f",
|
|
83
83
|
"capabilityGroup": "governance-versioning",
|
|
84
84
|
"audience": [
|
|
85
85
|
"maintainer",
|
|
@@ -346,7 +346,7 @@
|
|
|
346
346
|
"title": "Publish transaction",
|
|
347
347
|
"path": "docs/publish-transaction.md",
|
|
348
348
|
"plane": "verify",
|
|
349
|
-
"digest": "sha256:
|
|
349
|
+
"digest": "sha256:cde5256d5f6443a6d32b47783900a0677e973855266af5a360db8d4d112bb677",
|
|
350
350
|
"capabilityGroup": "release-passport-trust",
|
|
351
351
|
"audience": [
|
|
352
352
|
"release-operator"
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
],
|
|
141
141
|
"maturity": "stable",
|
|
142
142
|
"sourcePath": "actions/promote-buildchain-ref/README.md",
|
|
143
|
-
"digest": "sha256:
|
|
143
|
+
"digest": "sha256:21d5ee78b10754a16fa71134f37c5e2442cc3395524dcbfabccc0a9cf94edf14",
|
|
144
144
|
"headings": [
|
|
145
145
|
{
|
|
146
146
|
"level": 1,
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
"anchor": "publish-transactions"
|
|
159
159
|
}
|
|
160
160
|
],
|
|
161
|
-
"markdown": "# promote-buildchain-ref\n\nInternal buildchain action for promoting verified buildchain release-line and\ncompatibility refs from buildchain release channels:\n\n- `alpha/v2/v2.0` creates or reuses the next exact prerelease tag such as\n `v2.0.1-alpha.0`, writes that version into package version state, points the\n alpha and dev channel branches at the version commit, then promotes\n `v2.0-alpha` and, when this is the highest published alpha minor, `v2-alpha`;\n- `release/v2/v2.0` creates or reuses the next exact release tag such as\n `v2.0.0`, writes that version into package version state, points the release\n channel branch and release tags at the release commit, then prepares a second\n source commit for the next exact prerelease tag such as `v2.0.1-alpha.0` and\n points the alpha/dev channel branches plus `v2.0-alpha` at that prerelease\n commit, and moves `v2-alpha` only if no higher v2 minor has published an alpha;\n- `publish-gate/major` accepts a reviewed PR from a production release line such\n as `release/v2/v2.0`, writes the next major production version such as\n `v3.0.0`, points `publish-gate/major`, `release/v3/v3.0`, `v3.0`, and `v3`\n at that release commit, then prepares `v3.0.1-alpha.0` for\n `alpha/v3/v3.0`, `dev/v3/v3.0`, `v3.0-alpha`, and `v3-alpha`. The older `major-gate`\n branch name is a compatibility alias only.\n\nThe release branch name defines the minor line. For example,\n`release/v2/v2.1` creates `v2.1.N`, promotes `v2.1`, and promotes `v2` only\nwhen the next minor tag such as `v2.2` does not already exist.\n\nThe action updates version state in `lerna.json`, root `package.json`, and\nworkspace package manifests discovered from package manager metadata\n(`package.json` workspaces, `lerna.json` packages, or `pnpm-workspace.yaml`).\nPackage manager detection is adaptive (`pnpm`, `npm`, or `yarn`) and is recorded\nin logs.\n\nRepositories can also provide `buildchain.toml` to declare version-state files\nand `lifecycle.verify`. TOML-configured version files take precedence over\npackage-manager discovery and can target JSON, TOML, or regex-based files. The\nversion commit itself is written through the GitHub Git Data API so the ref\ngraph is the durable source of truth. Repositories without any supported version\nstate degrade to ref-only promotion only when strict version state is disabled.\n\nJSON and TOML version entries whose declared key already matches the requested\nversion are treated as semantic no-ops. TOML changes use a parser-verified\nlossless key edit, so repository formatting is preserved and formatter-only\nrelease-preparation commits are not created. If a unique lossless edit cannot\nbe proven, promotion fails closed instead of rewriting the full TOML document.\n\n## Dry Run\n\nUse `dry-run: \"true\"` or the CLI `buildchain release --dry-run` before merging a\nchannel PR when you need to understand what Buildchain would do. This dry-run is\nat the Buildchain release-line level. It explains:\n\n- the legal source branch for the target channel;\n- exact release or alpha tags that would be created or reused;\n- floating tags and channel branches that would move;\n- version-state files and verification lifecycle that would apply;\n- branch protection, PR lineage, and release-from-alpha checks;\n- publish transaction behavior when `lifecycle.publish` or\n `publish-transaction` is enabled.\n\nIt does not move refs, move tags, write package files, run publish commands, or\npublish npm packages. The GitHub action dry-run still calls GitHub APIs to\nresolve the current target SHA and concrete pending ref updates, but every\nwrite is reported as a dry-run update.\n\nRepositories whose package version is anchored to an explicitly selected\nupstream release can opt into manual next-anchor behavior:\n\n```toml\n[version]\nrequired = true\nstrategy = \"anchored\"\nnext = \"manual\"\nmanifest = \"libnode.release.json\"\n```\n\nIn this mode, the action validates the configured version files and anchor\nmanifest through the repository's verify lifecycle, but it does not rewrite the\npackage version to match the Buildchain release tag. After a production\nrelease, it sets `next-anchor-required=true` and does not auto-create the next\nalpha branch or tag. The repository must create the next upstream anchor line\nexplicitly, then run the normal channel promotion flow for that line.\n\nWhen branch protection requires pull requests, generated version-state commits\nstill run through promotion automation first. The action updates\nBuildchain-managed channel protection before generated bookkeeping, admits only\nthe exact `github-actions` App to the target-bound bypass allowlist, creates\nevery configured required check on the exact generated version-state commit, then\ntries to apply that commit directly. If GitHub still rejects release\nfinalization bookkeeping, Buildchain creates or reuses a same-repository\n`buildchain/version-state/*` PR based on the current target channel head and\nreturns `finalization-needed=true`; a later idempotent promotion run can resume\nfrom the durable transaction state. Strict alpha uses the same protected\nversion-state PR recovery for its target and dev bookkeeping, and does not move\ntags until those provider-enforced transactions land. Reusable wrapper callers\nshould allow `checks: write` so the generated checks are owned by GitHub Actions\nand match the managed branch protection rule.\n\nStable promotion also protects concurrent development work. The reusable\nwrapper checks out the exact current `dev/vN/vN.M` head as a reconciliation\nworkspace. If next-alpha bookkeeping cannot fast-forward that branch, the\naction reruns the declared version-state generation and verification from that\ndev tree, creates a two-parent reconciliation commit from the regenerated\nfiles, and fails closed if the checkout moved before the mutation boundary.\nThis prevents generated projections from an older release tree from replacing\ncapabilities that reached dev while the release was in progress.\n\nFor Buildchain-owned automation, callers may pass\n`branch-protection-bypass-apps: github-actions`. The action rejects every other\nApp slug and all user or team bypass actors. It configures managed\n`dev/vN/vN.M`, `alpha/vN/vN.M`, and `release/vN/vN.M` branches with one\nrequired approving review, Code Owner review, stale-review dismissal,\nlatest-push approval, exact App-bound GitHub Actions checks, admin enforcement,\nconversation resolution, no force pushes, and no deletions; the bypass\nallowance only lets the named automation identity apply generated version-state\nor channel bookkeeping without a second human review after the reviewed channel\nPR has already merged.\n\n## Publish Transactions\n\nPromotion can also own external publish side effects. Enable this only from a\ntrusted channel workflow:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n generated-ref-update-token: ${{ github.token }}\n sha: ${{ github.sha }}\n target-ref: release/v2/v2.0\n publish-transaction: \"true\"\n publish-mode: publish-final-version\n publish-auth: trusted-publishing\n publish-required-artifacts-json: >-\n [\n {\"kind\":\"npm\",\"name\":\"@kungfu-tech/buildchain\",\"ref\":\"2.0.0\",\"digest\":\"sha256:...\"}\n ]\n```\n\nFor anchored/manual package repositories that build through the reusable\nworkflow, keep the publish entrypoint on the `publish-gate/*` source-lock\ncontract:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n sha: ${{ needs.build.outputs.publish-source-sha }}\n target-ref: release/v22/v22.22\n require-publish-source-lock: \"true\"\n publish-source-ref: ${{ needs.build.outputs.publish-source-ref }}\n publish-source-sha: ${{ needs.build.outputs.publish-source-sha }}\n publish-source-locked: ${{ needs.build.outputs.publish-source-locked }}\n publish-transaction: \"true\"\n publish-mode: publish-final-version\n publish-auth: trusted-publishing\n```\n\n`target-ref` remains the channel promotion target that must point at `sha`.\n`publish-source-ref` is the reviewed source-lock branch that authorized this\nspecific package publication. Direct `alpha/*` or `release/*` channel refs are\nnot valid publish source locks when `require-publish-source-lock` is enabled,\nand a mismatched `publish-source-sha` fails before any promotion or publish side effects begin.\n\nConsumers that opt in to a product-owned final predicate set\n`require-publication-qualification: \"true\"` and pass the exact sealed\n`publication-capability-json`, complete `publication-gate-aggregate-json`, and\n`publication-qualification-receipt-json`. The action validates their canonical\ndigests, predicate identity, freshness, nonce, source, version, channel, target,\nand evidence bindings both before provider access and immediately before the\npublish transaction. Missing or drifted receipts fail before mutation. The\nreusable `release-candidate-promote.yml` workflow creates these values in a\nseparate credentialless consumer job; direct callers must preserve the same\ncontract and may pass previously consumed nonces through\n`publication-used-qualification-nonces-json`.\n\nThe reusable promote workflow serializes non-dry-run promotion intents per\nrepository and re-reads `target-ref` before checkout, dependency installation,\nrelease-candidate resolution, or publish-gate writes. If a queued intent asks\nfor an older SHA after the protected channel has advanced, the workflow records\nthe requested/current SHA pair, verifies that the current target is ahead of\nthe requested commit, and exits successfully as a superseded no-op. Diverged,\nbehind, or unreadable comparisons still fail closed.\nAfter queued-intent revalidation, the reusable workflow runs the canonical\nrelease-candidate resolver in metadata-only mode before installing candidate\ndependencies or starting the full promotion job. The full job resolves and\ndownloads the evidence again before any publish-gate or publication mutation.\nThis preserves the final exact-evidence trust check while making missing or\nstale PR-stage evidence fail early.\nThe action repeats that check at its mutation boundary for governed promotion\ncalls, closing the race between workflow preflight and action start. Direct\nnon-governed calls and dry-runs keep the strict target mismatch error so local\ndiagnostics cannot silently reinterpret a stale request.\nExpected manual dry-run failures remain visible in the workflow result and do\nnot create automated workflow-friction issues; issue reporting is reserved for\nnon-dry-run promotion failures.\nThe reusable build workflow performs the cheaper channel-ref preflight earlier:\nafter source-lock resolution and before the build matrix, it requires the target\nchannel ref such as `alpha/v22/v22.22` or `release/v22/v22.22` to already point\nat the locked `publish-source-sha`. If not, maintainers should merge the source\ncommit through the channel PR first.\n\nFor promote-only release candidates, attach the PR-stage reusable build evidence\nand fail before publish-gate side effects if it no longer matches:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n sha: ${{ needs.build.outputs.publish-source-sha }}\n target-ref: alpha/v22/v22.22\n promote-only-release-candidate: \"true\"\n release-candidate-passport-path: .buildchain/artifacts/release-candidate-passport.json\n release-candidate-build-summary-path: .buildchain/artifacts/build-summary.json\n```\n\nThe action validates repository, channel, source identity, platform matrix, and\nthe aggregate build-summary hash before it writes version state, opens\nrelease-state, runs publish transaction logic, or moves tags/branches. Source\nidentity accepts the exact source SHA, the PR merge ref SHA, or the promoted\nchannel HEAD's Git tree SHA matching the passport tree hash. If validation\nfails, run or attach the verified channel PR build first instead of promoting a\nstale or unproven artifact set.\n\nWhen enabled, the action creates or resumes a release transaction keyed by\nrepository, version, source SHA, and target ref. It persists that transaction to\na machine-managed branch under `buildchain/release-state/<version>`, with\n`state.json` and, once available, `evidence.json`. Fresh GitHub runners read\nthat durable ref before running publish, so reruns do not depend on a previous\nrunner's local `.buildchain` directory.\n\nConsumers whose publish lifecycle only assembles local release assets or\nPassport inputs may set `publish-rematerialize-on-resume: true`. After\nBuildchain restores and validates durable publish evidence, it replays that\nconsumer-owned lifecycle with the original transaction environment before\nPassport collection. This is explicit opt-in because registry publication and\nother provider mutations must not be replayed blindly; the option rejects\n`promote-existing-version`.\n\nThe action runs `lifecycle.publish` from `buildchain.toml` or the explicit\n`publish-command` input, then validates publish evidence before exact tags and\nfloating refs move. If durable state persistence fails, the action fails closed\nbefore publish or public ref finalization.\n\n`publish-mode` defaults to `publish-final-version`, the token-free path for\nnormal npm Trusted Publishing. Same-version alpha-to-latest recovery must be\ndeclared as `publish-mode: promote-existing-version` and\n`publish-auth: npm-token`; Buildchain runs `npm whoami` before it creates\nrelease-state or moves any `npm dist-tag`. The Trusted Publishing mode is not\nallowed to perform `npm dist-tag add`.\n\nBuildchain itself uses this path for npm. Its `lifecycle.publish` runs\n`node scripts/npm-publish-transaction.mjs`, which publishes\n`@kungfu-tech/buildchain` through npm Trusted Publishing and writes npm\nartifact evidence into the transaction before release refs move. The separate\n`.github/workflows/npm-publish.yml` workflow is dry-run only.\n\nPublish lifecycle environment:\n\n```text\nBUILDCHAIN_VERSION\nBUILDCHAIN_CHANNEL\nBUILDCHAIN_SOURCE_SHA\nBUILDCHAIN_TARGET_REF\nBUILDCHAIN_RELEASE_STATE\nBUILDCHAIN_EVIDENCE_DIR\nBUILDCHAIN_RELEASE_SHA\nBUILDCHAIN_RELEASE_MATERIAL_SHA\nBUILDCHAIN_PUBLISH_TOOLING_SHA\nBUILDCHAIN_PUBLISH_EVIDENCE\nBUILDCHAIN_REQUIRED_ARTIFACTS\n```\n\n`BUILDCHAIN_REQUIRED_ARTIFACTS` is the normalized requirement array after the\naction resolves a missing artifact `ref` to `BUILDCHAIN_VERSION`, or expands an\noptional `ref_template` containing exactly one `{version}`, and binds any\ndeclared provenance to the current release coordinate. Template expansion\nhappens after exact version selection; ambiguous or unsupported templates fail\nbefore `lifecycle.publish`. Requirement descriptors may omit `digest`; final\npublish evidence may not.\n\nThe action outputs `transaction-id`, `transaction-state`,\n`transaction-exact-tag`, `public-release-tag`, `transaction-release-sha`,\n`transaction-state-ref`, `transaction-state-sha`, `transaction-state-path`,\n`publish-evidence-path`, and `release-passport-path`, `release-passport-output-dir`,\n`release-passport-state-sha`, and `finalization-needed`.\n`transaction-state-ref` is the durable recovery location.\n`release-passport-state-sha` is the durable ref commit after the generated\n`release-passport/*` files have been uploaded into that recovery ref.\n`finalization-needed=true` means publish evidence is valid, but protected branch\nor ref finalization needs a later idempotent promotion run. For release\nfinalization, Buildchain may create a same-repository generated version-state\nPR when GitHub rejects the direct protected ref update; that PR is Buildchain\nbookkeeping, not a consumer-authored release change.\nSet `github-release: \"true\"` when the semver promotion should also publish the\npublic GitHub Release. After the release transaction reaches `complete` and\n`finalization-needed` is false, the action creates or updates the GitHub Release\nfor `public-release-tag`, applies deterministic metadata from the authoritative\npublication channel (`alpha` is a prerelease and never latest; `release`,\n`stable`, and `major` are stable and latest), and uploads the publish evidence\nfile plus generated release passport assets. Tag syntax remains the fallback for\nordinary callers that do not supply publication intent. For anchored/manual\npackage releases, `public-release-tag` is derived\nfrom the published package version, while `transaction-exact-tag` remains the\ninternal Buildchain transaction ref for recovery and audit. If the transaction is\nnot complete yet, the action defers GitHub Release publication to the next\nidempotent promotion run.\n\nAfter a publish transaction reaches `complete`, the action generates the unified\n`buildchain-release-passport` in `.buildchain/release-passport` by default and\npersists those files under `release-passport/` in the durable release-state ref.\nSet `release-passport-product-name` to record the consumer product name, for\nexample `Libnode`, instead of the default `Buildchain`.\nSet `release-passport-kfd-1-witness-jsons` to newline-separated KFD-1\ncontract-world witness JSON paths when released artifacts must prove\nbyte-for-byte KFD contract surfaces. Buildchain imports the KFD metadata from\n`@kungfu-tech/kfd`, freezes the witness, verifies artifact bytes, and writes the\nresult under the KFD-provided `kfd-1` passport section.\nSet `release-passport-kfd-2-claim-jsons` to newline-separated KFD-2 public\nrelease trust claim JSON paths when a release makes additional human/agent\nvisible claims. Buildchain requires each public claim to bind declared sources,\nmachine-readable evidence, hashes, artifact coordinates, verification results,\naudit boundary, responsibility state, and residual risk. Unbound claims fail\npassport verification; prose-only claims downgrade the KFD-2 audit.\nSet `release-passport-kfd-3-prebuild-witness-jsons` to newline-separated KFD-3\ncollaboration-interface pre-build witness paths, then provide artifact-side\nevidence with `release-passport-kfd-3-artifact-witness-jsons` or a\nproduct-owned `release-passport-kfd-3-artifact-verify-command` such as\n`kungfu agent verify --json`. Buildchain compares declared shipped public\nsurfaces with artifact-exposed public surfaces and writes the result under the\nKFD-provided `kfd-3` passport section.\nSet `release-passport-invariant-passport-jsons` to one or more product-owned\ninvariant Passport paths, or set `release-passport-invariant-passport-command`\nto a command that emits one canonical Passport JSON document. Buildchain does\nnot reinterpret product invariants: it verifies the declared semantic root,\nrequires a `verified` verdict, complete platform coverage, a clean exact source\nrevision, and then binds the result into `buildchain.release.json`. Missing,\nstale, falsified, incomplete, dirty, or tampered Passport evidence fails the\nrelease transaction closed.\nBuildchain's own release workflow sets `release-passport-buildchain-self-kfd:\n\"true\"`. In that mode the action generates Buildchain-owned KFD-1/2/3 witnesses\ninside the final version-state workspace, after the release transaction has\nmaterialized generated files such as `package.json` and `dist/site/*`. This\nkeeps self-hosted KFD witness hashes bound to the exact published package\ninstead of to a pre-promotion checkout.\nWhen present, the passport includes the aggregate build summary, platform\nartifact manifests, npm publish evidence, dist-tag promotion evidence, the\nrelease-state ref, trusted publishing metadata, and the Buildchain transaction\nresult. After the first passport upload, Buildchain backfills the durable\nrelease-state SHA into `buildchain.release.json` and persists the passport\nagain, so the consumer-side passport is a complete audit entrypoint. Set\n`release-passport: \"false\"` only for a controlled recovery run that must skip\npassport generation.\n\nFinalization recovery is anchored to the durable transaction, not to a single\nworkflow run SHA. After generated version-state bookkeeping is applied, the\ncurrent channel head can be the generated version-state commit or a historical\nmerge commit that contains or corresponds to the recorded `release_material_sha`;\nit does not have to equal the original `source_sha` or the transaction\n`release_sha`. Reruns accept exact tags that already point at the transaction\nrelease/material SHA or the finalized channel head, and continue moving any\nmissing floating tags or dev/alpha refs before marking the transaction\n`complete`.\n\nNormal reruns accept already-published artifacts only when evidence matches.\nMissing required artifacts can be published on the next run. Conflicting\nrefs, digests, or declared provenance put the transaction into\n`repair_required`; `abandoned` and\n`failed_permanently` also fail closed unless `publish-transaction-override` is\nset for a controlled repair. The same override may replace a stale transaction\nonly when its version, exact tag, target ref, and channel are unchanged, the\ntransaction is not complete, and it contains no published artifacts or\nevidence. This lets a newly admitted source retry a previously failed paper\npublication without weakening already-published facts.\n\nIn strict buildchain promotion, ref movement is also gated by the old ABV\ngovernance semantics:\n\n- when detailed target branch protection is readable, it must enforce\n protection for administrators and require approving PR review plus the strict\n `check` job from the `Verify` workflow; when GitHub withholds that\n administration endpoint from the workflow token, the exact transaction must\n instead prove a protected current head, same-repository merged PR,\n independent approval, and the required successful `check` from its configured\n GitHub App;\n- post-publish channel reconciliation reuses an already qualifying\n provider-enforced policy when the workflow token cannot read or rewrite the\n administrative protection document, and fails closed if the public branch\n summary no longer carries the required check for everyone;\n- alpha promotion must come from a merged same-repository PR\n `dev/vN/vN.M -> alpha/vN/vN.M`, or from a strict same-line\n `publish-gate/alpha/vN/vN.M/<version> -> alpha/vN/vN.M` source-lock PR;\n- release promotion must come from a merged same-repository PR\n `alpha/vN/vN.M -> release/vN/vN.M`, or from a strict same-line\n `publish-gate/release/vN/vN.M/<version> -> release/vN/vN.M` source-lock PR;\n- major promotion must come from a merged same-repository PR\n `release/vN/vN.M -> publish-gate/major`;\n- release promotion must have an exact alpha tag for the same patch line, and\n the release source tree must match that alpha tag tree, so release does not\n introduce new code after alpha;\n- anchored/manual release promotion may differ from that alpha tree only in\n declared `version.files` and the configured anchor manifest, and only when the\n checked-out release material has passed `lifecycle.verify` or the explicit\n `verification-command`;\n- generated release and next-alpha version-state trees can be verified locally\n with either the `verification-command` input or `buildchain.toml`\n `lifecycle.verify` before any tags or channel refs move.\n\nThe promotion workflow should use `BUILDCHAIN_PROMOTION_TOKEN` for non-dry-run\npromotion. The token is the buildchain equivalent of the old ABV runner release\nauthority: protected branch review and check rules guard human channel merges,\nwhile the reusable build trust gate now checks the source-lock channel HEAD and\nmerged same-repository PR lineage before heavy build runners start. This action\nstill independently rechecks PR lineage, alpha/release tree equivalence, and\ngenerated version-state verification before moving channel refs and tags.\nGenerated version-state direct ref updates can use a separate\n`generated-ref-update-token`; the reusable wrapper binds it to the run-scoped\n`github.token`.\nThe reusable `release-candidate-promote.yml` wrapper defaults\n`branch-protection-bypass-apps` to `github-actions`, so flow-internal promotion\ncan complete generated `dev`/`alpha`/`release` bookkeeping while ordinary human\npushes and PR merges remain governed by the one-review branch protection rule.\nThe promotion action rejects alternate App slugs and every user or team bypass,\nso the mutation path cannot widen the authority descriptor.\n\nThe tag names intentionally follow the old ABV release semantics:\nexact release tags are `vX.Y.Z`, exact alpha tags are `vX.Y.Z-alpha.N`, floating\nrelease tags are minor/major tags such as `v2.0` and `v2`, and floating alpha\ntags are minor-line tags such as `v2.0-alpha` plus cross-minor major tags such\nas `v2-alpha`. A major alpha tag only moves for the highest minor in that major\nwith a published alpha, so older-line maintenance cannot roll consumers back.\nBare tags such as `1.0.0` are not\nmaintained as buildchain release entrypoints.\n\nRepository rulesets should protect exact tags, not every `v*` tag. A ruleset\nsuch as `refs/tags/v*` also protects floating channel tags like `v2.0-alpha` and `v2-alpha`,\nwhich Buildchain must update after exact tags and publish evidence are durable.\nUse an exact-tag rule such as `refs/tags/v*.*.*` for immutable evidence tags and\nleave floating channel tags mutable for the promotion token."
|
|
161
|
+
"markdown": "# promote-buildchain-ref\n\nInternal buildchain action for promoting verified buildchain release-line and\ncompatibility refs from buildchain release channels:\n\n- `alpha/v2/v2.0` creates or reuses the next exact prerelease tag such as\n `v2.0.1-alpha.0`, writes that version into package version state, points the\n alpha and dev channel branches at the version commit, then promotes\n `v2.0-alpha` and, when this is the highest published alpha minor, `v2-alpha`;\n- `release/v2/v2.0` creates or reuses the next exact release tag such as\n `v2.0.0`, writes that version into package version state, points the release\n channel branch and release tags at the release commit, then prepares a second\n source commit for the next exact prerelease tag such as `v2.0.1-alpha.0` and\n points the alpha/dev channel branches plus `v2.0-alpha` at that prerelease\n commit, and moves `v2-alpha` only if no higher v2 minor has published an alpha;\n- `publish-gate/major` accepts a reviewed PR from a production release line such\n as `release/v2/v2.0`, writes the next major production version such as\n `v3.0.0`, points `publish-gate/major`, `release/v3/v3.0`, `v3.0`, and `v3`\n at that release commit, then prepares `v3.0.1-alpha.0` for\n `alpha/v3/v3.0`, `dev/v3/v3.0`, `v3.0-alpha`, and `v3-alpha`. The older `major-gate`\n branch name is a compatibility alias only.\n\nThe release branch name defines the minor line. For example,\n`release/v2/v2.1` creates `v2.1.N`, promotes `v2.1`, and promotes `v2` only\nwhen the next minor tag such as `v2.2` does not already exist.\n\nThe action updates version state in `lerna.json`, root `package.json`, and\nworkspace package manifests discovered from package manager metadata\n(`package.json` workspaces, `lerna.json` packages, or `pnpm-workspace.yaml`).\nPackage manager detection is adaptive (`pnpm`, `npm`, or `yarn`) and is recorded\nin logs.\n\nRepositories can also provide `buildchain.toml` to declare version-state files\nand `lifecycle.verify`. TOML-configured version files take precedence over\npackage-manager discovery and can target JSON, TOML, or regex-based files. The\nversion commit itself is written through the GitHub Git Data API so the ref\ngraph is the durable source of truth. Repositories without any supported version\nstate degrade to ref-only promotion only when strict version state is disabled.\n\nJSON and TOML version entries whose declared key already matches the requested\nversion are treated as semantic no-ops. TOML changes use a parser-verified\nlossless key edit, so repository formatting is preserved and formatter-only\nrelease-preparation commits are not created. If a unique lossless edit cannot\nbe proven, promotion fails closed instead of rewriting the full TOML document.\n\n## Dry Run\n\nUse `dry-run: \"true\"` or the CLI `buildchain release --dry-run` before merging a\nchannel PR when you need to understand what Buildchain would do. This dry-run is\nat the Buildchain release-line level. It explains:\n\n- the legal source branch for the target channel;\n- exact release or alpha tags that would be created or reused;\n- floating tags and channel branches that would move;\n- version-state files and verification lifecycle that would apply;\n- branch protection, PR lineage, and release-from-alpha checks;\n- publish transaction behavior when `lifecycle.publish` or\n `publish-transaction` is enabled.\n\nIt does not move refs, move tags, write package files, run publish commands, or\npublish npm packages. The GitHub action dry-run still calls GitHub APIs to\nresolve the current target SHA and concrete pending ref updates, but every\nwrite is reported as a dry-run update.\n\nRepositories whose package version is anchored to an explicitly selected\nupstream release can opt into manual next-anchor behavior:\n\n```toml\n[version]\nrequired = true\nstrategy = \"anchored\"\nnext = \"manual\"\nmanifest = \"libnode.release.json\"\n```\n\nIn this mode, the action validates the configured version files and anchor\nmanifest through the repository's verify lifecycle, but it does not rewrite the\npackage version to match the Buildchain release tag. After a production\nrelease, it sets `next-anchor-required=true` and does not auto-create the next\nalpha branch or tag. The repository must create the next upstream anchor line\nexplicitly, then run the normal channel promotion flow for that line.\n\nWhen branch protection requires pull requests, generated version-state commits\nstill run through promotion automation first. The action updates\nBuildchain-managed channel protection before generated bookkeeping, admits only\nthe exact `github-actions` App to the target-bound bypass allowlist, creates\nevery configured required check on the exact generated version-state commit, then\ntries to apply that commit directly. If GitHub still rejects release\nfinalization bookkeeping, Buildchain creates or reuses a same-repository\n`buildchain/version-state/*` PR based on the current target channel head and\nreturns `finalization-needed=true`; a later idempotent promotion run can resume\nfrom the durable transaction state. Strict alpha uses the same protected\nversion-state PR recovery for its target and dev bookkeeping, and does not move\ntags until those provider-enforced transactions land. Reusable wrapper callers\nshould allow `checks: write` so the generated checks are owned by GitHub Actions\nand match the managed branch protection rule.\n\nStable promotion also protects concurrent development work. The reusable\nwrapper checks out the exact current `dev/vN/vN.M` head as a reconciliation\nworkspace. If next-alpha bookkeeping cannot fast-forward that branch, the\naction reruns the declared version-state generation and verification from that\ndev tree, creates a two-parent reconciliation commit from the regenerated\nfiles, and fails closed if the checkout moved before the mutation boundary.\nThis prevents generated projections from an older release tree from replacing\ncapabilities that reached dev while the release was in progress.\n\nFor Buildchain-owned automation, callers may pass\n`branch-protection-bypass-apps: github-actions`. The action rejects every other\nApp slug and all user or team bypass actors. It configures managed\n`dev/vN/vN.M`, `alpha/vN/vN.M`, and `release/vN/vN.M` branches with one\nrequired approving review, Code Owner review, stale-review dismissal,\nlatest-push approval, exact App-bound GitHub Actions checks, admin enforcement,\nconversation resolution, no force pushes, and no deletions; the bypass\nallowance only lets the named automation identity apply generated version-state\nor channel bookkeeping without a second human review after the reviewed channel\nPR has already merged.\n\nGitHub may return either `403` or a deliberately opaque `404` when a\nnon-administrator token reads the full branch-protection endpoint. In that\ncase, promotion reads the provider's branch summary and accepts only an\nalready-protected branch that enforces the exact required check for everyone.\nIt does not interpret the opaque response as missing protection or try to\nrewrite policy with a developer token. The independent publication-authority\naudit remains responsible for the complete read-only governance proof.\n\n## Publish Transactions\n\nPromotion can also own external publish side effects. Enable this only from a\ntrusted channel workflow:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n generated-ref-update-token: ${{ github.token }}\n sha: ${{ github.sha }}\n target-ref: release/v2/v2.0\n publish-transaction: \"true\"\n publish-mode: publish-final-version\n publish-auth: trusted-publishing\n publish-required-artifacts-json: >-\n [\n {\"kind\":\"npm\",\"name\":\"@kungfu-tech/buildchain\",\"ref\":\"2.0.0\",\"digest\":\"sha256:...\"}\n ]\n```\n\nFor anchored/manual package repositories that build through the reusable\nworkflow, keep the publish entrypoint on the `publish-gate/*` source-lock\ncontract:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n sha: ${{ needs.build.outputs.publish-source-sha }}\n target-ref: release/v22/v22.22\n require-publish-source-lock: \"true\"\n publish-source-ref: ${{ needs.build.outputs.publish-source-ref }}\n publish-source-sha: ${{ needs.build.outputs.publish-source-sha }}\n publish-source-locked: ${{ needs.build.outputs.publish-source-locked }}\n publish-transaction: \"true\"\n publish-mode: publish-final-version\n publish-auth: trusted-publishing\n```\n\n`target-ref` remains the channel promotion target that must point at `sha`.\n`publish-source-ref` is the reviewed source-lock branch that authorized this\nspecific package publication. Direct `alpha/*` or `release/*` channel refs are\nnot valid publish source locks when `require-publish-source-lock` is enabled,\nand a mismatched `publish-source-sha` fails before any promotion or publish side effects begin.\n\nConsumers that opt in to a product-owned final predicate set\n`require-publication-qualification: \"true\"` and pass the exact sealed\n`publication-capability-json`, complete `publication-gate-aggregate-json`, and\n`publication-qualification-receipt-json`. The action validates their canonical\ndigests, predicate identity, freshness, nonce, source, version, channel, target,\nand evidence bindings both before provider access and immediately before the\npublish transaction. Missing or drifted receipts fail before mutation. The\nreusable `release-candidate-promote.yml` workflow creates these values in a\nseparate credentialless consumer job; direct callers must preserve the same\ncontract and may pass previously consumed nonces through\n`publication-used-qualification-nonces-json`.\n\nThe reusable promote workflow serializes non-dry-run promotion intents per\nrepository and re-reads `target-ref` before checkout, dependency installation,\nrelease-candidate resolution, or publish-gate writes. If a queued intent asks\nfor an older SHA after the protected channel has advanced, the workflow records\nthe requested/current SHA pair, verifies that the current target is ahead of\nthe requested commit, and exits successfully as a superseded no-op. Diverged,\nbehind, or unreadable comparisons still fail closed.\nAfter queued-intent revalidation, the reusable workflow runs the canonical\nrelease-candidate resolver in metadata-only mode before installing candidate\ndependencies or starting the full promotion job. The full job resolves and\ndownloads the evidence again before any publish-gate or publication mutation.\nThis preserves the final exact-evidence trust check while making missing or\nstale PR-stage evidence fail early.\nThe action repeats that check at its mutation boundary for governed promotion\ncalls, closing the race between workflow preflight and action start. Direct\nnon-governed calls and dry-runs keep the strict target mismatch error so local\ndiagnostics cannot silently reinterpret a stale request.\nExpected manual dry-run failures remain visible in the workflow result and do\nnot create automated workflow-friction issues; issue reporting is reserved for\nnon-dry-run promotion failures.\nThe reusable build workflow performs the cheaper channel-ref preflight earlier:\nafter source-lock resolution and before the build matrix, it requires the target\nchannel ref such as `alpha/v22/v22.22` or `release/v22/v22.22` to already point\nat the locked `publish-source-sha`. If not, maintainers should merge the source\ncommit through the channel PR first.\n\nFor promote-only release candidates, attach the PR-stage reusable build evidence\nand fail before publish-gate side effects if it no longer matches:\n\n```yaml\n- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2\n with:\n token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}\n sha: ${{ needs.build.outputs.publish-source-sha }}\n target-ref: alpha/v22/v22.22\n promote-only-release-candidate: \"true\"\n release-candidate-passport-path: .buildchain/artifacts/release-candidate-passport.json\n release-candidate-build-summary-path: .buildchain/artifacts/build-summary.json\n```\n\nThe action validates repository, channel, source identity, platform matrix, and\nthe aggregate build-summary hash before it writes version state, opens\nrelease-state, runs publish transaction logic, or moves tags/branches. Source\nidentity accepts the exact source SHA, the PR merge ref SHA, or the promoted\nchannel HEAD's Git tree SHA matching the passport tree hash. If validation\nfails, run or attach the verified channel PR build first instead of promoting a\nstale or unproven artifact set.\n\nWhen enabled, the action creates or resumes a release transaction keyed by\nrepository, version, source SHA, and target ref. It persists that transaction to\na machine-managed branch under `buildchain/release-state/<version>`, with\n`state.json` and, once available, `evidence.json`. Fresh GitHub runners read\nthat durable ref before running publish, so reruns do not depend on a previous\nrunner's local `.buildchain` directory.\n\nConsumers whose publish lifecycle only assembles local release assets or\nPassport inputs may set `publish-rematerialize-on-resume: true`. After\nBuildchain restores and validates durable publish evidence, it replays that\nconsumer-owned lifecycle with the original transaction environment before\nPassport collection. This is explicit opt-in because registry publication and\nother provider mutations must not be replayed blindly; the option rejects\n`promote-existing-version`.\n\nThe action runs `lifecycle.publish` from `buildchain.toml` or the explicit\n`publish-command` input, then validates publish evidence before exact tags and\nfloating refs move. If durable state persistence fails, the action fails closed\nbefore publish or public ref finalization.\n\n`publish-mode` defaults to `publish-final-version`, the token-free path for\nnormal npm Trusted Publishing. Same-version alpha-to-latest recovery must be\ndeclared as `publish-mode: promote-existing-version` and\n`publish-auth: npm-token`; Buildchain runs `npm whoami` before it creates\nrelease-state or moves any `npm dist-tag`. The Trusted Publishing mode is not\nallowed to perform `npm dist-tag add`.\n\nBuildchain itself uses this path for npm. Its `lifecycle.publish` runs\n`node scripts/npm-publish-transaction.mjs`, which publishes\n`@kungfu-tech/buildchain` through npm Trusted Publishing and writes npm\nartifact evidence into the transaction before release refs move. The separate\n`.github/workflows/npm-publish.yml` workflow is dry-run only.\n\nPublish lifecycle environment:\n\n```text\nBUILDCHAIN_VERSION\nBUILDCHAIN_CHANNEL\nBUILDCHAIN_SOURCE_SHA\nBUILDCHAIN_TARGET_REF\nBUILDCHAIN_RELEASE_STATE\nBUILDCHAIN_EVIDENCE_DIR\nBUILDCHAIN_RELEASE_SHA\nBUILDCHAIN_RELEASE_MATERIAL_SHA\nBUILDCHAIN_PUBLISH_TOOLING_SHA\nBUILDCHAIN_PUBLISH_EVIDENCE\nBUILDCHAIN_REQUIRED_ARTIFACTS\n```\n\n`BUILDCHAIN_REQUIRED_ARTIFACTS` is the normalized requirement array after the\naction resolves a missing artifact `ref` to `BUILDCHAIN_VERSION`, or expands an\noptional `ref_template` containing exactly one `{version}`, and binds any\ndeclared provenance to the current release coordinate. Template expansion\nhappens after exact version selection; ambiguous or unsupported templates fail\nbefore `lifecycle.publish`. Requirement descriptors may omit `digest`; final\npublish evidence may not.\n\nThe action outputs `transaction-id`, `transaction-state`,\n`transaction-exact-tag`, `public-release-tag`, `transaction-release-sha`,\n`transaction-state-ref`, `transaction-state-sha`, `transaction-state-path`,\n`publish-evidence-path`, and `release-passport-path`, `release-passport-output-dir`,\n`release-passport-state-sha`, and `finalization-needed`.\n`transaction-state-ref` is the durable recovery location.\n`release-passport-state-sha` is the durable ref commit after the generated\n`release-passport/*` files have been uploaded into that recovery ref.\n`finalization-needed=true` means publish evidence is valid, but protected branch\nor ref finalization needs a later idempotent promotion run. For release\nfinalization, Buildchain may create a same-repository generated version-state\nPR when GitHub rejects the direct protected ref update; that PR is Buildchain\nbookkeeping, not a consumer-authored release change.\nSet `github-release: \"true\"` when the semver promotion should also publish the\npublic GitHub Release. After the release transaction reaches `complete` and\n`finalization-needed` is false, the action creates or updates the GitHub Release\nfor `public-release-tag`, applies deterministic metadata from the authoritative\npublication channel (`alpha` is a prerelease and never latest; `release`,\n`stable`, and `major` are stable and latest), and uploads the publish evidence\nfile plus generated release passport assets. Tag syntax remains the fallback for\nordinary callers that do not supply publication intent. For anchored/manual\npackage releases, `public-release-tag` is derived\nfrom the published package version, while `transaction-exact-tag` remains the\ninternal Buildchain transaction ref for recovery and audit. If the transaction is\nnot complete yet, the action defers GitHub Release publication to the next\nidempotent promotion run.\n\nAfter a publish transaction reaches `complete`, the action generates the unified\n`buildchain-release-passport` in `.buildchain/release-passport` by default and\npersists those files under `release-passport/` in the durable release-state ref.\nSet `release-passport-product-name` to record the consumer product name, for\nexample `Libnode`, instead of the default `Buildchain`.\nSet `release-passport-kfd-1-witness-jsons` to newline-separated KFD-1\ncontract-world witness JSON paths when released artifacts must prove\nbyte-for-byte KFD contract surfaces. Buildchain imports the KFD metadata from\n`@kungfu-tech/kfd`, freezes the witness, verifies artifact bytes, and writes the\nresult under the KFD-provided `kfd-1` passport section.\nSet `release-passport-kfd-2-claim-jsons` to newline-separated KFD-2 public\nrelease trust claim JSON paths when a release makes additional human/agent\nvisible claims. Buildchain requires each public claim to bind declared sources,\nmachine-readable evidence, hashes, artifact coordinates, verification results,\naudit boundary, responsibility state, and residual risk. Unbound claims fail\npassport verification; prose-only claims downgrade the KFD-2 audit.\nSet `release-passport-kfd-3-prebuild-witness-jsons` to newline-separated KFD-3\ncollaboration-interface pre-build witness paths, then provide artifact-side\nevidence with `release-passport-kfd-3-artifact-witness-jsons` or a\nproduct-owned `release-passport-kfd-3-artifact-verify-command` such as\n`kungfu agent verify --json`. Buildchain compares declared shipped public\nsurfaces with artifact-exposed public surfaces and writes the result under the\nKFD-provided `kfd-3` passport section.\nSet `release-passport-invariant-passport-jsons` to one or more product-owned\ninvariant Passport paths, or set `release-passport-invariant-passport-command`\nto a command that emits one canonical Passport JSON document. Buildchain does\nnot reinterpret product invariants: it verifies the declared semantic root,\nrequires a `verified` verdict, complete platform coverage, a clean exact source\nrevision, and then binds the result into `buildchain.release.json`. Missing,\nstale, falsified, incomplete, dirty, or tampered Passport evidence fails the\nrelease transaction closed.\nBuildchain's own release workflow sets `release-passport-buildchain-self-kfd:\n\"true\"`. In that mode the action generates Buildchain-owned KFD-1/2/3 witnesses\ninside the final version-state workspace, after the release transaction has\nmaterialized generated files such as `package.json` and `dist/site/*`. This\nkeeps self-hosted KFD witness hashes bound to the exact published package\ninstead of to a pre-promotion checkout.\nWhen present, the passport includes the aggregate build summary, platform\nartifact manifests, npm publish evidence, dist-tag promotion evidence, the\nrelease-state ref, trusted publishing metadata, and the Buildchain transaction\nresult. After the first passport upload, Buildchain backfills the durable\nrelease-state SHA into `buildchain.release.json` and persists the passport\nagain, so the consumer-side passport is a complete audit entrypoint. Set\n`release-passport: \"false\"` only for a controlled recovery run that must skip\npassport generation.\n\nFinalization recovery is anchored to the durable transaction, not to a single\nworkflow run SHA. After generated version-state bookkeeping is applied, the\ncurrent channel head can be the generated version-state commit or a historical\nmerge commit that contains or corresponds to the recorded `release_material_sha`;\nit does not have to equal the original `source_sha` or the transaction\n`release_sha`. Reruns accept exact tags that already point at the transaction\nrelease/material SHA or the finalized channel head, and continue moving any\nmissing floating tags or dev/alpha refs before marking the transaction\n`complete`.\n\nNormal reruns accept already-published artifacts only when evidence matches.\nMissing required artifacts can be published on the next run. Conflicting\nrefs, digests, or declared provenance put the transaction into\n`repair_required`; `abandoned` and\n`failed_permanently` also fail closed unless `publish-transaction-override` is\nset for a controlled repair. The same override may replace a stale transaction\nonly when its version, exact tag, target ref, and channel are unchanged, the\ntransaction is not complete, and it contains no published artifacts or\nevidence. This lets a newly admitted source retry a previously failed paper\npublication without weakening already-published facts.\n\nIn strict buildchain promotion, ref movement is also gated by the old ABV\ngovernance semantics:\n\n- when detailed target branch protection is readable, it must enforce\n protection for administrators and require approving PR review plus the strict\n `check` job from the `Verify` workflow; when GitHub withholds that\n administration endpoint from the workflow token, the exact transaction must\n instead prove a protected current head, same-repository merged PR,\n independent approval, and the required successful `check` from its configured\n GitHub App;\n- post-publish channel reconciliation reuses an already qualifying\n provider-enforced policy when the workflow token cannot read or rewrite the\n administrative protection document, and fails closed if the public branch\n summary no longer carries the required check for everyone;\n- alpha promotion must come from a merged same-repository PR\n `dev/vN/vN.M -> alpha/vN/vN.M`, or from a strict same-line\n `publish-gate/alpha/vN/vN.M/<version> -> alpha/vN/vN.M` source-lock PR;\n- release promotion must come from a merged same-repository PR\n `alpha/vN/vN.M -> release/vN/vN.M`, or from a strict same-line\n `publish-gate/release/vN/vN.M/<version> -> release/vN/vN.M` source-lock PR;\n- major promotion must come from a merged same-repository PR\n `release/vN/vN.M -> publish-gate/major`;\n- release promotion must have an exact alpha tag for the same patch line, and\n the release source tree must match that alpha tag tree, so release does not\n introduce new code after alpha;\n- anchored/manual release promotion may differ from that alpha tree only in\n declared `version.files` and the configured anchor manifest, and only when the\n checked-out release material has passed `lifecycle.verify` or the explicit\n `verification-command`;\n- generated release and next-alpha version-state trees can be verified locally\n with either the `verification-command` input or `buildchain.toml`\n `lifecycle.verify` before any tags or channel refs move.\n\nThe reusable promotion workflow keeps governance reads, generated status checks,\nand generated ref updates on the run-scoped `github.token`. When branch\nprotection rejects generated bookkeeping, it supplies `BUILDCHAIN_PROMOTION_TOKEN`\nonly through `generated-pull-request-token` so the same-repository recovery PR can\nbe listed or created without broadening the governance client. Protected branch\nreview and check rules guard human channel merges, while the reusable build trust\ngate checks the source-lock channel HEAD and merged same-repository PR lineage\nbefore heavy build runners start. This action still independently rechecks PR\nlineage, alpha/release tree equivalence, and generated version-state verification\nbefore moving channel refs and tags.\nThe reusable `release-candidate-promote.yml` wrapper defaults\n`branch-protection-bypass-apps` to `github-actions`, so flow-internal promotion\ncan complete generated `dev`/`alpha`/`release` bookkeeping while ordinary human\npushes and PR merges remain governed by the one-review branch protection rule.\nThe promotion action rejects alternate App slugs and every user or team bypass,\nso the mutation path cannot widen the authority descriptor.\n\nThe tag names intentionally follow the old ABV release semantics:\nexact release tags are `vX.Y.Z`, exact alpha tags are `vX.Y.Z-alpha.N`, floating\nrelease tags are minor/major tags such as `v2.0` and `v2`, and floating alpha\ntags are minor-line tags such as `v2.0-alpha` plus cross-minor major tags such\nas `v2-alpha`. A major alpha tag only moves for the highest minor in that major\nwith a published alpha, so older-line maintenance cannot roll consumers back.\nBare tags such as `1.0.0` are not\nmaintained as buildchain release entrypoints.\n\nRepository rulesets should protect exact tags, not every `v*` tag. A ruleset\nsuch as `refs/tags/v*` also protects floating channel tags like `v2.0-alpha` and `v2-alpha`,\nwhich Buildchain must update after exact tags and publish evidence are durable.\nUse an exact-tag rule such as `refs/tags/v*.*.*` for immutable evidence tags and\nleave floating channel tags mutable for the promotion token."
|
|
162
162
|
},
|
|
163
163
|
{
|
|
164
164
|
"id": "action:report-buildchain-issue",
|
|
@@ -534,7 +534,7 @@
|
|
|
534
534
|
],
|
|
535
535
|
"maturity": "preview",
|
|
536
536
|
"sourcePath": "docs/github-governance-authority.md",
|
|
537
|
-
"digest": "sha256:
|
|
537
|
+
"digest": "sha256:8484b18d5b0fe6d61d102d6b9cb9e18beac9f47ecb516d430fb5427518e2931f",
|
|
538
538
|
"headings": [
|
|
539
539
|
{
|
|
540
540
|
"level": 1,
|
|
@@ -567,7 +567,7 @@
|
|
|
567
567
|
"anchor": "mutation-and-rollback-boundary"
|
|
568
568
|
}
|
|
569
569
|
],
|
|
570
|
-
"markdown": "---\nstatus: draft\nperiod: ongoing\ntheme: github-governance-authority\ndoc_type: protocol\nsource_level: local-files\nconfidence: high\nsensitivity: public\nevidence_grade: B\nreview_state: unreviewed\nlast_reviewed: 2026-07-24\nai_provenance:\n model_family: GPT-5\n product: Codex\n generated_at: 2026-07-24\n limits: Live GitHub state and account recovery remain provider-controlled and must be re-audited.\n---\n\n# GitHub Governance Authority\n\nBuildchain treats GitHub governance as an independently verified, fail-closed\nauthority boundary. A green CI run, a CODEOWNERS file, an API success response,\nor an administrator's assertion is not sufficient by itself. The verifier\ncombines the exact CODEOWNERS bytes from the target base branch, classic branch\nprotection, every applicable repository or organization ruleset, account role\nclasses, plan capability, required checks, and provider-read completeness into\none short-lived immutable receipt.\n\nThe machine contract is\n`@kungfu-tech/buildchain/github-governance-authority`. Its policy root covers\nthe managed-zone repository and target-ref admission rules, the exact\nrequired-check context/App bindings and strict-update semantics for every\npublic authoritative target, the dual-account authority split, protected\nverifier paths, native review requirements, break-glass constraints, and the\nexplicit trust boundary.\n\n## Trust boundary and non-claims\n\nThe trusted computing base contains GitHub service integrity, retained\norganization-owner recovery custody, the `kungfu-origin` review/governance\nidentity, the exact Buildchain verifier, and official publication identities.\nThe protocol does not claim resistance to compromise of GitHub itself,\ncompromise of all retained owner and recovery anchors, or malicious control of\nall independent trust anchors. A governance receipt grants no GitHub\npermission and is not a bearer credential.\n\n`dongkeren` is the development and pull-request author identity.\n`kungfu-origin` is the independent Code Owner and governance identity. A\nqualifying receipt requires the development identity to be active without an\nadministrator or maintainer role and requires the review identity to retain the\nadmitted governance role. Account recovery and retained root custody remain\noutside normal contributor and workflow paths.\n\n## Effective policy\n\nThe verifier evaluates native provider layers together. Every authoritative\ntarget must require:\n\n- a pull request, at least one independent Code Owner approval, and a fresh\n approval after the latest reviewable push;\n- administrator enforcement, resolved review conversations, and a non-empty\n required-check set whose exact contexts, GitHub App producer identities, and\n strict-update setting match the versioned target policy;\n- no unapproved bypass actor, force push, or protected-ref deletion. Managed\n dev/alpha/release ref bookkeeping may admit only the exact GitHub Actions App\n identity versioned for that target; user and team bypass actors remain\n non-qualifying;\n- exact last-match ownership of CODEOWNERS and the governance descriptor,\n collector, rollout planner, and scheduled audit workflow;\n- complete readable GitHub API evidence. Missing, forbidden, ambiguous, or\n malformed provider state is non-qualifying.\n\nRepository and organization rulesets are additive to classic branch\nprotection. Inspecting only one layer is insufficient because an applicable\nbypass or weaker update path in another layer can invalidate the effective\npolicy.\n\n## Repository and plan admission\n\nThe 2026-07-24 baseline contains 16 managed repositories: 13 public and three\nprivate. Public repository names are versioned in the descriptor. Private\nrepository names are never emitted in public evidence; their identities are\nrepresented by stable roots derived from the GitHub provider repository ID,\nindependent of the governance policy root. This prevents a policy revision from\nchanging repository identity or creating a circular admission dependency. A\nnewly discovered repository or target ref is non-authoritative until explicitly\nadmitted.\n\nThe descriptor also versions every active public merge target. The full audit\nevaluates one receipt per authoritative target rather than assuming the default\nbranch represents dev, alpha, release, or major publish-gate branches. The live\ndefault branch is always included even if it drifts outside the registry, in\nwhich case it is non-qualifying. Retained historical channels and generated\nper-release publish-gate refs are not silently deleted or promoted to current\nauthority; they require an explicit registry revision before they can qualify.\n\nFor an admitted private repository, the active target set is the current\ndefault branch plus existing alpha/release siblings on the same version line.\nIts required-check bindings remain non-qualifying until their sanitized binding\nroots are sealed into the private identity entry after supported native\nprotection exists.\n\nPublic repositories can qualify on supported Free, Team, or Enterprise\nenforcement. Private repositories and organization-wide rules require Team or\nEnterprise capability. On an unsupported plan they remain explicitly\n`non-authoritative-plan-capability-required` and publication-ineligible. The\nverifier does not replace missing native enforcement with CI or documentation,\nand the implementation never makes a private repository public as a\nworkaround.\n\n## Read-only audit\n\nRun the organization audit without mutation:\n\n```bash\nbuildchain audit github-governance \\\n --organization kungfu-systems \\\n --output github-governance.json \\\n --json\n```\n\nLimit a canary to one repository:\n\n```bash\nbuildchain audit github-governance \\\n --repository kungfu-systems/buildchain \\\n --target-ref dev/v2/v2.14 \\\n --require-qualifying \\\n --json\n```\n\nProtected merge and publication consumers verify the receipt against the exact\nrepository, target base ref, policy root, freshness window, and exact\nBuildchain verifier source revision. Non-dry-run publication does not trust a\ncaller-supplied JSON hash: it mints a bounded token for the dedicated read-only\ngovernance auditor GitHub App, recollects live provider state with the exact\nBuildchain runtime, requires the resulting single-repository/single-target\naudit to qualify, and consumes that independently generated receipt. Missing\nApp configuration or unreadable provider state denies publication before\nprovider mutation. The publication authority workflow is itself an explicit\nCode Owner path.\n\nThe output is sanitized. Public repositories retain their public identity.\nPrivate repositories expose only an identity root, visibility class, target\nref, sanitized required-check bindings and fact roots, and a qualifying or\nnon-qualifying decision. Tokens, cookies, recovery material, private\nCODEOWNERS bytes, raw permission payloads, and credential-bearing URLs are\nnever included.\n\n## Mutation and rollback boundary\n\nLive role, ruleset, branch-protection, Actions, Environment, or repository\nchanges are separate from audit. Every mutation starts from a read-only\ninventory and a frozen rollback snapshot. A rollout plan binds both roots and\nlists the exact API operation, impact, expected observation, and inverse\noperation. Apply must stop on the first unexplained drift and must perform a\npost-change read-back before continuing to the next bounded canary.\n\nPlan one exact branch without mutation:\n\n```bash\nbuildchain github-governance plan \\\n --repository kungfu-systems/buildchain \\\n --branch dev/v2/v2.14 \\\n --required-check check \\\n --required-check-app-id check=15368 \\\n --required-approvals 1 \\\n --snapshot-output rollback.json \\\n --plan-output rollout.json\n```\n\nAn already protected check preserves its observed GitHub App binding. Every new\nrequired check must declare `--required-check-app-id <context>=<app-id>`;\ncontext-only replacement is rejected because it would broaden which producer\ncan satisfy the gate.\n\nClassic branch-protection bypass allowances and ruleset bypass actors are both\npart of the effective policy. Reconciliation writes explicit empty user, team,\nand App bypass lists and verifies those lists after apply; omitting the provider\nfield is not treated as removal because GitHub may preserve the prior value.\n\nThe plan prints a `planRoot`. Apply requires that exact root and stops if live\nprotection no longer matches the frozen inventory:\n\n```bash\nbuildchain github-governance apply \\\n --plan-json rollout.json \\\n --confirm-plan-root sha256:...\n```\n\nRollback is separately explicit and root-bound:\n\n```bash\nbuildchain github-governance rollback \\\n --plan-json rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nFor an admitted exact target, classic branch protection can also be compiled\ndirectly from the authority descriptor. This mode preserves both App-bound\nchecks and intentionally unbound check contexts such as Kungfu alpha's\n`build`, rather than guessing a provider App identity.\n\n```bash\nbuildchain github-governance protection-policy-plan \\\n --repository kungfu-systems/kungfu \\\n --branch alpha/v4/v4.0 \\\n --snapshot-output protection-rollback.json \\\n --plan-output protection-rollout.json\n\nbuildchain github-governance protection-policy-apply \\\n --plan-json protection-rollout.json \\\n --confirm-plan-root sha256:...\n\nbuildchain github-governance protection-policy-rollback \\\n --plan-json protection-rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nFor an admitted exact target, repository ruleset reconciliation compiles the\ntarget descriptor into the provider body. It replaces bypass actors with the\nexact provider-admitted desired set, requires fresh Code Owner approval and\nresolved review threads, and binds required checks plus strict-update semantics\nto the target policy. Newly synthesized managed rules include GitHub's explicit\ncanonical defaults so the frozen expected root matches provider read-back.\nRepository rulesets default to no bypass actors. The\ndescriptor's target-bound GitHub Actions allowance is an upper bound on\neffective provider state, not a requirement to add that actor to every\nprotection layer; when needed, the built-in App allowance is expressed by\nclassic branch protection. The target condition must contain exactly one\nbranch; unrelated rules and conditions are preserved in place.\n\n```bash\nbuildchain github-governance ruleset-policy-plan \\\n --repository kungfu-systems/buildchain \\\n --branch alpha/v2/v2.14 \\\n --ruleset-id 19518955 \\\n --snapshot-output ruleset-rollback.json \\\n --plan-output ruleset-rollout.json\n\nbuildchain github-governance ruleset-policy-apply \\\n --plan-json ruleset-rollout.json \\\n --confirm-plan-root sha256:...\n\nbuildchain github-governance ruleset-policy-rollback \\\n --plan-json ruleset-rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nThe narrower `ruleset-plan` mode changes only `bypass_actors`; it remains\navailable for a bypass-only canary, but it cannot prove that an effective\nruleset matches the target descriptor. Both modes require the frozen ruleset\nsnapshot root for rollback.\n\nPaid-plan purchase, billing, legal/account-owner decisions, and any operation\nthat could remove the last recoverable owner remain external human gates.\nBreak-glass is disabled by default and, if ever admitted, must be separately\nauthenticated, reason-bound, time-bounded, independently receipted, and\nfollowed by mandatory restoration and root comparison."
|
|
570
|
+
"markdown": "---\nstatus: draft\nperiod: ongoing\ntheme: github-governance-authority\ndoc_type: protocol\nsource_level: local-files\nconfidence: high\nsensitivity: public\nevidence_grade: B\nreview_state: unreviewed\nlast_reviewed: 2026-07-24\nai_provenance:\n model_family: GPT-5\n product: Codex\n generated_at: 2026-07-24\n limits: Live GitHub state and account recovery remain provider-controlled and must be re-audited.\n---\n\n# GitHub Governance Authority\n\nBuildchain treats GitHub governance as an independently verified, fail-closed\nauthority boundary. A green CI run, a CODEOWNERS file, an API success response,\nor an administrator's assertion is not sufficient by itself. The verifier\ncombines the exact CODEOWNERS bytes from the target base branch, classic branch\nprotection, every applicable repository or organization ruleset, account role\nclasses, plan capability, required checks, and provider-read completeness into\none short-lived immutable receipt.\n\nThe machine contract is\n`@kungfu-tech/buildchain/github-governance-authority`. Its policy root covers\nthe managed-zone repository and target-ref admission rules, the exact\nrequired-check context/App bindings and strict-update semantics for every\npublic authoritative target, the dual-account authority split, protected\nverifier paths, native review requirements, break-glass constraints, and the\nexplicit trust boundary.\n\n## Trust boundary and non-claims\n\nThe trusted computing base contains GitHub service integrity, retained\norganization-owner recovery custody, the `kungfu-origin` review/governance\nidentity, the exact Buildchain verifier, and official publication identities.\nThe protocol does not claim resistance to compromise of GitHub itself,\ncompromise of all retained owner and recovery anchors, or malicious control of\nall independent trust anchors. A governance receipt grants no GitHub\npermission and is not a bearer credential.\n\n`dongkeren` is the development and pull-request author identity.\n`kungfu-origin` is the independent Code Owner and governance identity. A\nqualifying receipt requires the development identity to be active without an\nadministrator or maintainer role and requires the review identity to retain the\nadmitted governance role. Account recovery and retained root custody remain\noutside normal contributor and workflow paths.\n\n## Effective policy\n\nThe verifier evaluates native provider layers together. Every authoritative\ntarget must require:\n\n- a pull request, at least one independent Code Owner approval, and a fresh\n approval after the latest reviewable push;\n- administrator enforcement, resolved review conversations, and a non-empty\n required-check set whose exact contexts, GitHub App producer identities, and\n strict-update setting match the versioned target policy;\n- no unapproved bypass actor, force push, or protected-ref deletion. Managed\n dev/alpha/release ref bookkeeping may admit only the exact GitHub Actions App\n identity versioned for that target; user and team bypass actors remain\n non-qualifying;\n- exact last-match ownership of CODEOWNERS and the governance descriptor,\n collector, rollout planner, and scheduled audit workflow;\n- complete readable GitHub API evidence. Missing, forbidden, ambiguous, or\n malformed provider state is non-qualifying.\n\nRepository and organization rulesets are additive to classic branch\nprotection. Inspecting only one layer is insufficient because an applicable\nbypass or weaker update path in another layer can invalidate the effective\npolicy.\n\n## Repository and plan admission\n\nThe 2026-07-24 baseline contains 16 managed repositories: 13 public and three\nprivate. Public repository names are versioned in the descriptor. Private\nrepository names are never emitted in public evidence; their identities are\nrepresented by stable roots derived from the GitHub provider repository ID,\nindependent of the governance policy root. This prevents a policy revision from\nchanging repository identity or creating a circular admission dependency. A\nnewly discovered repository or target ref is non-authoritative until explicitly\nadmitted.\n\nThe descriptor also versions every active public merge target. The full audit\nevaluates one receipt per authoritative target rather than assuming the default\nbranch represents dev, alpha, release, or major publish-gate branches. The live\ndefault branch is always included even if it drifts outside the registry, in\nwhich case it is non-qualifying. Retained historical channels and generated\nper-release publish-gate refs are not silently deleted or promoted to current\nauthority; they require an explicit registry revision before they can qualify.\n\nFor an admitted private repository, the active target set is the current\ndefault branch plus existing alpha/release siblings on the same version line.\nIts required-check bindings remain non-qualifying until their sanitized binding\nroots are sealed into the private identity entry after supported native\nprotection exists.\n\nPublic repositories can qualify on supported Free, Team, or Enterprise\nenforcement. Private repositories and organization-wide rules require Team or\nEnterprise capability. On an unsupported plan they remain explicitly\n`non-authoritative-plan-capability-required` and publication-ineligible. The\nverifier does not replace missing native enforcement with CI or documentation,\nand the implementation never makes a private repository public as a\nworkaround.\n\n## Read-only audit\n\nRun the organization audit without mutation:\n\n```bash\nbuildchain audit github-governance \\\n --organization kungfu-systems \\\n --output github-governance.json \\\n --json\n```\n\nLimit a canary to one repository:\n\n```bash\nbuildchain audit github-governance \\\n --repository kungfu-systems/buildchain \\\n --target-ref dev/v2/v2.14 \\\n --require-qualifying \\\n --json\n```\n\nProtected merge and publication consumers verify the receipt against the exact\nrepository, target base ref, policy root, freshness window, and exact\nBuildchain verifier source revision. Non-dry-run publication does not trust a\ncaller-supplied JSON hash: it mints a bounded token for the dedicated read-only\ngovernance auditor GitHub App, recollects live provider state with the exact\nBuildchain runtime, requires the resulting single-repository/single-target\naudit to qualify, and consumes that independently generated receipt. Missing\nApp configuration or unreadable provider state denies publication before\nprovider mutation. The publication authority workflow is itself an explicit\nCode Owner path.\n\nThe publication authority job and every reusable-workflow caller grant the\nbuilt-in `GITHUB_TOKEN` only `actions: read`, `checks: read`, `contents: read`,\nand `pull-requests: read`. The dedicated auditor App independently recollects\nthe organization-wide governance receipt, while these job-scoped permissions\nallow the exact publication transaction audit to resolve required check runs\nand merged pull-request review lineage. Omitting either read permission makes\nthe transaction evidence incomplete and therefore non-qualifying.\n\nThe output is sanitized. Public repositories retain their public identity.\nPrivate repositories expose only an identity root, visibility class, target\nref, sanitized required-check bindings and fact roots, and a qualifying or\nnon-qualifying decision. Tokens, cookies, recovery material, private\nCODEOWNERS bytes, raw permission payloads, and credential-bearing URLs are\nnever included.\n\n## Mutation and rollback boundary\n\nLive role, ruleset, branch-protection, Actions, Environment, or repository\nchanges are separate from audit. Every mutation starts from a read-only\ninventory and a frozen rollback snapshot. A rollout plan binds both roots and\nlists the exact API operation, impact, expected observation, and inverse\noperation. Apply must stop on the first unexplained drift and must perform a\npost-change read-back before continuing to the next bounded canary.\n\nPlan one exact branch without mutation:\n\n```bash\nbuildchain github-governance plan \\\n --repository kungfu-systems/buildchain \\\n --branch dev/v2/v2.14 \\\n --required-check check \\\n --required-check-app-id check=15368 \\\n --required-approvals 1 \\\n --snapshot-output rollback.json \\\n --plan-output rollout.json\n```\n\nAn already protected check preserves its observed GitHub App binding. Every new\nrequired check must declare `--required-check-app-id <context>=<app-id>`;\ncontext-only replacement is rejected because it would broaden which producer\ncan satisfy the gate.\n\nClassic branch-protection bypass allowances and ruleset bypass actors are both\npart of the effective policy. Reconciliation writes explicit empty user, team,\nand App bypass lists and verifies those lists after apply; omitting the provider\nfield is not treated as removal because GitHub may preserve the prior value.\n\nThe plan prints a `planRoot`. Apply requires that exact root and stops if live\nprotection no longer matches the frozen inventory:\n\n```bash\nbuildchain github-governance apply \\\n --plan-json rollout.json \\\n --confirm-plan-root sha256:...\n```\n\nRollback is separately explicit and root-bound:\n\n```bash\nbuildchain github-governance rollback \\\n --plan-json rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nFor an admitted exact target, classic branch protection can also be compiled\ndirectly from the authority descriptor. This mode preserves both App-bound\nchecks and intentionally unbound check contexts such as Kungfu alpha's\n`build`, rather than guessing a provider App identity.\n\n```bash\nbuildchain github-governance protection-policy-plan \\\n --repository kungfu-systems/kungfu \\\n --branch alpha/v4/v4.0 \\\n --snapshot-output protection-rollback.json \\\n --plan-output protection-rollout.json\n\nbuildchain github-governance protection-policy-apply \\\n --plan-json protection-rollout.json \\\n --confirm-plan-root sha256:...\n\nbuildchain github-governance protection-policy-rollback \\\n --plan-json protection-rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nFor an admitted exact target, repository ruleset reconciliation compiles the\ntarget descriptor into the provider body. It replaces bypass actors with the\nexact provider-admitted desired set, requires fresh Code Owner approval and\nresolved review threads, and binds required checks plus strict-update semantics\nto the target policy. Newly synthesized managed rules include GitHub's explicit\ncanonical defaults so the frozen expected root matches provider read-back.\nRepository rulesets default to no bypass actors. The\ndescriptor's target-bound GitHub Actions allowance is an upper bound on\neffective provider state, not a requirement to add that actor to every\nprotection layer; when needed, the built-in App allowance is expressed by\nclassic branch protection. The target condition must contain exactly one\nbranch; unrelated rules and conditions are preserved in place.\n\n```bash\nbuildchain github-governance ruleset-policy-plan \\\n --repository kungfu-systems/buildchain \\\n --branch alpha/v2/v2.14 \\\n --ruleset-id 19518955 \\\n --snapshot-output ruleset-rollback.json \\\n --plan-output ruleset-rollout.json\n\nbuildchain github-governance ruleset-policy-apply \\\n --plan-json ruleset-rollout.json \\\n --confirm-plan-root sha256:...\n\nbuildchain github-governance ruleset-policy-rollback \\\n --plan-json ruleset-rollout.json \\\n --confirm-rollback-root sha256:...\n```\n\nThe narrower `ruleset-plan` mode changes only `bypass_actors`; it remains\navailable for a bypass-only canary, but it cannot prove that an effective\nruleset matches the target descriptor. Both modes require the frozen ruleset\nsnapshot root for rollback.\n\nPaid-plan purchase, billing, legal/account-owner decisions, and any operation\nthat could remove the last recoverable owner remain external human gates.\nBreak-glass is disabled by default and, if ever admitted, must be separately\nauthenticated, reason-bound, time-bounded, independently receipted, and\nfollowed by mandatory restoration and root comparison."
|
|
571
571
|
},
|
|
572
572
|
{
|
|
573
573
|
"id": "manual:homebrew",
|
|
@@ -1258,7 +1258,7 @@
|
|
|
1258
1258
|
],
|
|
1259
1259
|
"maturity": "stable",
|
|
1260
1260
|
"sourcePath": "docs/publish-transaction.md",
|
|
1261
|
-
"digest": "sha256:
|
|
1261
|
+
"digest": "sha256:cde5256d5f6443a6d32b47783900a0677e973855266af5a360db8d4d112bb677",
|
|
1262
1262
|
"headings": [
|
|
1263
1263
|
{
|
|
1264
1264
|
"level": 1,
|
|
@@ -1321,7 +1321,7 @@
|
|
|
1321
1321
|
"anchor": "build-images-follow-up"
|
|
1322
1322
|
}
|
|
1323
1323
|
],
|
|
1324
|
-
"markdown": "# Publish Transaction\n\nBuildchain release promotion is not just tag movement. A release can also publish\nexternal artifacts: npm packages, Python wheels, OCI images, binary archives,\nmetadata manifests, or site deployment records. Those side effects are harder\nthan Git refs because most registries are append-only: a failed rerun must know\nwhich artifacts already exist, which are still missing, and whether any existing\nartifact conflicts with the release material.\n\nBuildchain v2 models that work as a release transaction.\n\n## Why This Exists\n\nThe old ABV workflow made Git refs the visible release authority. That was\nenough when \"release\" meant \"create a version commit, move tags, and let\ndownstream jobs react.\" It is not enough when a single publish run must also\nupload packages and images.\n\nThe failure mode to avoid is:\n\n1. publish an external artifact;\n2. fail before moving the exact release tag or floating channel refs;\n3. rerun from a new job id with no memory of the artifact;\n4. either republish something different or move refs without proving the\n already-published artifact matches the release.\n\nThe transaction gives reruns a stable identity and a machine-readable state so\nBuildchain can resume safely. The identity is:\n\n```text\nrepository + version + source_sha + target_ref\n```\n\nIt is not the GitHub Actions run id.\n\n## Durable State\n\n`actions/promote-buildchain-ref` stores release transaction state in a\nmachine-managed Git branch:\n\n```text\nrefs/heads/buildchain/release-state/<version>\n```\n\nThe branch contains:\n\n```text\nstate.json\nevidence.json # present after publish evidence exists\n```\n\nThe local `.buildchain/release-state/...` and\n`.buildchain/release-evidence/...` files are working copies. They are useful for\nlocal inspection and lifecycle commands, but they are not the durable truth for\nGitHub-hosted reruns. On action startup, Buildchain reads the durable state ref\nfirst, restores the local working copies, and only then decides whether to\npublish, repair, or finalize.\n\nEvery meaningful state transition is written to the durable ref before public\nrelease refs move. Release-state GitHub API reads and writes use retry/backoff\nfor transient service failures such as HTTP 5xx responses, connection resets,\ntimeouts, and \"other side closed\" socket failures. If the durable write still\ncannot be persisted after retries, the action fails closed.\n\nDurable release-state refs reserve their exact version even when the public exact\ntag was never created. If a later machine run sees a failed or repair-required\nstate for `vX.Y.Z-alpha.N` and cannot resume it with the same transaction\nidentity, alpha version selection must advance to the next prerelease instead\nof reusing or overwriting that failed transaction slot.\n\n## Lifecycle\n\nRepositories declare publish work in `.buildchain/buildchain.toml`:\n\n```toml\n[publish]\nmode = \"publish-final-version\"\nauth = \"trusted-publishing\"\ndist_tag = \"latest\"\npackage_set_order = \"platforms-first-main-last\"\nmain_package = \"@kungfu-tech/libnode\"\n\n[lifecycle.publish]\ncommands = [\n \"python scripts/publish_wheels.py\",\n \"node scripts/publish-images.mjs\",\n \"node scripts/write-publish-evidence.mjs\",\n]\n```\n\n`actions/promote-buildchain-ref` runs `lifecycle.publish` only when\n`publish-transaction: \"true\"` is set or when a `publish-command` input is\nprovided. The action sets:\n\n```text\nBUILDCHAIN_VERSION\nBUILDCHAIN_CHANNEL\nBUILDCHAIN_SOURCE_SHA\nBUILDCHAIN_TARGET_REF\nBUILDCHAIN_RELEASE_STATE\nBUILDCHAIN_EVIDENCE_DIR\nBUILDCHAIN_RELEASE_SHA\nBUILDCHAIN_RELEASE_MATERIAL_SHA\nBUILDCHAIN_PUBLISH_TOOLING_SHA\nBUILDCHAIN_PUBLISH_EVIDENCE\nBUILDCHAIN_REQUIRED_ARTIFACTS\nBUILDCHAIN_PUBLISH_MODE\nBUILDCHAIN_PUBLISH_AUTH\nBUILDCHAIN_NPM_DIST_TAG\nBUILDCHAIN_PACKAGE_SET_ORDER\nBUILDCHAIN_PACKAGE_SET_MAIN_PACKAGE\n```\n\nBuildchain itself uses this contract for npm publishing:\n\n```toml\n[lifecycle.publish]\ncommand = \"node scripts/npm-publish-transaction.mjs\"\n```\n\nThat script validates that `package.json` matches `BUILDCHAIN_VERSION`, runs\n`npm publish --access public --tag <BUILDCHAIN_NPM_DIST_TAG>` through npm Trusted\nPublishing, and writes npm artifact evidence before the promotion action moves\npublic refs.\n\n`BUILDCHAIN_RELEASE_MATERIAL_SHA` is the source material whose artifacts must\nmatch. `BUILDCHAIN_PUBLISH_TOOLING_SHA` identifies the publishing code. A repair\nrun may change tooling, but material drift fails closed.\n\n## Post-Publish Requirements And Artifact Provenance\n\n`publish-required-artifacts-json` is a pre-publish family declaration, not a\nrequest to guess registry digests. A descriptor must include `kind + name`; it\nmay omit `ref` and `digest`. The action resolves a missing `ref` to the exact\n`BUILDCHAIN_VERSION`. Registries whose exact refs add a stable prefix or suffix\nmay instead declare a `ref_template` containing exactly one `{version}`, such\nas `v{version}`. The template is expanded only after exact version selection,\nso a resumed alpha transaction receives the newly selected prerelease rather\nthan the checked-out version. Declaring both `ref` and `ref_template`, using\nanother placeholder, or leaving unmatched braces fails before\n`lifecycle.publish`. The action exports the normalized exact refs as\n`BUILDCHAIN_REQUIRED_ARTIFACTS`, runs `lifecycle.publish`, and then requires the\nfinal evidence to contain every exact member with a non-empty digest. Existing\ncallers may continue supplying exact refs and digests.\n\nOCI publishers can opt into strict per-artifact provenance by adding\n`action: built` or `action: reused`. Those artifacts carry two separate\ncoordinates:\n\n- `content`: the version, ref, source SHA, and material SHA that produced the\n immutable content;\n- `release`: the exact current version/ref, target ref, source SHA, and release\n material SHA that bind that content into this release.\n\nThis distinction permits truthful cross-version reuse without claiming that an\nold OCI config was rebuilt from current material. For an OCI artifact with an\naction, final evidence also requires `platform`, positive `contract_major`, and\n`verification` containing a public manifest result, exact ref and digest,\nplatform, contract major, optional parent digest, evidence location, and a\npassed named smoke policy. Buildchain cross-checks those values against the\nartifact and current transaction. Missing family members and ref, digest,\ncontent, release, or verification conflicts enter `repair_required` before\npublic refs move.\n\nExample reused OCI evidence entry (the pre-publish requirement may omit\n`ref`, `digest`, `release`, and the observed verification values):\n\n```json\n{\n \"group\": \"image\",\n \"kind\": \"oci\",\n \"name\": \"ghcr.io/kungfu-systems/base-linux\",\n \"ref\": \"1.2.0-alpha.3\",\n \"digest\": \"sha256:...\",\n \"action\": \"reused\",\n \"platform\": \"linux/amd64\",\n \"contract_major\": 1,\n \"content\": {\n \"version\": \"1.1.9\",\n \"ref\": \"1.1.9\",\n \"source_sha\": \"<source-sha>\",\n \"material_sha\": \"<material-sha>\"\n },\n \"release\": {\n \"version\": \"1.2.0-alpha.3\",\n \"ref\": \"1.2.0-alpha.3\",\n \"target_ref\": \"alpha/v1/v1.2\",\n \"source_sha\": \"<current-source-sha>\",\n \"material_sha\": \"<current-material-sha>\"\n },\n \"verification\": {\n \"public_manifest\": true,\n \"ref\": \"1.2.0-alpha.3\",\n \"digest\": \"sha256:...\",\n \"platform\": \"linux/amd64\",\n \"contract_major\": 1,\n \"evidence\": \"registry-inspect.json\",\n \"smoke\": {\n \"policy\": \"manifest-contract\",\n \"passed\": true,\n \"evidence\": \"smoke.json\"\n }\n }\n}\n```\n\n## Release Modes And Auth\n\nBuildchain distinguishes two npm release modes:\n\n| Mode | Use | Auth | npm operation |\n| --- | --- | --- | --- |\n| `publish-final-version` | normal alpha or stable publication | `trusted-publishing` | `npm publish --tag <alpha|vX.Y-alpha|latest>` |\n| `promote-existing-version` | same-version alpha-to-latest recovery | `npm-token` | `npm dist-tag add <pkg>@<version> latest` |\n\nThe normal libnode path is `publish-final-version`: publish an alpha package set\nsuch as `22.22.3-kf.3-alpha.0` with the `alpha` dist-tag, then publish a\ndistinct final package set such as `22.22.3-kf.3` with the `latest` dist-tag.\nGitHub-hosted npm Trusted Publishing can authorize those `npm publish` calls\nwhen the workflow grants `id-token: write`.\n\n`promote-existing-version` is deliberately separate. npm Trusted Publishing does\nnot authorize arbitrary registry-management operations such as `npm dist-tag\nadd`; it authorizes publish-time package provenance. Therefore same-version\npromotion must declare `auth = \"npm-token\"`. Buildchain runs an npm token\npreflight with `npm whoami` before it writes any release transaction state or\nmoves a dist-tag. Missing token auth fails early with a contract error instead\nof a late `E401` after publish evidence has started to move.\n\nFor package sets, `package_set_order = \"platforms-first-main-last\"` makes the\nmain package the visibility gate. Platform package side effects are planned or\nretried first, and the main package or main dist-tag move happens last.\n\nWhen the transaction reaches `complete`, `actions/promote-buildchain-ref`\ngenerates `.buildchain/release-passport/buildchain.release.json` and persists\nthe `release-passport/*` files into the durable `buildchain/release-state/...`\nref. The passport is the stable release artifact for agents and people: it\nlinks the package set, npm publish evidence, dist-tag evidence, build summary,\nplatform artifact manifests, trusted publishing metadata, release-state ref,\ndurable release-state SHA, and transaction result in one schema. Consumer\nrepositories can set `release-passport-product-name` so the passport names their\nproduct instead of the Buildchain default.\n\n## Evidence\n\nThe publish lifecycle must write JSON evidence. Buildchain validates common\nfields and required artifact identities before final refs move.\n\n```json\n{\n \"schema\": 1,\n \"version\": \"2.0.11\",\n \"channel\": \"release\",\n \"source_sha\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"release_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"target_ref\": \"release/v2/v2.0\",\n \"release_material_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"publish_tooling_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"artifacts\": [\n {\n \"group\": \"node\",\n \"kind\": \"npm\",\n \"name\": \"@kungfu-systems/example\",\n \"ref\": \"2.0.11\",\n \"digest\": \"sha256:...\"\n },\n {\n \"group\": \"image\",\n \"kind\": \"oci\",\n \"name\": \"ghcr.io/kungfu-systems/example\",\n \"ref\": \"2.0.11\",\n \"digest\": \"sha256:...\"\n }\n ]\n}\n```\n\nThe generic contract is intentionally small:\n\n- `version`, `channel`, `source_sha`, `release_sha`, and `target_ref` must match\n the promotion run;\n- dist-tag promotion evidence is written beside the publish evidence as\n `dist-tag-evidence.json` and is referenced from the generated passport;\n- required artifacts must appear in evidence;\n- evidence used by a GitHub-hosted rerun must either be stored in the durable\n state ref or be reconstructed by a machine-verifiable consumer command;\n- existing artifacts with the same identity and digest are accepted on rerun;\n- missing artifacts can be published by the next run;\n- an existing artifact with a different digest puts the transaction into\n `repair_required`.\n\nArtifact identity is `group + kind + name + ref`. A required artifact that omits\n`group` matches any group with the same `kind + name + ref`.\n\n## Registry Truth Contract\n\nBuildchain owns transaction orchestration, finalization ordering, durable state,\nand generic evidence validation. It does not embed registry clients for npm,\nPyPI, GHCR/OCI, GitHub Releases, S3, Conan, CMake packaging, or project-specific\ndownload pages.\n\nConsumer `lifecycle.publish` commands own registry truth. A valid consumer stage\nmust be idempotent and machine-verifiable:\n\n- inspect the target registry before publishing;\n- accept an existing exact artifact only when version, identity, digest, and\n release-source binding match;\n- publish missing required artifacts;\n- reject conflicting existing artifacts and write evidence that lets Buildchain\n move the transaction to `repair_required`;\n- write `BUILDCHAIN_PUBLISH_EVIDENCE` after every successful inspect/publish\n cycle;\n- leave floating aliases such as npm dist-tags, PyPI stable markers, OCI\n floating tags, GitHub Release \"published\" status, or download-page stable\n links to a finalization step after Buildchain evidence validation.\n\nThe first-class adapter surface is command-based. Projects may wrap npm, PyPI,\nGHCR/OCI, GitHub Release assets, archives, SBOMs, provenance, or checksums\nhowever they need, as long as they emit the common evidence contract.\n\n## States\n\nThe state machine is:\n\n```text\nprepared -> publishing -> published -> finalizing -> complete\n | | |\n v v v\n publish_failed repair_required failed_permanently\n |\n v\n abandoned\n```\n\nSupported states:\n\n| State | Meaning |\n| --- | --- |\n| `prepared` | Transaction identity was created, but publish has not started. |\n| `publishing` | Publish lifecycle is running or may have been interrupted. |\n| `publish_failed` | Publish command failed before valid evidence was produced. |\n| `published` | Evidence is valid; refs have not necessarily finalized. |\n| `finalizing` | Buildchain is moving exact/floating refs or needs a later run to do it. |\n| `complete` | Required evidence is valid and refs have finalized. |\n| `repair_required` | Existing evidence or artifact state conflicts with expected release material. |\n| `abandoned` | A human or controlled process abandoned this transaction, usually because a newer version supersedes it. |\n| `failed_permanently` | Recovery should not continue without explicit override. |\n\n`repair_required`, `abandoned`, and `failed_permanently` fail closed unless the\noperator passes an explicit override. That override is for controlled repair\nruns, not normal retry behavior.\n\n## Ref Ordering\n\nWhen publish transactions are enabled, promotion order is:\n\n1. verify target source and governance;\n2. create or reuse the version-state release commit;\n3. acquire or resume the release transaction;\n4. run `lifecycle.publish` or accept already-valid evidence;\n5. validate evidence and required artifacts;\n6. move exact release/prerelease tag;\n7. move floating tags and channel refs;\n8. mark the transaction `complete`.\n\nConsumer products that expose a signed well-known channel can opt into one\nadditional, deliberately final step with `publication-commit-command`. Before\nthat command runs, Buildchain has already completed the transaction, created\nthe public GitHub Release, and uploaded every release-passport file plus the\nexplicit PR-stage payload files selected by\n`github-release-payload-patterns`. The command is therefore a commit point for\ndiscovery authority, not another artifact publisher.\n\nThe command receives the exact version, source SHA, release SHA, release tag,\nrelease passport path, and downloaded payload directory through\n`BUILDCHAIN_PUBLICATION_COMMIT_*`. Optional consumer-owned dispatch/API\ncredentials and private signing material are exposed separately as\n`BUILDCHAIN_PUBLICATION_COMMIT_TOKEN` and\n`BUILDCHAIN_PUBLICATION_COMMIT_SIGNING_KEY`; Buildchain never logs, persists,\nor interprets either value. The command must write\n`.buildchain/publication-commit/evidence.json` (or another declared path below\n`.buildchain/`) with this contract:\n\n```json\n{\n \"schema\": \"kungfu-buildchain-publication-commit-evidence/v1\",\n \"status\": \"passed\",\n \"identity\": {\n \"version\": \"4.0.0-alpha.2\",\n \"sourceSha\": \"<source-sha>\",\n \"releaseSha\": \"<release-sha>\",\n \"releaseTag\": \"v4.0.0-alpha.2\"\n },\n \"publication\": {\n \"url\": \"https://example.test/.well-known/product/alpha.json\",\n \"payloadRoot\": \"sha256:<64-lowercase-hex>\"\n },\n \"readback\": {\n \"status\": \"passed\",\n \"url\": \"https://example.test/.well-known/product/alpha.json\",\n \"payloadRoot\": \"sha256:<same-root>\"\n },\n \"recovery\": {\n \"previousAuthority\": \"preserved\",\n \"rollbackReference\": \"sha256:<previous-root>\"\n }\n}\n```\n\nBuildchain rejects stale evidence, identity drift, non-public or mutable URLs,\nread-back root drift, and missing recovery evidence. It also rejects\n`standalone-binary-distribution=true` with a final commit command because that\nwould queue product mutations after the authority moved. On any command or\nread-back failure, the consumer must leave the previous well-known document\nauthoritative; Buildchain does not retry the command behind a successful\nreceipt.\n\nIf protected branch finalization is interrupted after publish evidence is\nvalid, the transaction can stop in `finalizing` and output\n`finalization-needed=true`. A later run resumes from the same transaction state\nand completes ref movement without republishing matching artifacts. New\nBuildchain-managed promotions first try to finish generated version-state\nbookkeeping with the promotion token directly. Before patching a protected\ngenerated bookkeeping ref, Buildchain emits every configured required check on\nthe exact generated version-state commit so branch protection can\nvalidate the automation path without a second build, then uses the generated\nref update token for the protected ref PATCH. If release finalization\nbookkeeping is still rejected, Buildchain creates or reuses a same-repository\n`buildchain/version-state/*` PR and leaves the transaction resumable with\n`finalization-needed=true`. Strict alpha uses the same protected PR fallback\nfor both its target channel and subsequent dev reconciliation. A later\nidempotent run continues only after the provider shows that the PR reached the\nprotected branch. The reusable wrapper binds that token to the run-scoped\n`github.token` and rejects user, team, or alternate App bypass actors.\n\nIf finalization fails after an exact Git tag, a channel branch, or dev/alpha\nsync ref has already moved, the next run reads the durable `finalizing` state\nand continues from the recorded transaction. The current workflow SHA may be a\ngenerated version-state commit, or a historical version-state merge commit, that\ncontains or corresponds to the transaction's `release_material_sha`; it does not\nhave to equal the original `source_sha` or the transaction `release_sha`. Exact\ntags are accepted when they already point at the transaction release/material\nSHA or the finalized channel head. Floating\nchannel tags and dev/alpha refs are then retried idempotently, and the\ntransaction is marked `complete` only after those public refs are consistent.\nWriting `complete` clears any stale `failure` value from earlier attempts, so\nthe durable `state.json` represents the successful final state instead of the\nlast transient error seen before a rerun.\nAn exact tag at an unrelated SHA is still a material conflict and blocks\nrecovery.\n\nFor anchored package versions, the package version and internal line tag are\nseparate transaction coordinates. A retry can correct a stale internal tag on\nan unfinished `published` or `finalizing` transaction only when its validated\nevidence and complete artifact set match the same package version, source,\nrelease material, and target. Buildchain additionally requires that the stale\ntag does not already point at the transaction and that the newly selected tag\nis unclaimed or already points at accepted release material. No registry publish\ncommand is rerun during this exact-tag rebind.\n\nGoverned retries distinguish unrelated channel advancement from advancement\nmade by their own durable transaction. An unrelated descendant remains an\nauditable `superseded-promotion` no-op. When the target ref is exactly the\nrecorded `release_sha` for the requested source, target, and expected version,\nBuildchain resumes finalization, restores publish evidence, and emits the\nrelease-passport paths needed by downstream controller receipts.\n\nPublication authority planning applies the same occupied-version rule as the\nlater mutation step. If a current alpha transaction already contains published\nmaterial and regenerating version state would create new release material, the\nplanner advances to the next alpha before sealing authority. It never seals the\nold published version and then lets the publisher discover a different version\ninside the mutation boundary.\n\nIf finalization fails after an exact Git tag is created, the next run reads the\ndurable `finalizing` state, verifies the exact tag points at the recorded\nrelease SHA, and retries the remaining floating refs. An exact tag at a\ndifferent SHA is a material conflict and blocks recovery.\n\n## CLI Recovery\n\nLocal recovery commands operate on the same state/evidence files:\n\n```bash\nnode scripts/release-transaction.mjs inspect --version v2.0.11\nnode scripts/release-transaction.mjs recover --version v2.0.11\nnode scripts/release-transaction.mjs finalize --version v2.0.11\nnode scripts/release-transaction.mjs abort --version v2.0.11 --superseded-by v2.0.12\n```\n\nThe CLI is a diagnostic and local repair surface. It reports the durable\n`state_ref`, but remote durable-ref writes and public Git ref finalization are\nowned by `actions/promote-buildchain-ref`, because that action runs inside the\nsame governed GitHub permissions and branch-protection checks as release\npromotion. In other words, CLI `finalize` can mark the local transaction state\ncomplete after valid evidence; the machine-operated public finalization path is\nto rerun the promotion action.\n\nWhen no state file exists, creation commands also require:\n\n```bash\n--repository kungfu-systems/buildchain \\\n--source-sha <sha> \\\n--release-sha <sha> \\\n--target-ref release/v2/v2.0 \\\n--channel release\n```\n\n## Build-Images Follow-Up\n\n`build-images` should consume this contract rather than inventing a separate\nworkflow rule. The expected integration shape is:\n\n- image build writes OCI digests into publish evidence;\n- required image families are passed through `publish-required-artifacts-json`\n before their final digests are known;\n- mixed built/reused evidence preserves content provenance separately from the\n current release binding;\n- reruns check GHCR or the target registry and accept existing images only when\n tag and digest match;\n- preview or alpha image tags remain non-stable until the transaction evidence\n validates;\n- production image aliases move only after all required image artifacts are\n present and the Buildchain exact release tag has finalized."
|
|
1324
|
+
"markdown": "# Publish Transaction\n\nBuildchain release promotion is not just tag movement. A release can also publish\nexternal artifacts: npm packages, Python wheels, OCI images, binary archives,\nmetadata manifests, or site deployment records. Those side effects are harder\nthan Git refs because most registries are append-only: a failed rerun must know\nwhich artifacts already exist, which are still missing, and whether any existing\nartifact conflicts with the release material.\n\nBuildchain v2 models that work as a release transaction.\n\n## Why This Exists\n\nThe old ABV workflow made Git refs the visible release authority. That was\nenough when \"release\" meant \"create a version commit, move tags, and let\ndownstream jobs react.\" It is not enough when a single publish run must also\nupload packages and images.\n\nThe failure mode to avoid is:\n\n1. publish an external artifact;\n2. fail before moving the exact release tag or floating channel refs;\n3. rerun from a new job id with no memory of the artifact;\n4. either republish something different or move refs without proving the\n already-published artifact matches the release.\n\nThe transaction gives reruns a stable identity and a machine-readable state so\nBuildchain can resume safely. The identity is:\n\n```text\nrepository + version + source_sha + target_ref\n```\n\nIt is not the GitHub Actions run id.\n\n## Durable State\n\n`actions/promote-buildchain-ref` stores release transaction state in a\nmachine-managed Git branch:\n\n```text\nrefs/heads/buildchain/release-state/<version>\n```\n\nThe branch contains:\n\n```text\nstate.json\nevidence.json # present after publish evidence exists\n```\n\nThe local `.buildchain/release-state/...` and\n`.buildchain/release-evidence/...` files are working copies. They are useful for\nlocal inspection and lifecycle commands, but they are not the durable truth for\nGitHub-hosted reruns. On action startup, Buildchain reads the durable state ref\nfirst, restores the local working copies, and only then decides whether to\npublish, repair, or finalize.\n\nEvery meaningful state transition is written to the durable ref before public\nrelease refs move. Release-state GitHub API reads and writes use retry/backoff\nfor transient service failures such as HTTP 5xx responses, connection resets,\ntimeouts, and \"other side closed\" socket failures. If the durable write still\ncannot be persisted after retries, the action fails closed.\n\nDurable release-state refs reserve their exact version even when the public exact\ntag was never created. If a later machine run sees a failed or repair-required\nstate for `vX.Y.Z-alpha.N` and cannot resume it with the same transaction\nidentity, alpha version selection must advance to the next prerelease instead\nof reusing or overwriting that failed transaction slot.\n\n## Lifecycle\n\nRepositories declare publish work in `.buildchain/buildchain.toml`:\n\n```toml\n[publish]\nmode = \"publish-final-version\"\nauth = \"trusted-publishing\"\ndist_tag = \"latest\"\npackage_set_order = \"platforms-first-main-last\"\nmain_package = \"@kungfu-tech/libnode\"\n\n[lifecycle.publish]\ncommands = [\n \"python scripts/publish_wheels.py\",\n \"node scripts/publish-images.mjs\",\n \"node scripts/write-publish-evidence.mjs\",\n]\n```\n\n`actions/promote-buildchain-ref` runs `lifecycle.publish` only when\n`publish-transaction: \"true\"` is set or when a `publish-command` input is\nprovided. The action sets:\n\n```text\nBUILDCHAIN_VERSION\nBUILDCHAIN_CHANNEL\nBUILDCHAIN_SOURCE_SHA\nBUILDCHAIN_TARGET_REF\nBUILDCHAIN_RELEASE_STATE\nBUILDCHAIN_EVIDENCE_DIR\nBUILDCHAIN_RELEASE_SHA\nBUILDCHAIN_RELEASE_MATERIAL_SHA\nBUILDCHAIN_PUBLISH_TOOLING_SHA\nBUILDCHAIN_PUBLISH_EVIDENCE\nBUILDCHAIN_REQUIRED_ARTIFACTS\nBUILDCHAIN_PUBLISH_MODE\nBUILDCHAIN_PUBLISH_AUTH\nBUILDCHAIN_NPM_DIST_TAG\nBUILDCHAIN_PACKAGE_SET_ORDER\nBUILDCHAIN_PACKAGE_SET_MAIN_PACKAGE\n```\n\nBuildchain itself uses this contract for npm publishing:\n\n```toml\n[lifecycle.publish]\ncommand = \"node scripts/npm-publish-transaction.mjs\"\n```\n\nThat script validates that `package.json` matches `BUILDCHAIN_VERSION`, runs\n`npm publish --access public --tag <BUILDCHAIN_NPM_DIST_TAG>` through npm Trusted\nPublishing, and writes npm artifact evidence before the promotion action moves\npublic refs.\n\n`BUILDCHAIN_RELEASE_MATERIAL_SHA` is the source material whose artifacts must\nmatch. `BUILDCHAIN_PUBLISH_TOOLING_SHA` identifies the publishing code. A repair\nrun may change tooling, but material drift fails closed.\n\n## Post-Publish Requirements And Artifact Provenance\n\n`publish-required-artifacts-json` is a pre-publish family declaration, not a\nrequest to guess registry digests. A descriptor must include `kind + name`; it\nmay omit `ref` and `digest`. The action resolves a missing `ref` to the exact\n`BUILDCHAIN_VERSION`. Registries whose exact refs add a stable prefix or suffix\nmay instead declare a `ref_template` containing exactly one `{version}`, such\nas `v{version}`. The template is expanded only after exact version selection,\nso a resumed alpha transaction receives the newly selected prerelease rather\nthan the checked-out version. Declaring both `ref` and `ref_template`, using\nanother placeholder, or leaving unmatched braces fails before\n`lifecycle.publish`. The action exports the normalized exact refs as\n`BUILDCHAIN_REQUIRED_ARTIFACTS`, runs `lifecycle.publish`, and then requires the\nfinal evidence to contain every exact member with a non-empty digest. Existing\ncallers may continue supplying exact refs and digests.\n\nOCI publishers can opt into strict per-artifact provenance by adding\n`action: built` or `action: reused`. Those artifacts carry two separate\ncoordinates:\n\n- `content`: the version, ref, source SHA, and material SHA that produced the\n immutable content;\n- `release`: the exact current version/ref, target ref, source SHA, and release\n material SHA that bind that content into this release.\n\nThis distinction permits truthful cross-version reuse without claiming that an\nold OCI config was rebuilt from current material. For an OCI artifact with an\naction, final evidence also requires `platform`, positive `contract_major`, and\n`verification` containing a public manifest result, exact ref and digest,\nplatform, contract major, optional parent digest, evidence location, and a\npassed named smoke policy. Buildchain cross-checks those values against the\nartifact and current transaction. Missing family members and ref, digest,\ncontent, release, or verification conflicts enter `repair_required` before\npublic refs move.\n\nExample reused OCI evidence entry (the pre-publish requirement may omit\n`ref`, `digest`, `release`, and the observed verification values):\n\n```json\n{\n \"group\": \"image\",\n \"kind\": \"oci\",\n \"name\": \"ghcr.io/kungfu-systems/base-linux\",\n \"ref\": \"1.2.0-alpha.3\",\n \"digest\": \"sha256:...\",\n \"action\": \"reused\",\n \"platform\": \"linux/amd64\",\n \"contract_major\": 1,\n \"content\": {\n \"version\": \"1.1.9\",\n \"ref\": \"1.1.9\",\n \"source_sha\": \"<source-sha>\",\n \"material_sha\": \"<material-sha>\"\n },\n \"release\": {\n \"version\": \"1.2.0-alpha.3\",\n \"ref\": \"1.2.0-alpha.3\",\n \"target_ref\": \"alpha/v1/v1.2\",\n \"source_sha\": \"<current-source-sha>\",\n \"material_sha\": \"<current-material-sha>\"\n },\n \"verification\": {\n \"public_manifest\": true,\n \"ref\": \"1.2.0-alpha.3\",\n \"digest\": \"sha256:...\",\n \"platform\": \"linux/amd64\",\n \"contract_major\": 1,\n \"evidence\": \"registry-inspect.json\",\n \"smoke\": {\n \"policy\": \"manifest-contract\",\n \"passed\": true,\n \"evidence\": \"smoke.json\"\n }\n }\n}\n```\n\n## Release Modes And Auth\n\nBuildchain distinguishes two npm release modes:\n\n| Mode | Use | Auth | npm operation |\n| --- | --- | --- | --- |\n| `publish-final-version` | normal alpha or stable publication | `trusted-publishing` | `npm publish --tag <alpha|vX.Y-alpha|latest>` |\n| `promote-existing-version` | same-version alpha-to-latest recovery | `npm-token` | `npm dist-tag add <pkg>@<version> latest` |\n\nThe normal libnode path is `publish-final-version`: publish an alpha package set\nsuch as `22.22.3-kf.3-alpha.0` with the `alpha` dist-tag, then publish a\ndistinct final package set such as `22.22.3-kf.3` with the `latest` dist-tag.\nGitHub-hosted npm Trusted Publishing can authorize those `npm publish` calls\nwhen the workflow grants `id-token: write`.\n\n`promote-existing-version` is deliberately separate. npm Trusted Publishing does\nnot authorize arbitrary registry-management operations such as `npm dist-tag\nadd`; it authorizes publish-time package provenance. Therefore same-version\npromotion must declare `auth = \"npm-token\"`. Buildchain runs an npm token\npreflight with `npm whoami` before it writes any release transaction state or\nmoves a dist-tag. Missing token auth fails early with a contract error instead\nof a late `E401` after publish evidence has started to move.\n\nFor package sets, `package_set_order = \"platforms-first-main-last\"` makes the\nmain package the visibility gate. Platform package side effects are planned or\nretried first, and the main package or main dist-tag move happens last.\n\nWhen the transaction reaches `complete`, `actions/promote-buildchain-ref`\ngenerates `.buildchain/release-passport/buildchain.release.json` and persists\nthe `release-passport/*` files into the durable `buildchain/release-state/...`\nref. The passport is the stable release artifact for agents and people: it\nlinks the package set, npm publish evidence, dist-tag evidence, build summary,\nplatform artifact manifests, trusted publishing metadata, release-state ref,\ndurable release-state SHA, and transaction result in one schema. Consumer\nrepositories can set `release-passport-product-name` so the passport names their\nproduct instead of the Buildchain default.\n\n## Evidence\n\nThe publish lifecycle must write JSON evidence. Buildchain validates common\nfields and required artifact identities before final refs move.\n\n```json\n{\n \"schema\": 1,\n \"version\": \"2.0.11\",\n \"channel\": \"release\",\n \"source_sha\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"release_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"target_ref\": \"release/v2/v2.0\",\n \"release_material_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"publish_tooling_sha\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n \"artifacts\": [\n {\n \"group\": \"node\",\n \"kind\": \"npm\",\n \"name\": \"@kungfu-systems/example\",\n \"ref\": \"2.0.11\",\n \"digest\": \"sha256:...\"\n },\n {\n \"group\": \"image\",\n \"kind\": \"oci\",\n \"name\": \"ghcr.io/kungfu-systems/example\",\n \"ref\": \"2.0.11\",\n \"digest\": \"sha256:...\"\n }\n ]\n}\n```\n\nThe generic contract is intentionally small:\n\n- `version`, `channel`, `source_sha`, `release_sha`, and `target_ref` must match\n the promotion run;\n- dist-tag promotion evidence is written beside the publish evidence as\n `dist-tag-evidence.json` and is referenced from the generated passport;\n- required artifacts must appear in evidence;\n- evidence used by a GitHub-hosted rerun must either be stored in the durable\n state ref or be reconstructed by a machine-verifiable consumer command;\n- existing artifacts with the same identity and digest are accepted on rerun;\n- missing artifacts can be published by the next run;\n- an existing artifact with a different digest puts the transaction into\n `repair_required`.\n\nArtifact identity is `group + kind + name + ref`. A required artifact that omits\n`group` matches any group with the same `kind + name + ref`.\n\n## Registry Truth Contract\n\nBuildchain owns transaction orchestration, finalization ordering, durable state,\nand generic evidence validation. It does not embed registry clients for npm,\nPyPI, GHCR/OCI, GitHub Releases, S3, Conan, CMake packaging, or project-specific\ndownload pages.\n\nConsumer `lifecycle.publish` commands own registry truth. A valid consumer stage\nmust be idempotent and machine-verifiable:\n\n- inspect the target registry before publishing;\n- accept an existing exact artifact only when version, identity, digest, and\n release-source binding match;\n- publish missing required artifacts;\n- reject conflicting existing artifacts and write evidence that lets Buildchain\n move the transaction to `repair_required`;\n- write `BUILDCHAIN_PUBLISH_EVIDENCE` after every successful inspect/publish\n cycle;\n- leave floating aliases such as npm dist-tags, PyPI stable markers, OCI\n floating tags, GitHub Release \"published\" status, or download-page stable\n links to a finalization step after Buildchain evidence validation.\n\nThe first-class adapter surface is command-based. Projects may wrap npm, PyPI,\nGHCR/OCI, GitHub Release assets, archives, SBOMs, provenance, or checksums\nhowever they need, as long as they emit the common evidence contract.\n\n## States\n\nThe state machine is:\n\n```text\nprepared -> publishing -> published -> finalizing -> complete\n | | |\n v v v\n publish_failed repair_required failed_permanently\n |\n v\n abandoned\n```\n\nSupported states:\n\n| State | Meaning |\n| --- | --- |\n| `prepared` | Transaction identity was created, but publish has not started. |\n| `publishing` | Publish lifecycle is running or may have been interrupted. |\n| `publish_failed` | Publish command failed before valid evidence was produced. |\n| `published` | Evidence is valid; refs have not necessarily finalized. |\n| `finalizing` | Buildchain is moving exact/floating refs or needs a later run to do it. |\n| `complete` | Required evidence is valid and refs have finalized. |\n| `repair_required` | Existing evidence or artifact state conflicts with expected release material. |\n| `abandoned` | A human or controlled process abandoned this transaction, usually because a newer version supersedes it. |\n| `failed_permanently` | Recovery should not continue without explicit override. |\n\n`repair_required`, `abandoned`, and `failed_permanently` fail closed unless the\noperator passes an explicit override. That override is for controlled repair\nruns, not normal retry behavior.\n\n## Ref Ordering\n\nWhen publish transactions are enabled, promotion order is:\n\n1. verify target source and governance;\n2. create or reuse the version-state release commit;\n3. acquire or resume the release transaction;\n4. run `lifecycle.publish` or accept already-valid evidence;\n5. validate evidence and required artifacts;\n6. move exact release/prerelease tag;\n7. move floating tags and channel refs;\n8. mark the transaction `complete`.\n\nWhen a protected channel requires a generated version-state pull request, the\nfirst run can stop at `finalizing` after registry publication. If the reviewed\nmerge commit later contains that exact transaction release material but the\nexact tag is still absent, a retry performs finalization only: it reloads the\nsame durable source, release material, tooling, evidence, version, and target\nbindings; creates the exact and floating tags at the transaction release SHA;\nand completes the passport from the transaction source tree. It does not rerun\nthe provider mutation and does not authorize the newer composite channel tree\nas published material. A different source tree still requires a new version and\na fresh release candidate.\n\nDeferred binary dispatch, controller-evidence bundling, and any consumer\npublication commit are skipped while `finalization-needed=true`. They run only\nafter the exact public tag and complete release passport exist.\n\nConsumer products that expose a signed well-known channel can opt into one\nadditional, deliberately final step with `publication-commit-command`. Before\nthat command runs, Buildchain has already completed the transaction, created\nthe public GitHub Release, and uploaded every release-passport file plus the\nexplicit PR-stage payload files selected by\n`github-release-payload-patterns`. The command is therefore a commit point for\ndiscovery authority, not another artifact publisher.\n\nThe command receives the exact version, source SHA, release SHA, release tag,\nrelease passport path, and downloaded payload directory through\n`BUILDCHAIN_PUBLICATION_COMMIT_*`. Optional consumer-owned dispatch/API\ncredentials and private signing material are exposed separately as\n`BUILDCHAIN_PUBLICATION_COMMIT_TOKEN` and\n`BUILDCHAIN_PUBLICATION_COMMIT_SIGNING_KEY`; Buildchain never logs, persists,\nor interprets either value. The command must write\n`.buildchain/publication-commit/evidence.json` (or another declared path below\n`.buildchain/`) with this contract:\n\n```json\n{\n \"schema\": \"kungfu-buildchain-publication-commit-evidence/v1\",\n \"status\": \"passed\",\n \"identity\": {\n \"version\": \"4.0.0-alpha.2\",\n \"sourceSha\": \"<source-sha>\",\n \"releaseSha\": \"<release-sha>\",\n \"releaseTag\": \"v4.0.0-alpha.2\"\n },\n \"publication\": {\n \"url\": \"https://example.test/.well-known/product/alpha.json\",\n \"payloadRoot\": \"sha256:<64-lowercase-hex>\"\n },\n \"readback\": {\n \"status\": \"passed\",\n \"url\": \"https://example.test/.well-known/product/alpha.json\",\n \"payloadRoot\": \"sha256:<same-root>\"\n },\n \"recovery\": {\n \"previousAuthority\": \"preserved\",\n \"rollbackReference\": \"sha256:<previous-root>\"\n }\n}\n```\n\nBuildchain rejects stale evidence, identity drift, non-public or mutable URLs,\nread-back root drift, and missing recovery evidence. It also rejects\n`standalone-binary-distribution=true` with a final commit command because that\nwould queue product mutations after the authority moved. On any command or\nread-back failure, the consumer must leave the previous well-known document\nauthoritative; Buildchain does not retry the command behind a successful\nreceipt.\n\nIf protected branch finalization is interrupted after publish evidence is\nvalid, the transaction can stop in `finalizing` and output\n`finalization-needed=true`. A later run resumes from the same transaction state\nand completes ref movement without republishing matching artifacts. New\nBuildchain-managed promotions first try to finish generated version-state\nbookkeeping with the promotion token directly. Before patching a protected\ngenerated bookkeeping ref, Buildchain emits every configured required check on\nthe exact generated version-state commit so branch protection can\nvalidate the automation path without a second build, then uses the generated\nref update token for the protected ref PATCH. If release finalization\nbookkeeping is still rejected, Buildchain creates or reuses a same-repository\n`buildchain/version-state/*` PR and leaves the transaction resumable with\n`finalization-needed=true`. Strict alpha uses the same protected PR fallback\nfor both its target channel and subsequent dev reconciliation. A later\nidempotent run continues only after the provider shows that the PR reached the\nprotected branch. The reusable wrapper binds that token to the run-scoped\n`github.token` and rejects user, team, or alternate App bypass actors.\n\nIf finalization fails after an exact Git tag, a channel branch, or dev/alpha\nsync ref has already moved, the next run reads the durable `finalizing` state\nand continues from the recorded transaction. The current workflow SHA may be a\ngenerated version-state commit, or a historical version-state merge commit, that\ncontains or corresponds to the transaction's `release_material_sha`; it does not\nhave to equal the original `source_sha` or the transaction `release_sha`. Exact\ntags are accepted when they already point at the transaction release/material\nSHA or the finalized channel head. Floating\nchannel tags and dev/alpha refs are then retried idempotently, and the\ntransaction is marked `complete` only after those public refs are consistent.\nWriting `complete` clears any stale `failure` value from earlier attempts, so\nthe durable `state.json` represents the successful final state instead of the\nlast transient error seen before a rerun.\nAn exact tag at an unrelated SHA is still a material conflict and blocks\nrecovery.\n\nFor anchored package versions, the package version and internal line tag are\nseparate transaction coordinates. A retry can correct a stale internal tag on\nan unfinished `published` or `finalizing` transaction only when its validated\nevidence and complete artifact set match the same package version, source,\nrelease material, and target. Buildchain additionally requires that the stale\ntag does not already point at the transaction and that the newly selected tag\nis unclaimed or already points at accepted release material. No registry publish\ncommand is rerun during this exact-tag rebind.\n\nGoverned retries distinguish unrelated channel advancement from advancement\nmade by their own durable transaction. An unrelated descendant remains an\nauditable `superseded-promotion` no-op. When the target ref is exactly the\nrecorded `release_sha` for the requested source, target, and expected version,\nBuildchain resumes finalization, restores publish evidence, and emits the\nrelease-passport paths needed by downstream controller receipts.\n\nPublication authority planning applies the same occupied-version rule as the\nlater mutation step. If a current alpha transaction already contains published\nmaterial and regenerating version state would create new release material, the\nplanner advances to the next alpha before sealing authority. It never seals the\nold published version and then lets the publisher discover a different version\ninside the mutation boundary.\n\nIf finalization fails after an exact Git tag is created, the next run reads the\ndurable `finalizing` state, verifies the exact tag points at the recorded\nrelease SHA, and retries the remaining floating refs. An exact tag at a\ndifferent SHA is a material conflict and blocks recovery.\n\n## CLI Recovery\n\nLocal recovery commands operate on the same state/evidence files:\n\n```bash\nnode scripts/release-transaction.mjs inspect --version v2.0.11\nnode scripts/release-transaction.mjs recover --version v2.0.11\nnode scripts/release-transaction.mjs finalize --version v2.0.11\nnode scripts/release-transaction.mjs abort --version v2.0.11 --superseded-by v2.0.12\n```\n\nThe CLI is a diagnostic and local repair surface. It reports the durable\n`state_ref`, but remote durable-ref writes and public Git ref finalization are\nowned by `actions/promote-buildchain-ref`, because that action runs inside the\nsame governed GitHub permissions and branch-protection checks as release\npromotion. In other words, CLI `finalize` can mark the local transaction state\ncomplete after valid evidence; the machine-operated public finalization path is\nto rerun the promotion action.\n\nWhen no state file exists, creation commands also require:\n\n```bash\n--repository kungfu-systems/buildchain \\\n--source-sha <sha> \\\n--release-sha <sha> \\\n--target-ref release/v2/v2.0 \\\n--channel release\n```\n\n## Build-Images Follow-Up\n\n`build-images` should consume this contract rather than inventing a separate\nworkflow rule. The expected integration shape is:\n\n- image build writes OCI digests into publish evidence;\n- required image families are passed through `publish-required-artifacts-json`\n before their final digests are known;\n- mixed built/reused evidence preserves content provenance separately from the\n current release binding;\n- reruns check GHCR or the target registry and accept existing images only when\n tag and digest match;\n- preview or alpha image tags remain non-stable until the transaction evidence\n validates;\n- production image aliases move only after all required image artifacts are\n present and the Buildchain exact release tag has finalized."
|
|
1325
1325
|
},
|
|
1326
1326
|
{
|
|
1327
1327
|
"id": "manual:readme-badges",
|
|
@@ -2154,6 +2154,7 @@
|
|
|
2154
2154
|
"branch-protection-bypass-users",
|
|
2155
2155
|
"dry-run",
|
|
2156
2156
|
"expected-publication-version",
|
|
2157
|
+
"generated-pull-request-token",
|
|
2157
2158
|
"generated-ref-update-token",
|
|
2158
2159
|
"generated-status-check-token",
|
|
2159
2160
|
"github-release",
|
|
@@ -2212,7 +2213,7 @@
|
|
|
2212
2213
|
"transaction-state-path",
|
|
2213
2214
|
"verification-command"
|
|
2214
2215
|
],
|
|
2215
|
-
"inputCount":
|
|
2216
|
+
"inputCount": 64
|
|
2216
2217
|
},
|
|
2217
2218
|
{
|
|
2218
2219
|
"id": "report-buildchain-issue",
|
|
@@ -3909,8 +3910,8 @@
|
|
|
3909
3910
|
"workflowRegistryPath": "dist/site/workflow-registry.json",
|
|
3910
3911
|
"pageRegistryPath": "dist/site/page-registry.json",
|
|
3911
3912
|
"cliRegistryDigest": "5ba7fd93a13993b05767b6f02d0626a7347f25c3d7cd4589ed4f70028c1f1bd1",
|
|
3912
|
-
"workflowRegistryDigest": "
|
|
3913
|
-
"pageRegistryDigest": "
|
|
3913
|
+
"workflowRegistryDigest": "c2abf629b205a96f536e8758c3d9cdb3eade6945294fe278774877ef41d90b60",
|
|
3914
|
+
"pageRegistryDigest": "16a40ed6f3848fcb6a743f9d0369b04e956dfb7b8548b1a7a79266f76b928c80"
|
|
3914
3915
|
},
|
|
3915
3916
|
"comparison": {
|
|
3916
3917
|
"missingCliRegistry": [],
|
|
@@ -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-24T13:47:59.986Z",
|
|
5
|
+
"publishedAt": "2026-07-24T13:47:59.986Z",
|
|
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": "f13e0810af995f59dd7e64752e0243454df80c7b",
|
|
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.18-alpha.
|
|
35
|
+
"version": "2.14.18-alpha.6",
|
|
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-24T13:47:59.986Z",
|
|
5
|
+
"publishedAt": "2026-07-24T13:47:59.986Z",
|
|
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": "f13e0810af995f59dd7e64752e0243454df80c7b",
|
|
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.18-alpha.
|
|
40
|
+
"version": "2.14.18-alpha.6",
|
|
41
41
|
"versionSource": "package.json#version"
|
|
42
42
|
},
|
|
43
43
|
"entrypoint": "buildchain-site.json",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"path": "docs/github-governance-authority.md",
|
|
94
94
|
"plane": "verify",
|
|
95
95
|
"exists": true,
|
|
96
|
-
"digest": "sha256:
|
|
96
|
+
"digest": "sha256:8484b18d5b0fe6d61d102d6b9cb9e18beac9f47ecb516d430fb5427518e2931f"
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
"id": "release-candidate",
|
|
@@ -245,7 +245,7 @@
|
|
|
245
245
|
"path": "docs/publish-transaction.md",
|
|
246
246
|
"plane": "verify",
|
|
247
247
|
"exists": true,
|
|
248
|
-
"digest": "sha256:
|
|
248
|
+
"digest": "sha256:cde5256d5f6443a6d32b47783900a0677e973855266af5a360db8d4d112bb677"
|
|
249
249
|
},
|
|
250
250
|
{
|
|
251
251
|
"id": "release-governance",
|
|
@@ -1867,6 +1867,7 @@
|
|
|
1867
1867
|
"branch-protection-bypass-users",
|
|
1868
1868
|
"dry-run",
|
|
1869
1869
|
"expected-publication-version",
|
|
1870
|
+
"generated-pull-request-token",
|
|
1870
1871
|
"generated-ref-update-token",
|
|
1871
1872
|
"generated-status-check-token",
|
|
1872
1873
|
"github-release",
|
|
@@ -1925,7 +1926,7 @@
|
|
|
1925
1926
|
"transaction-state-path",
|
|
1926
1927
|
"verification-command"
|
|
1927
1928
|
],
|
|
1928
|
-
"inputCount":
|
|
1929
|
+
"inputCount": 64,
|
|
1929
1930
|
"capabilityGroup": "release-passport-trust",
|
|
1930
1931
|
"status": "active"
|
|
1931
1932
|
},
|
|
@@ -140,6 +140,14 @@ App configuration or unreadable provider state denies publication before
|
|
|
140
140
|
provider mutation. The publication authority workflow is itself an explicit
|
|
141
141
|
Code Owner path.
|
|
142
142
|
|
|
143
|
+
The publication authority job and every reusable-workflow caller grant the
|
|
144
|
+
built-in `GITHUB_TOKEN` only `actions: read`, `checks: read`, `contents: read`,
|
|
145
|
+
and `pull-requests: read`. The dedicated auditor App independently recollects
|
|
146
|
+
the organization-wide governance receipt, while these job-scoped permissions
|
|
147
|
+
allow the exact publication transaction audit to resolve required check runs
|
|
148
|
+
and merged pull-request review lineage. Omitting either read permission makes
|
|
149
|
+
the transaction evidence incomplete and therefore non-qualifying.
|
|
150
|
+
|
|
143
151
|
The output is sanitized. Public repositories retain their public identity.
|
|
144
152
|
Private repositories expose only an identity root, visibility class, target
|
|
145
153
|
ref, sanitized required-check bindings and fact roots, and a qualifying or
|
|
@@ -363,6 +363,21 @@ When publish transactions are enabled, promotion order is:
|
|
|
363
363
|
7. move floating tags and channel refs;
|
|
364
364
|
8. mark the transaction `complete`.
|
|
365
365
|
|
|
366
|
+
When a protected channel requires a generated version-state pull request, the
|
|
367
|
+
first run can stop at `finalizing` after registry publication. If the reviewed
|
|
368
|
+
merge commit later contains that exact transaction release material but the
|
|
369
|
+
exact tag is still absent, a retry performs finalization only: it reloads the
|
|
370
|
+
same durable source, release material, tooling, evidence, version, and target
|
|
371
|
+
bindings; creates the exact and floating tags at the transaction release SHA;
|
|
372
|
+
and completes the passport from the transaction source tree. It does not rerun
|
|
373
|
+
the provider mutation and does not authorize the newer composite channel tree
|
|
374
|
+
as published material. A different source tree still requires a new version and
|
|
375
|
+
a fresh release candidate.
|
|
376
|
+
|
|
377
|
+
Deferred binary dispatch, controller-evidence bundling, and any consumer
|
|
378
|
+
publication commit are skipped while `finalization-needed=true`. They run only
|
|
379
|
+
after the exact public tag and complete release passport exist.
|
|
380
|
+
|
|
366
381
|
Consumer products that expose a signed well-known channel can opt into one
|
|
367
382
|
additional, deliberately final step with `publication-commit-command`. Before
|
|
368
383
|
that command runs, Buildchain has already completed the transaction, created
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kungfu-tech/buildchain",
|
|
3
|
-
"version": "2.14.18-alpha.
|
|
3
|
+
"version": "2.14.18-alpha.6",
|
|
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",
|