fix: bypass cargo-release token check for crates.io OIDC publishing - #17
Conversation
cargo-release performs its own pre-publish registry token existence check before ever invoking `cargo publish`, which means the OIDC token exchange with crates.io never runs, producing "no token found" errors. Fix: set publish = false in release.toml so cargo-release skips publishing entirely, then add a dedicated `cargo publish` step in the workflow. The native `cargo publish` command supports crates.io trusted publishing via OIDC when `id-token: write` is granted — no CARGO_REGISTRY_TOKEN needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lease Pre-exchange the GitHub OIDC JWT for a short-lived crates.io API token via crates.io trusted publishing (https://crates.io/docs/trusted-publishing) and set CARGO_REGISTRY_TOKEN in GITHUB_ENV before cargo-release runs. This satisfies cargo-release's pre-publish token check so publish = true works — no stored API token secret required, and the full release (bump → commit → tag → push → publish) remains atomic. Reverts publish = false workaround from the previous approach. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates the release configuration and GitHub Actions workflow to support crates.io “trusted publishing” by exchanging the GitHub OIDC JWT for a short-lived crates.io API token before running cargo-release, allowing publish = true and an atomic release flow again.
Changes:
- Re-enable
publish = trueinrelease.tomland document the OIDC token exchange flow. - Add a workflow step to fetch a GitHub OIDC JWT, exchange it for a crates.io token, and export
CARGO_REGISTRY_TOKENbefore invokingcargo release --execute.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
release.toml |
Documents the trusted publishing/OIDC flow and keeps publish = true for atomic releases. |
.github/workflows/release.yml |
Adds OIDC→crates.io token exchange and sets CARGO_REGISTRY_TOKEN prior to running cargo-release. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| OIDC_TOKEN=$(curl -sSf "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=crates.io" \ | ||
| -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \ | ||
| | jq -r '.value') |
There was a problem hiding this comment.
Fixed in commit 834d135 — changed to jq -er '.value'. The -e flag makes jq exit with a non-zero status when the output value is null or false, so the step fails immediately if the OIDC response doesn't contain .value rather than silently passing "null" to the exchange request.
There was a problem hiding this comment.
Superseded by commit 4f01ec3 — the entire manual curl/jq exchange has been replaced by rust-lang/crates-io-auth-action@v1.0.5, the official action that handles the GitHub OIDC JWT → crates.io token exchange. The action also auto-revokes the token in its post step. No custom shell code left to mishandle missing fields.
| CRATES_TOKEN=$(curl -sSf https://crates.io/api/v0/trusted_publishing/tokens \ | ||
| -H "Content-Type: application/json" \ | ||
| -d "{\"jwt\": \"${OIDC_TOKEN}\"}" \ | ||
| | jq -r '.token') |
There was a problem hiding this comment.
Superseded by commit 4f01ec3 — same as above. The official rust-lang/crates-io-auth-action replaces the entire curl/jq step, so neither the .value nor the .token parsing exists anymore.
Replace jq -r with jq -er in the Get crates.io OIDC token step so the step exits immediately (non-zero) if .value is absent from the OIDC response or .token is absent from the crates.io exchange response, rather than silently setting variables to the string "null" and proceeding to a confusing downstream failure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…hange Replace the manual curl/jq OIDC token exchange with the official rust-lang/crates-io-auth-action@v1.0.5. The action handles the GitHub OIDC JWT → crates.io short-lived token exchange and automatically revokes the token in its post step. The token is passed as CARGO_REGISTRY_TOKEN scoped to the Release step so cargo-release's pre-publish check passes with publish = true. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Review round addressed (commit 4f01ec3)The Copilot What changed
|
Summary
Instead of bypassing cargo-release's token check (the previous approach of setting
publish = falseand running a separatecargo publishstep), pre-exchange the GitHub OIDC JWT for a short-lived crates.io API token via crates.io trusted publishing, then setCARGO_REGISTRY_TOKENbeforecargo-releaseruns.This lets
cargo-releasesee a valid token, pass its pre-publish check, and proceed withpublish = true— so the full release (version bump → commit → tag → push → publish) is atomic again.Why this is better than the previous approach
The previous PR set
publish = falseinrelease.tomland added a separatecargo publishstep becausecargo-releasechecks for a registry token before invokingcargo publish, which prevented the OIDC exchange from ever running.The correct fix per crates.io trusted publishing docs is to pre-fetch the OIDC token and exchange it for an API token before
cargo-releaseruns:ACTIONS_ID_TOKEN_REQUEST_URLwithaudience=crates.io)POST https://crates.io/api/v0/trusted_publishing/tokensCARGO_REGISTRY_TOKENinGITHUB_ENVcargo release --execute— token check passes,publish = trueworksChanges
release.toml: revertspublish = false→publish = true; updates comment to describe the OIDC flow.github/workflows/release.yml: replaces split "Release + Publish" steps with a single "Get crates.io OIDC token" step followed by a unified "Release" stepTest plan
releaseworkflow with a version; verify version bump commit and tag are pushedcargo-releasepublishes to crates.io via OIDC (no registry token secret required)🤖 Generated with Claude Code