Repository navigation
feat(release): gate the publish transition on OIDC, so a registry token cannot be the way in - #356
Merged
wenzowski merged 1 commit intoAug 12, 2026
Conversation
CLOUD-109 Switch release-plz to OIDC trusted publishing
Avoid a long-lived registry token. Scope / acceptance
|
wenzowski
marked this pull request as ready for review
August 12, 2026 05:17
…en cannot be the way in CLOUD-109 asked to switch release-plz to crates.io OIDC trusted publishing and to delete CARGO_REGISTRY_TOKEN. Measured: `release-plz.toml` sets `publish = false`, so release-plz never contacts a registry, and that secret does not exist — the repository carries exactly one Actions secret, RELEASE_PLZ_TOKEN, and a tree-wide grep finds the registry name nowhere. Adding `id-token: write` today would grant a capability no step uses, which zizmor's excessive-permissions audit reads as a finding. So the deliverable is the transition, not an edit to today's workflow. publish-credential-check refuses a registry token or a hand-rolled cargo login in any workflow, and refuses `publish = true` unless the release job carries `id-token: write` in the same commit. An absent `publish` key reads as true, because that is release-plz's default and a gate silent in exactly its own case is no gate. The workflow header now separates the two credentials it kept conflating: crates.io OIDC retires a registry token and does nothing for RELEASE_PLZ_TOKEN, whose replacement is an org-owned GitHub App (CLOUD-94). Refs: CLOUD-109
wenzowski
force-pushed
the
wenzowski/cloud-109-switch-release-plz-to-oidc-trusted-publishing
branch
from
August 12, 2026 05:19
4338d05 to
ac10c3a
Compare
|
Contributor
Author
|
/fast-forward |
wenzowski
deleted the
wenzowski/cloud-109-switch-release-plz-to-oidc-trusted-publishing
branch
August 12, 2026 05:27
This was referenced Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



CLOUD-109 asks for two things. Measured against the repository, neither was a
change that did anything:
mainpermissions: id-token: write)release-plz.tomlsets[workspace] publish = false.mise run releasenever contacts a registry, so there is no publish for a trusted publisher to authenticate.CARGO_REGISTRY_TOKENsecret is removed once trusted publishing is confirmed workinggh api repos/button-inc/batten/actions/secretsreturns exactly one name,RELEASE_PLZ_TOKEN, and a tree-wide grep findsCARGO_REGISTRY_TOKENnowhere.Adding
id-token: writetoday would grant a capability no step uses — deadconfig that zizmor's excessive-permissions audit reads as a finding, and the
syntax of trusted publishing without its semantics.
And the decision behind it is not stale: CLOUD-205 (Done, founder-confirmed)
keeps the crate unpublished. So the deliverable is the transition, which
needs no credential and is buildable now.
What lands
mise run publish-credential-check, wired into the hk gate. One question — canthis repository publish with a long-lived credential? — and the load-bearing
rule is an implication rather than a literal:
CARGO_REGISTRY_TOKEN, theCARGO_REGISTRIES_*_TOKENalternate-registry form,and a hand-rolled
cargo login. Green today by construction — it is theratchet that keeps it green.
publish = truerequiresid-token: writein the same commit. Whilepublishing is off the permission is not required, because requiring it would
require the dead config above. Turning publishing on is therefore a change that
cannot skip OIDC.
publishkey reads astrue, because that is release-plz's owndefault. Reading a missing key as
falsewould make the gate silent in exactlythe case it exists for; a test pins it.
Output is pointer-only (rule 4) and the matched line is deliberately never
printed — the class of thing this gate looks for is the class that must not reach
a log. A test asserts the finding names
path:lineand a rule id and nothingelse. Exit
0/1/2per house-style §7.The
release-plz.ymlheader separated the two credentials it had beenconflating, since that conflation is what put this issue and CLOUD-94 on the same
thread.
What a human must still do — none of it possible from a session
→ GitHub, owner
button-inc, repobatten, workflowrelease-plz.yml).Impossible before the crate is published at all.
publish = true. CLOUD-205's decision to revisit, not this ticket's topre-empt. The gate is what makes that flip safe whenever it comes.
RELEASE_PLZ_TOKEN— a GitHub App onbutton-incwithcontents: write+pull_requests: write, andAPP_ID/APP_PRIVATE_KEYsecrets. crates.io OIDC does not reach this credential, so CLOUD-94 must not
be closed on the strength of this PR. That is CLOUD-94's scope and it already
specifies the fix.
Verification
mise run publish-credential-checkgreen on the tree (publish=false, 16workflows clean).
tests/publish-credential-check.bats(13) covers both directions: each of thethree credential spellings,
publish = truewithout the permission (fails) andwith it (passes), the permission named only in a comment (still fails), the
absent-key default, and exit 2 for an unreadable config, an empty workflow
directory, and publishing on with no release workflow.
mise run verifygreen.Refs: CLOUD-109