Release Candidate Passport
The release-candidate passport is the pre-promotion evidence contract produced after a reusable build matrix succeeds and before any publish-gate side effects run. It is different from the release passport:
release-candidate-passport.jsonproves which source SHA, channel, runtime, workflow run, and platform artifacts were verified before promotion.buildchain.release.jsonis generated after publish finalization and remains the durable audit entrypoint for the published release.
Enable it on the reusable build workflow:
jobs:
build:
uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v3
with:
artifact-name: libnode
release-candidate: true
publish-channel: alpha
publish-source-ref: publish-gate/alpha/v22/v22.22/22.22.3-kf.3-alpha.7
When the platform matrix and aggregate summaries complete, Buildchain uploads:
<artifact-name>-release-candidate-<publish-source-sha>
The passport contract is kungfu-buildchain-release-candidate-passport. It
contains:
- repository and pull request context;
- target channel, target ref, and product version or a non-publish
source-<shortSha>candidate label; - source head SHA, merge ref SHA, and the Git
HEAD^{tree}SHA for PR merge equivalence after the channel PR lands; - Buildchain runtime ref/SHA and workflow shell ref;
- workflow run id/attempt/url;
- normalized platform matrix and artifact summaries;
- the hash of the aggregate
build-summary.json.
Promotion workflows that should not rebuild artifacts can enable:
- uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v3
with:
token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}
sha: ${{ needs.build.outputs.publish-source-sha }}
target-ref: alpha/v22/v22.22
promote-only-release-candidate: "true"
release-candidate-passport-path: .buildchain/artifacts/release-candidate-passport.json
release-candidate-build-summary-path: .buildchain/artifacts/build-summary.json
With promote-only-release-candidate: "true", promotion fails before
version-state, publish transaction, tag, or branch side effects when the
passport does not match the repository, channel, source identity, platform
matrix, or build-summary hash. Source identity accepts the exact PR source SHA,
the PR merge ref SHA, or an exact Git tree match with the promoted channel HEAD;
this keeps post-merge channel commits strict without forcing a rebuild. The
Buildchain-owned promotion workflow resolves the matching same-repository
merged channel PR and downloads its PR-stage RC passport automatically before
promotion starts. The consumer wrapper defaults to a PR-stage workflow file
named build.yml with display name Build, and filters the RC passport and
build summary by the configured artifact-name before promotion. It also
downloads payload artifacts from the same PR-stage run, validates the required
payload count, passes downloaded platform manifests into the release passport,
and either forwards an explicit publish-required-artifacts-json value or
generates one before calling promote-buildchain-ref. Before that call, the
wrapper creates or updates publish-gate/{alpha,release,major} to the
promotion channel commit and passes that ref, target SHA, and locked=true to
the promote action with require-publish-source-lock: "true". Consumers using
floating @v3 therefore get publish-side source-lock drift protection without
copying resolver or promote YAML. The default npm path
generates that requirement list from the downloaded .tgz payloads themselves:
Buildchain reads package/package.json inside each tarball for the real scoped
package name and version, computes npm-style sha512-... integrity over the
tarball bytes, marks publish-package-main as role: main, and marks every
other package as role: platform. Consumer workflows therefore stay
declarative and do not need their own artifact download or publish-evidence
generation scripts.
Because a channel merge can trigger promotion before its PR-stage matrix has finished uploading evidence, the resolver waits up to ten minutes for the exact merged PR’s successful workflow run and paired artifacts. Polling remains bound to the PR/head identity; timeout or a sibling run still fails closed.
The public promotion router preserves the requested vN or vN-alpha ref as
audit metadata, but binds the router to GitHub’s selected reusable-workflow SHA
and resolves each remaining floating shell/runtime ref exactly once. Every
later checkout and delegated promotion receives those immutable SHAs, so a
channel tag moving during the run cannot mix two Buildchain revisions.
If a promote-only run failed after its consumer commit was already merged and its PR-stage artifacts were built, rerun the complete failed workflow after the fixed Buildchain channel is published:
gh run rerun <run-id> --repo <owner>/<consumer>
Use a complete rerun, not --failed, so GitHub resolves the reusable workflow
again. The release-candidate resolver reuses the existing candidate artifacts,
and the durable publication transaction makes the recovery idempotent; do not
open a replacement consumer PR or rebuild the native matrix solely for this
router failure.
By default, the wrapper forwards GitHub Release publication to the underlying
promote-buildchain-ref semver model. Once the release transaction is complete,
the action creates or updates the public GitHub Release, applies
prerelease/latest metadata from the authoritative publication channel (falling
back to semver tag syntax only for ordinary callers without that intent), and
uploads the publish evidence file together with the generated release passport
assets. This keeps
npm/registry publication, Buildchain release passport persistence, and
release.published propagation in one declarative reusable workflow. Consumers
that do not publish GitHub Releases can opt out with github-release: false.
For anchored/manual package releases, the public GitHub Release tag defaults to
v<publishedVersion> while the internal transaction exact tag remains recorded
in the release passport.
Standalone binary publication is a separate consumer capability. The promotion
wrapper does not assume that an npm-only repository provides
.github/workflows/binary-distribution.yml. Repositories that own that workflow
opt in with standalone-binary-distribution: true; Buildchain’s self-promotion
does so explicitly. Once enabled, a missing or invalid binary workflow remains a
hard failure rather than being silently skipped.
Products that publish KFD release trust evidence can keep that path declarative too. Pass KFD-1 self contract witnesses, KFD-2 public claim files, and KFD-3 pre-build/artifact evidence into the wrapper:
jobs:
promote:
uses: kungfu-systems/buildchain/.github/workflows/release-candidate-promote.yml@v3
with:
buildchain-channel: auto
buildchain-alpha-contract-lock-path: .buildchain/alpha-contract-lock.json
buildchain-stable-contract-lock-path: .buildchain/contract-lock.json
channel: alpha
artifact-name: libnode
release-passport-kfd-1-witness-jsons: .buildchain/kfd/kfd-1/standard-contract.witness.json
release-passport-kfd-2-claim-jsons: .buildchain/kfd/kfd-2/release-claims.json
release-passport-kfd-3-prebuild-witness-jsons: .buildchain/kfd/kfd-3/collaboration-interface.prebuild.json
release-passport-kfd-3-artifact-verify-command: kungfu agent verify --json
Buildchain forwards those declarations into promote-buildchain-ref, verifies
KFD-1 source/artifact contract surfaces, audits KFD-2 public release claims, and
compares KFD-3 declared shipped public surfaces with artifact-exposed public
surfaces. The release passport records the results under kfd-1, kfd-2, and
the KFD-provided kfd-3 section.
Managed consumers may also ask the promotion wrapper to assemble sealed publication evidence from the exact release candidate instead of producing short-lived admission JSON in repository-specific workflow code:
publication-auto-admission: true
publication-auto-no-gate: true
publication-publisher-workflow-path: .github/workflows/buildchain-ref-promotion.yml
publication-product: Example Product
publication-target: npm:@example/product
publication-package-name: "@example/product"
publication-auto-no-gate is an explicit consumer decision, not a default. A
consumer with a Shifu Gate registry supplies publication-gate-aggregate-json
instead. Buildchain still requires caller-owned RC evidence, an exact authority
runtime and source SHA, a repository-local publisher workflow, matching npm
target/package identity or exact caller-bound GitHub Release target, and a
qualifying control-plane audit.
GitHub-Release-only consumers use the same managed admission without inventing an npm package identity:
publication-auto-admission: true
publication-auto-no-gate: true
publication-publisher-workflow-path: .github/workflows/buildchain-ref-promotion.yml
publication-product: Example Binary
publication-target: github-release:example/example-binary
publication-package-name: ""
The target must exactly match the caller repository. Buildchain audits the job-scoped GitHub token, exact release-candidate payloads and manifests, protected channel lineage, and public release transaction before allowing the GitHub Release mutation.
A consumer that owns additional product qualification semantics can opt in to the sealed handoff without teaching Buildchain those semantics:
publication-consumer-predicate-id: kungfu.release-admission/v1
publication-consumer-qualification-command: node scripts/qualify-release.mjs
The command reads BUILDCHAIN_PUBLICATION_CAPABILITY_PATH and
BUILDCHAIN_PUBLICATION_GATE_AGGREGATE_PATH, evaluates the complete aggregate,
and writes a decision JSON document to
BUILDCHAIN_PUBLICATION_QUALIFICATION_RESULT_PATH. It also receives
BUILDCHAIN_PUBLICATION_PREDICATE_ID and
BUILDCHAIN_PUBLICATION_PREDICATE_DIGEST. The separate qualification job has
no write or OIDC permission and does not inherit publication secrets. A
successful deterministic receipt is rechecked by the provider action
immediately before mutation. Omitting both inputs preserves the existing
consumer contract; supplying only one fails closed.