---
status: draft
period: ongoing
theme: sealed-publication-authority
doc_type: protocol
source_level: local-files
confidence: high
sensitivity: public
evidence_grade: B
review_state: unreviewed
last_reviewed: 2026-07-31
ai_provenance:
  model_family: GPT-5
  product: Codex
  generated_at: 2026-07-15
  limits: Live provider configuration must be re-audited; no credential values are represented.
---

# Sealed Publication Authority

Buildchain publication authority is a closed-world, fail-closed protocol. It does
not mint registry or cloud credentials. It independently verifies whether an
already protected publication job is allowed to request a short-lived provider
credential for one exact product, target, version, channel, and artifact digest.

The machine-readable authority inventory is
`dist/site/publication-authority-registry.json`. Any workflow with a write,
environment, OIDC, cloud credential, registry publish, release, or Git push
signal must have an explicit descriptor. A new authority-bearing workflow that
is absent from the inventory fails site generation. Unknown workflows and every
descriptor not marked `product-publication` are denied product publication.

## Evidence chain

A qualifying admission binds exact source and runtime SHAs; contract, consumer
policy, qualifying controller receipt, Shifu/Gate aggregate, artifact, runner,
and control-plane digests; repository, authority workflow, provider publisher
workflow, Environment policy,
product, target, version, and channel; plus a unique nonce and a lifetime of no
more than 15 minutes. Every expected binding is mandatory at verification time;
an omitted expected field is not a wildcard.

The independent verifier recomputes every digest and ignores a producer's own
allow/deny conclusion. It fetches the exact evidence run, validates the actual
release-candidate passport and referenced qualifying controller receipt,
recomputes the Shifu Gate aggregate or explicit consumer-owned no-Gate policy,
recomputes the downloaded artifact manifests, and hashes every declared product
payload file against those manifests. The `.buildchain/` diagnostics envelope is
bound by the manifest digest but excluded from the product-byte set because it can
be finalized after the lifecycle scan. The verifier also compares the PR evidence tree to the
admitted post-merge source commit tree. It rejects an unknown
workflow, stale or replayed nonce, runner downgrade, control-plane drift,
source/runtime mismatch, and artifact substitution. A successful result is a
scoped capability receipt, not a bearer credential.

## Runner and control-plane evidence

Runner evidence uses exactly four classes: `ephemeral`, `reimaged`,
`persistent-measured`, and `unqualified`. Ephemeral runners also record their
job-isolation boundary. Reimaged and persistent runners qualify only when a
clean baseline is proven and baseline, toolchain, cache-contract, and task-
isolation digests are all present. Otherwise they still emit diagnostic
evidence with `qualificationStatus = unqualified`, but cannot receive a product
capability.

The external audit records digests and pass/fail status for repository Actions
defaults, classic branch protection or an active matching repository ruleset,
declared protected Environment policy or an explicit no-Environment binding,
job-scoped credentials,
absence of long-lived workflow publication credentials, provider authority,
and authorized runner class. Provider modes are `npm-trusted-publisher`,
`github-token`, and `oidc-role`. The OIDC-role mode consumes only a sanitized
provider audit containing a role digest and qualifying decision; raw IAM policy,
tokens, or credentials are rejected. Package-owner, cloud-root, GitHub
administrator, and registry-root credentials remain outside Buildchain's trust
boundary. Missing or unreadable facts fail closed.

An unauthenticated local npm CLI is not evidence that Trusted Publishing is
missing. `npm whoami` reports only the local CLI session and does not report the
OIDC identity that npm creates during `npm publish`. The default read-only audit
therefore binds the exact provider, repository, caller workflow, optional
Environment, job-scoped OIDC permission, and absence of long-lived credentials,
then records `provider-at-transaction`: npm makes the final authorization
decision when `npm publish` exchanges the job's OIDC token. A missing or drifted
trusted-publisher configuration consequently denies the transaction safely; it
is not preflighted through an unrelated long-lived npm login.

An authenticated external auditor can add stronger point-in-time evidence by
supplying sanitized `npm trust list --json` output with `--npm-trust-json`. This
changes the publisher fact to `audited-control-plane`; the workflow never runs
`npm trust list` itself and never receives that auditor's npm credential.

The credential-free collector proves effective Actions and runner scope from
the publication workflow fetched at `--workflow-ref`: explicit read-only
workflow defaults, job-scoped write/OIDC permissions, and an exact GitHub-hosted
runner label. It does not call repository Actions-default or self-hosted-runner
administration endpoints. Branch/ruleset and OIDC subject facts remain live
read-only provider queries. When the detailed branch-protection endpoint is not
readable with the workflow token, `--source-sha` binds the provider's public
protected-branch summary to the exact merged PR, independent approval, required
successful check, same-repository lineage, and current branch head. This records
provider-enforced transaction evidence without treating an unavailable
administration endpoint as an unprotected branch. It avoids turning a
repository-admin token into a publication prerequisite.
When a legacy caller declares a reusable job id such as `build`, the collector
accepts it only if the protected branch exposes exactly one required context
under `build / ...`; it then verifies that exact context, configured app, and PR
head SHA. Exact declarations remain unchanged, and ambiguous prefixes fail
closed.

For non-dry-run workflows, missing admission, runner, control-plane, Gate, or
expected-binding evidence is rejected before Buildchain downloads candidate
artifacts. The denial explicitly records that npm Trusted Publishing and OIDC
were not evaluated, so downstream diagnostics cannot misclassify an admission
assembly failure as an npm authentication failure.

An explicitly opted-in managed `workflow_run` promotion lane may assemble those
inputs from evidence owned by its caller repository. It downloads the exact prior RC passport,
summary, referenced controller receipt, manifests, and product payloads; proves
the admitted channel commit has the same Git tree as the RC; performs the live
read-only control-plane audit; records the GitHub-hosted job as ephemeral runner
provenance; and consumes either a caller-supplied Gate aggregate or an explicit
caller no-Gate decision. The
independent verifier then recomputes every receipt and payload digest exactly as
it does for externally supplied admission. Automatic assembly keeps Buildchain
as the canonical authority repository, requires evidence to belong to the
caller, binds a repository-local publisher workflow, and rejects unknown refs,
non-exact source SHAs, package/target mismatches, or an undeclared Gate policy.
Manual apply and consumers that do not opt in still require their own explicit
admission inputs.

Before authority verification, the reusable promotion controller runs the same
release transaction selector in read-only mode. That plan supplies one exact
publication version and tag to the admission verifier, the publish-gate source
lock, and the real promotion action. The verifier rejects a capability for a
different version, and the promotion action rechecks the planned version before
any publish transaction side effect. Release-candidate fixture versions are
artifact evidence only; they never name Buildchain's own source-lock or
publication capability.

Evidence publication is a separate authority class and never grants product
publication.

## Managed web-surface production

The reusable web-surface controller owns a complete standard producer path for
its documented production mechanisms. A reviewed matching release-PR merge or a
manual dispatch by an actor with current repository write authority creates a
signed decision bound to the exact source SHA. After build, verify, and
production planning, the workflow creates a qualifying pre-publication
controller receipt and assembles a ten-minute admission over the source tree,
immutable Buildchain runtime, deployment plan, artifact hash, production
Environment, AWS role/deploy target, runner provenance, decision digest, and
nonce. The independent verifier emits the scoped `web-production` capability.

The production job rechecks the capability and candidate against the same plan
before downloading product artifacts. AWS authorization is deliberately
recorded as `provider-at-transaction`: the capability binds the exact role and
Environment, while `configure-aws-credentials` performs the live OIDC exchange
and remains the final provider authorization gate before mutation. Buildchain
does not claim that an IAM trust relationship passed before that transaction.

Externally assembled admissions remain an optional compatibility path and must
provide the full admission, runner, control-plane, Gate aggregate, expected
bindings, and nonce set. They are not required for the managed web-surface
release-PR or trusted-manual paths.

## Consumer qualification handoff

For managed release candidates, a consumer whose Gate can only be decided
after the exact candidate bytes exist may provide `publication-gate-command`.
The sealed authority downloads and recomputes the RC evidence first, checks out
the exact admitted consumer source without credentials, and runs that command
with read-only evidence paths. The command must write one complete qualifying
Shifu aggregate to `BUILDCHAIN_PUBLICATION_GATE_RESULT_PATH`. Buildchain then
checks the aggregate digest and source binding before assembling the admission;
the later consumer predicate and provider action still revalidate the same
complete aggregate. A precomputed aggregate, the command, and an explicit
no-Gate decision are mutually exclusive.

Consumers may explicitly opt in to a final, consumer-owned qualification
predicate. Buildchain then transports the complete Gate aggregate alongside the
sealed capability instead of reducing it to a summary. The capability binds the
authority registry, consumer Gate registry and policy, exact source and runtime,
controller, runner, control-plane, artifact, provider target, channel, version,
freshness window, nonce, and exact predicate command digest.

The predicate runs in a separate job with read-only source access, no inherited
secrets, no OIDC permission, and no provider write permission. It receives only
paths to `capability.json` and `gate-aggregate.json` plus the exact predicate id
and digest. The consumer writes a
`kungfu-buildchain-consumer-publication-decision`; Buildchain seals that result
as a deterministic
`kungfu-buildchain-publication-qualification-receipt`. Buildchain does not parse
product-specific Gate meanings.

The provider action revalidates the capability, full aggregate, receipt,
predicate identity, freshness, nonce, source, version, channel, target, and all
sealed digests immediately before the publish transaction. Missing, denied,
stale, replayed, substituted, or drifted receipts fail before provider mutation.
Direct calls to the provider action cannot bypass the receipt when
`require-publication-qualification` is enabled. Consumers that do not opt in
retain the existing publication contract.

## API and CLI

Use `@kungfu-tech/buildchain/publication-authority` or run:

```bash
buildchain verify publication-admission admission.json \
  --registry-json publication-authority-registry.json \
  --runner-json runner.json \
  --control-plane-audit-json control-plane.json \
  --publication-evidence-json publication-evidence.json \
  --expected-json expected.json \
  --used-nonce previous-run-nonce \
  --json
```

The read-only live collector defaults to npm trusted publishing. Other product
providers select an explicit adapter:

```bash
buildchain audit publication-control-plane \
  --repository kungfu-systems/buildchain \
  --branch dev/v3/v3.0 \
  --source-sha <exact-merged-branch-sha> \
  --workflow .github/workflows/release-candidate-promote.yml \
  --workflow-ref <exact-buildchain-sha> \
  --publisher-workflow .github/workflows/buildchain-ref-promotion.yml \
  --job promote \
  --environment none

# Optional stronger external evidence; generate the JSON outside the workflow.
buildchain audit publication-control-plane \
  --repository kungfu-systems/buildchain \
  --branch dev/v3/v3.0 \
  --workflow .github/workflows/release-candidate-promote.yml \
  --publisher-workflow .github/workflows/buildchain-ref-promotion.yml \
  --job promote \
  --environment none \
  --npm-trust-json sanitized-npm-trust.json

buildchain audit publication-control-plane \
  --repository kungfu-systems/buildchain \
  --branch release/v3/v3.0 \
  --workflow .github/workflows/.binary-release-assets.yml \
  --job publish \
  --environment buildchain-release-assets \
  --publisher-mode github-token

buildchain audit publication-control-plane \
  --repository OWNER/CONSUMER \
  --workflow-repository kungfu-systems/buildchain \
  --branch main \
  --workflow .github/workflows/.web-surface.yml \
  --job production-apply \
  --environment production \
  --publisher-mode oidc-role \
  --provider-audit-json sanitized-oidc-role-audit.json
```

The authority workflow identifies the reusable implementation that performs the
publication job. The publisher workflow identifies the caller filename bound by
the provider's trusted-publisher policy; these identities are deliberately
separate. `--environment none` is an explicit assertion that the job declares no
GitHub Environment and the provider policy has no Environment restriction. A
named Environment must exist, be protected, and be declared by the job. The
Buildchain receipt alone is never sufficient authorization.

## Publication lanes

`Binary Distribution` is evidence-only. It builds platform archives and a
release evidence bundle with read-only repository permissions. GitHub Release
asset writes live in `Binary Release Assets`, which downloads an exact prior
evidence run, verifies its bundle digest against the sealed capability, and is
the only binary job with `contents: write` in the protected
`buildchain-release-assets` Environment.

The npm/promotion, paper, binary-release, and web-production lanes all depend on
the independent verifier. Preview, staging, build, source-check, controller,
and failure-evidence lanes do not inherit product publication capability.
