Skip to content

fix: bypass cargo-release token check for crates.io OIDC publishing - #17

Merged
eywalker merged 4 commits into
mainfrom
fix/release-registry-token
Jun 20, 2026
Merged

fix: bypass cargo-release token check for crates.io OIDC publishing#17
eywalker merged 4 commits into
mainfrom
fix/release-registry-token

Conversation

@kurodo3

@kurodo3 kurodo3 Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Instead of bypassing cargo-release's token check (the previous approach of setting publish = false and running a separate cargo publish step), pre-exchange the GitHub OIDC JWT for a short-lived crates.io API token via crates.io trusted publishing, then set CARGO_REGISTRY_TOKEN before cargo-release runs.

This lets cargo-release see a valid token, pass its pre-publish check, and proceed with publish = 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 = false in release.toml and added a separate cargo publish step because cargo-release checks for a registry token before invoking cargo 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-release runs:

  1. Fetch the GitHub OIDC JWT (ACTIONS_ID_TOKEN_REQUEST_URL with audience=crates.io)
  2. Exchange with POST https://crates.io/api/v0/trusted_publishing/tokens
  3. Set CARGO_REGISTRY_TOKEN in GITHUB_ENV
  4. Run cargo release --execute — token check passes, publish = true works

Changes

  • release.toml: reverts publish = falsepublish = 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" step

Test plan

  • Trigger the release workflow with a version; verify version bump commit and tag are pushed
  • Verify cargo-release publishes to crates.io via OIDC (no registry token secret required)

🤖 Generated with Claude Code

kurodo3 Bot and others added 2 commits June 20, 2026 02:08
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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 = true in release.toml and 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_TOKEN before invoking cargo 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.

Comment thread .github/workflows/release.yml Outdated
Comment on lines +56 to +58
OIDC_TOKEN=$(curl -sSf "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=crates.io" \
-H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
| jq -r '.value')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread .github/workflows/release.yml Outdated
Comment on lines +59 to +62
CRATES_TOKEN=$(curl -sSf https://crates.io/api/v0/trusted_publishing/tokens \
-H "Content-Type: application/json" \
-d "{\"jwt\": \"${OIDC_TOKEN}\"}" \
| jq -r '.token')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

kurodo3 Bot and others added 2 commits June 20, 2026 20:21
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>
@kurodo3

kurodo3 Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

Review round addressed (commit 4f01ec3)

The Copilot jq -er feedback pointed at the right problem but the right fix was deeper: replaced the entire manual curl/jq OIDC exchange with rust-lang/crates-io-auth-action@v1.0.5, the official action built by the crates.io team for exactly this purpose.

What changed

  • release.yml: The "Get crates.io OIDC token" shell step (two curl invocations + jq) is gone. In its place:

    - name: Authenticate with crates.io (trusted publishing)
      id: crates-io-auth
      uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18  # v1.0.5
    
    - name: Release
      env:
        CARGO_REGISTRY_TOKEN: ${{ steps.crates-io-auth.outputs.token }}
      run: cargo release ${{ inputs.version }} --execute --no-confirm

    The action handles the OIDC JWT fetch and crates.io exchange internally, surfaces the result as outputs.token, and automatically revokes it in its post step. CARGO_REGISTRY_TOKEN is scoped to the Release step (not exported to GITHUB_ENV) so it's not available to any other step.

  • release.toml: comment updated to reference crates-io-auth-action instead of the manual curl approach.

@eywalker
eywalker merged commit 9e5dd82 into main Jun 20, 2026
3 checks passed
@eywalker
eywalker deleted the fix/release-registry-token branch June 20, 2026 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants