feat(release): Trusted Publishing (OIDC) for crates.io (#96)#122
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 16 minutes and 18 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request updates the documentation to prioritize and detail the setup for Trusted Publishing (OIDC) on crates.io, including a new workflow example and troubleshooting guide. It also clarifies the authentication hierarchy in the release runbook. Feedback includes correcting non-existent GitHub Action versions in the documentation and adding reliability flags to the example shipper publish command to better demonstrate the tool's core features.
| - uses: actions/checkout@v6 | ||
| - uses: dtolnay/rust-toolchain@stable |
There was a problem hiding this comment.
The action versions actions/checkout@v6 and dtolnay/rust-toolchain@stable appear to be incorrect. actions/checkout is currently at v4, and dtolnay/rust-toolchain typically uses @v1 with the toolchain specified in a with block. Using non-existent versions will cause the GitHub Action to fail.
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@v1 | |
| with: | |
| toolchain: stable |
| # Falls back to the long-lived secret if OIDC is unavailable | ||
| # (e.g. during incident response or the first bootstrap run). | ||
| CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token || secrets.CARGO_REGISTRY_TOKEN }} | ||
| run: shipper publish --policy safe |
There was a problem hiding this comment.
For production releases, it is recommended to include the reliability flags used in the minimal workflow example (lines 58-60), such as --readiness-method both, --max-attempts, and --max-delay. This ensures the publish process is resilient to registry backpressure and transient network issues, which is a core value proposition of Shipper.
| run: shipper publish --policy safe | |
| run: | | |
| shipper publish \ | |
| --policy safe \ | |
| --readiness-method both \ | |
| --max-attempts 12 \ | |
| --max-delay 15m |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 98f487d971
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - name: Mint crates.io token (Trusted Publishing) | ||
| id: auth | ||
| uses: rust-lang/crates-io-auth-action@v1 |
There was a problem hiding this comment.
Keep publish job running when OIDC token mint fails
This step is documented as having a secret-token fallback, but without continue-on-error: true any crates.io OIDC exchange failure (missing/denied id-token, crates.io outage, or trusted-publisher mismatch) aborts the job before steps.auth.outputs.token || secrets.CARGO_REGISTRY_TOKEN is ever evaluated in later steps. That makes the advertised bootstrap/incident-response fallback path non-functional for publish-crates-io (and the same pattern appears in release-resume).
Useful? React with 👍 / 👎.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
98f487d to
3d13cd4
Compare
3d13cd4 to
9d963a1
Compare
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Rebased onto current main (now includes #97 stack + #98 stack merges). Ready for review/merge. Note: this should land after #135 (the reframed #95 packaging unification). No hard conflict between them, but landing #96 first and then #95 would force another rebase on the release.yml workflow since #95 also touches it for the |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d963a1bcf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| id: publish | ||
| env: | ||
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | ||
| CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token || secrets.CARGO_REGISTRY_TOKEN }} |
There was a problem hiding this comment.
Use secret fallback when OIDC token lacks crate scope
This fallback expression only helps when the auth step returns no token, but Trusted Publishing can return a token that still fails on some crates (the docs added in this commit describe 401s for unregistered crates). In a partial-registration rollout, this line will always prefer the OIDC token and never use secrets.CARGO_REGISTRY_TOKEN, so shipper publish can fail mid-train even though the workflow advertises a bootstrap/incident fallback.
Useful? React with 👍 / 👎.
| - name: Mint crates.io token (Trusted Publishing) | ||
| id: auth | ||
| uses: rust-lang/crates-io-auth-action@v1 | ||
| continue-on-error: true |
There was a problem hiding this comment.
Bind rehearsal OIDC minting to the release environment
The new rehearsal auth step runs in a job without environment: release, but the same commit’s docs recommend configuring trusted publishers with the release environment as a scope guard. That mismatch means OIDC minting will keep failing even after setup is complete, and continue-on-error: true will silently mask it, so rehearsal cannot validate the real Trusted Publishing path before a production tag.
Useful? React with 👍 / 👎.
Wire the release workflow to mint a short-lived crates.io token per
run via `rust-lang/crates-io-auth-action@v1` instead of relying on a
long-lived `CARGO_REGISTRY_TOKEN` secret.
Shipper's auth layer already detects the OIDC env vars
(`ACTIONS_ID_TOKEN_REQUEST_URL` + `_TOKEN`) and returns
`AuthType::TrustedPublishing`; the workflow side is what was missing.
- release.yml:
- add `id-token: write` at the workflow level
- publish-crates-io, release-rehearse, and release-resume jobs each
run `rust-lang/crates-io-auth-action@v1` before invoking shipper,
and set `CARGO_REGISTRY_TOKEN` from `steps.auth.outputs.token`.
- fallback to `secrets.CARGO_REGISTRY_TOKEN` via `||` so incident
response / bootstrap still works when OIDC can't mint.
- docs/how-to/run-in-github-actions.md: replace the minimal OIDC stub
with a full recipe — one-time crates.io registration steps,
`environment: release` scope guard, and troubleshooting for the
three common failure modes.
- docs/release-runbook.md: promote Trusted Publishing from "preferred"
to the primary auth path; keep the token fallback documented.
Prereq (one-time, admin task, not code): register each published crate
as a trusted publisher on crates.io with this repo + release.yml +
`release` environment. Until that's done for all 12 crates, the
fallback keeps the train runnable.
Addresses #96 review concerns: 1. **Rehearsal scope guard.** `release-rehearse` now binds to `environment: release` so OIDC tokens it mints scope identically to production. Without this, rehearsal would only validate the mint mechanism while silently hiding scope-binding misconfiguration. 2. **Mixed-registration caveat.** Release workflow comment + how-to doc now explicitly require all crates to be registered as trusted publishers before enabling OIDC. Shipper's `preflight --policy safe` ownership check surfaces scope mismatches for existing crates; first-publish of unregistered new crates depends on operator discipline (documented).
9d963a1 to
d8ea9bf
Compare
|
Addressed the two review concerns:
Rebased on latest main. CI should re-run. |
Three-column reconciliation of what's actually merged vs each issue's acceptance checklist. Single source of truth for what closes each pillar issue. **Findings:** - **#90 Recover** — honestly closable. Code side is done (#124 + #130); operator-side real rehearsal is an ops action, not a code gap. - **#97 Prove tier 2** — 85% done. Rehearsal + visibility + hard gate + plan_id binding all landed (#127 + #133). Missing: install/smoke check (cargo install against the rehearsal registry / consumer build). One narrow follow-up PR closes it. - **#98 Remediate** — 60% done. Receipt schema + plan-yank (from-receipt) + yank primitive + fix-forward planning all landed (#121 + #132 + #134). Missing: plan-yank's --starting-crate graph mode, plan execution for yank + fix-forward. Two narrow follow-ups. Also captures the two review concerns on #122 (Trusted Publishing) that were addressed in a follow-up commit to that PR. Recommended next merge order and follow-up PRs spelled out at bottom.
Three-column reconciliation of what's actually merged vs each issue's acceptance checklist. Single source of truth for what closes each pillar issue. **Findings:** - **#90 Recover** — honestly closable. Code side is done (#124 + #130); operator-side real rehearsal is an ops action, not a code gap. - **#97 Prove tier 2** — 85% done. Rehearsal + visibility + hard gate + plan_id binding all landed (#127 + #133). Missing: install/smoke check (cargo install against the rehearsal registry / consumer build). One narrow follow-up PR closes it. - **#98 Remediate** — 60% done. Receipt schema + plan-yank (from-receipt) + yank primitive + fix-forward planning all landed (#121 + #132 + #134). Missing: plan-yank's --starting-crate graph mode, plan execution for yank + fix-forward. Two narrow follow-ups. Also captures the two review concerns on #122 (Trusted Publishing) that were addressed in a follow-up commit to that PR. Recommended next merge order and follow-up PRs spelled out at bottom.
Summary
Switch the release workflow from a long-lived
CARGO_REGISTRY_TOKENsecret to Trusted Publishing via
rust-lang/crates-io-auth-action@v1.Short-lived tokens, scoped to this repo +
release.yml+releaseenvironment. Closes #96.
Shipper's auth layer (
ops/auth/oidc.rs) already detectsACTIONS_ID_TOKEN_REQUEST_URL+_TOKENand returnsAuthType::TrustedPublishing— only the workflow side was missing.Changes
.github/workflows/release.yml:id-token: writeat workflow level.publish-crates-io,release-rehearse,release-resume: each runsrust-lang/crates-io-auth-action@v1before invoking shipper, feedssteps.auth.outputs.tokenintoCARGO_REGISTRY_TOKEN.steps.auth.outputs.token || secrets.CARGO_REGISTRY_TOKENso incident response / bootstrap still works when OIDC can't mint.
release-rehearsemarks the auth stepcontinue-on-error: true(rehearse is best-effort and shouldn't block on a missing OIDC scope).
docs/how-to/run-in-github-actions.md: replace minimal stub withfull recipe — one-time crates.io registration steps, environment scope
guard, troubleshooting section (3 common failure modes).
docs/release-runbook.md: promote Trusted Publishing from"preferred" to primary auth path; keep token fallback documented.
Prerequisite (NOT code — one-time admin task)
Each of the 12 crates must be registered on crates.io as a Trusted
Publisher with:
EffortlessMetrics/shipperrelease.ymlreleaseUntil registration is complete for all 12 crates, the fallback keeps
the train runnable via the secret. First release on the OIDC path
should be a rehearse run, then a real tag.
Test plan
release.ymlparses as valid YAML.workflow_dispatch mode=rehearserun should show the"Mint crates.io token" step succeed (or
continue-on-errorif therepo isn't yet registered).
per-crate
cargo publishinsideshipper publishpicks up theminted token without reaching for the secret.