8000
Skip to content

chore(rust): pin the toolchain in-repo - #489

Open
sturdy-robot wants to merge 2 commits into
openfootmanager:developfrom
sturdy-robot:chore/rust-toolchain-pin
Open

chore(rust): pin the toolchain in-repo#489
sturdy-robot wants to merge 2 commits into
openfootmanager:developfrom
sturdy-robot:chore/rust-toolchain-pin

Conversation

@sturdy-robot
@sturdy-robot sturdy-robot commented Aug 17, 2026
Copy link
Copy Markdown
Collaborator

What and why

The local default toolchain and CI's pin were free to drift. CI installs Rust 1.95.0; a contributor
whose default is 1.94.0 gets a different clippy, with a different lint set — so a change can be
clean locally and red on CI for reasons that have nothing to do with the change.

rust-toolchain.toml at the repository root fixes that. rustup resolves it by walking up from
the working directory, so it governs both cargo --manifest-path src-tauri/Cargo.toml … run from
the root and a bare cargo … run from inside src-tauri/. Both were verified.

The agreement between that file and the workflows is load-bearing, not cosmetic. Both release
workflows pass targets: aarch64-apple-darwin,x86_64-apple-darwin to the toolchain action, which
installs those targets into the toolchain the action selects. If rust-toolchain.toml then
selected a different toolchain, cargo would pick one with no Apple targets and the macOS build
would break — on a workflow that only runs at release time, where nobody is watching. That is why
the consistency check exists.

scripts/check-toolchain-pin.sh enumerates .github/workflows/ rather than checking the four
pins that exist today. A script that verifies what it already knows about passes happily on the day
someone adds a fifth, which is the only day it matters. It rejects a moving pin (@stable,
@master), a pin that disagrees with the toolchain file, a workflow that builds Rust without
installing the toolchain through the action, and — see below — any cargo +<toolchain>.

Deliberately no targets = [...] in the toolchain file: the release builds install their Apple
targets through the action, so listing them here would make every Linux contributor download a
macOS standard library they will never build against.

No linked issue — this is the first of a small series of CI/infrastructure changes, not a feature.

What review changed

The first version of this check had a bypass and a false positive, and its central comment was
wrong. All three are fixed in 37982322.

cargo +<toolchain> walked straight through it. The detector required a lowercase letter
immediately after cargo , and +nightly starts with a +, so a workflow whose only Rust step was
run: cargo +nightly test was skipped entirely and the script exited 0. This is the one spelling
that matters most, because cargo +<toolchain> overrides rust-toolchain.toml itself — rustup
honours the +toolchain argument above the file. One line defeated the pin and the check guarding
the pin at once, and the check reported success. It is now rejected outright rather than
pin-checked: there is no version it could name that would be safe, since the point of the file is to
be the single answer.

npx tauri build was not recognised as building Rust — despite being how tauri-smoke builds in
this very workflow. tauri build now counts alongside a cargo subcommand and tauri-apps/tauri-action.

The word cargo in a comment counted as a Rust build, so a workflow that builds nothing could be
asked for a toolchain pin. Full-line comments are stripped before the detector runs. (Anchoring the
pattern to run:/uses: keys instead would have been worse: a run: | block puts the cargo line on
a continuation line, so anchoring stops matching this repo's real Rust steps.)

The comment on that last check was simply wrong, and is rewritten. It claimed an unpinned job
"silently gets whatever the runner ships". That stopped being true the moment this branch added
rust-toolchain.toml: rustup walks up from the checkout and installs the channel the file names, on
ubuntu-latest as anywhere else. What the action actually supplies is targets — the macOS release
matrices cannot build --target aarch64-apple-darwin without it — plus warm downloads. The rule is
worth keeping; the stated reason was not the real one.

For the same reason, one thing this check deliberately does not do is treat
with: toolchain: <other> as an override. At a version tag, dtolnay/rust-toolchain's action.yml
declares no toolchain input at all and hardcodes env: toolchain: 1.95.0; the documented input
exists only on @master, which this script rejects as a moving pin anyway.

How to verify

scripts/tests/toolchain-pin/ holds one deliberately broken repository per rule, and
scripts/check-toolchain-pin.test.sh asserts each is rejected. It runs in CI before the real
check, because the real repository is correct — a loosened regex would sail through the real run and
report success.

./scripts/check-toolchain-pin.test.sh   # 7 cases, 5 rejections and 2 acceptances
./scripts/check-toolchain-pin.sh        # passes, reports the agreed version
cargo --version                         # 1.95.0, from the repo root and from src-tauri/

Run against the previous version of the script, the same fixtures read:

Fixture before now
cargo-plus-toolchain exit 0 — bypass exit 1
unpinned-tauri-cli-build exit 0 — bypass exit 1
cargo-only-in-a-comment exit 1 — false positive exit 0
mismatched-action-pin exit 1 exit 1
moving-channel exit 1 exit 1
unpinned-cargo-build exit 1 exit 1
agreeing exit 0 exit 0

One thing this PR cannot verify from a pull request. No pull_request workflow exercises
tauri-action.yml or nightly-tauri-action.yml, so the toolchain file's effect on the five-platform
release matrices is untested until a release runs. The pin and the action both name 1.95.0 so they
agree, and the script keeps them agreeing — but please trigger nightly-tauri-action.yml via
workflow_dispatch after merging
and confirm all five platforms still build.

Incidental findings

There are five workflow files, not four. nightly-release-manifest.yml was missed by the manual
survey that preceded this change; it builds no Rust, so it is not a gap. The enumerating script is
the reason the question got asked.

rustup auto-installs the components declared in the toolchain file on the first cargo
invocation, so rustfmt for 1.95.0 now arrives without anyone running rustup component add — which
closes a stated precondition for the pending format sweep.

Separately, and outside this diff: develop currently requires zero status checks to merge
(required_status_checks.contexts is []). The new toolchain-pin job will run and can go red
without blocking anything until it is added to branch protection.


Checklist

  • Targets develop, branched from an up-to-date develop
  • Conventional-commit title
  • Linked to an issue — infrastructure change, no issue opened

Tests

  • New behaviour has a test that would have failed before this change — check-toolchain-pin.test.sh,
    with the before/after table above
  • npm test — not run; this PR touches no frontend code
  • cargo test --manifest-path src-tauri/Cargo.toml --workspace passes
  • cargo clippy --manifest-path src-tauri/Cargo.toml --workspace --all-targets -- -D warnings
    is clean

If this changes docs-worthy behaviour

  • src-tauri/CLAUDE.md §6 notes the pin, what changing it requires, and the cargo +<toolchain> ban

AI assistance

  • This change was written or assisted by an AI coding agent
  • I have read the diff myself and I stand behind it

The local default toolchain and CI's pin were free to drift, so a change could
be clean locally and red on CI — 1.95's clippy carries lints 1.94 does not.
`rust-toolchain.toml` at the repository root closes that: rustup resolves it by
walking up from the working directory, so it governs both
`cargo --manifest-path src-tauri/Cargo.toml ...` from the root and a bare
`cargo ...` from inside `src-tauri/`.

The agreement between that file and the workflows is load-bearing rather than
cosmetic. Both release workflows pass
`targets: aarch64-apple-darwin,x86_64-apple-darwin` to the toolchain action,
which installs those targets into the toolchain *the action* selects. If the
toolchain file then selected a different one, cargo would pick a toolchain with
no Apple targets and the macOS build would fail — on a workflow that only runs
at release time, where nobody is watching.

`scripts/check-toolchain-pin.sh` enforces the agreement. It enumerates the
workflow directory rather than checking the four pins that exist today, because
a script that verifies what it already knows about passes happily on the day
someone adds a fifth — the only day it matters. It also rejects a moving pin
(`@stable`, `@master`) and a workflow that builds Rust with no pin at all.

Deliberately no `targets = [...]` in the toolchain file: the release builds
install their Apple targets through the action, so listing them here would make
every Linux contributor download a macOS standard library.

Verified the gate goes red three ways — a mismatched pin in an existing
workflow, a newly added workflow pinning `@stable`, and a cargo-building
workflow with no pin — and green again after each revert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 17, 2026 23:04
@coderabbitai
coderabbitai Bot commented Aug 17, 2026
Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@sturdy-robot, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 36 minutes

Limit details: You’ve used all 4 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 980af3f5-aa2b-41d0-b339-d0ad1ef64ab7

📥 Commits

Reviewing files that changed from the base of the PR and between 92a7f29 and 3798232.

📒 Files selected for processing (21)
  • .github/workflows/build-check.yml
  • rust-toolchain.toml
  • scripts/check-toolchain-pin.sh
  • scripts/check-toolchain-pin.test.sh
  • scripts/tests/toolchain-pin/agreeing/rust-toolchain.toml
  • scripts/tests/toolchain-pin/agreeing/workflows/build.yml
  • scripts/tests/toolchain-pin/agreeing/workflows/no-rust.yml
  • scripts/tests/toolchain-pin/cargo-only-in-a-comment/rust-toolchain.toml
  • scripts/tests/toolchain-pin/cargo-only-in-a-comment/workflows/docs.yml
  • scripts/tests/toolchain-pin/cargo-plus-toolchain/rust-toolchain.toml
  • scripts/tests/toolchain-pin/cargo-plus-toolchain/workflows/build.yml
  • scripts/tests/toolchain-pin/mismatched-action-pin/rust-toolchain.toml
  • scripts/tests/toolchain-pin/mismatched-action-pin/workflows/build.yml
  • scripts/tests/toolchain-pin/moving-channel/rust-toolchain.toml
  • scripts/tests/toolchain-pin/moving-channel/workflows/build.yml
  • scripts/tests/toolchain-pin/unpinned-cargo-build/rust-toolchain.toml
  • scripts/tests/toolchain-pin/unpinned-cargo-build/workflows/build.yml
  • scripts/tests/toolchain-pin/unpinned-cargo-build/workflows/msrv.yml
  • scripts/tests/toolchain-pin/unpinned-tauri-cli-build/rust-toolchain.toml
  • scripts/tests/toolchain-pin/unpinned-tauri-cli-build/workflows/smoke.yml
  • src-tauri/CLAUDE.md

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Pins the Rust toolchain at the repository root to keep local development and CI using the same Rust/Clippy version, and adds a CI gate to prevent future drift between rust-toolchain.toml and workflow toolchain installs.

Changes:

  • Add root rust-toolchain.toml pinning Rust 1.95.0 plus clippy/rustfmt components.
  • Add scripts/check-toolchain-pin.sh and a fast CI job that enforces toolchain pin consistency across workflows.
  • Update the backend CI toolchain install to include rustfmt and document the new pinning rule in src-tauri/CLAUDE.md.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src-tauri/CLAUDE.md Documents the new in-repo Rust toolchain pin and the requirement to update workflow pins in the same commit.
scripts/check-toolchain-pin.sh New enforcement script that checks rust-toolchain.toml vs workflow pins and detects Rust-building workflows without a pinned toolchain install.
rust-toolchain.toml New root toolchain pin (1.95.0) with clippy and rustfmt components.
.github/workflows/build-check.yml Adds a dedicated “toolchain-pin” job and updates the backend Rust install to include rustfmt.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/check-toolchain-pin.sh Outdated
Comment on lines +62 to +66
# Match how Rust actually gets built — a cargo subcommand, or the action that shells out to
# cargo — not the bare word. `nightly-release-manifest.yml` names "nightly-tauri-action.yml"
# in an env var and builds nothing.
grep -qE '(^|[^[:alnum:]_-])cargo[[:space:]]+[a-z]|uses:[[:space:]]*tauri-apps/tauri-action' "$workflow" || continue
grep -q "dtolnay/rust-toolchain@" "$workflow" && continue
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Taken in 3798232, though not by anchoring to run:/uses:. That would have made things worse:
a run: | block puts the cargo line on a continuation line, so anchoring the pattern to the key
stops matching the repository's real Rust steps — including backend's own cargo test, which is
the one this check most needs to see.

Full-line comments are stripped before the detector runs instead. That covers the case you found —
build-check.yml has exactly the shape you describe, a comment mentioning cargo above a step —
without losing multi-line run: blocks. Trailing comments after code are left alone deliberately,
since stripping them would need to know about quoting.

There is a fixture for it now: scripts/tests/toolchain-pin/cargo-only-in-a-comment/ is a workflow
whose only mention of cargo is in a comment, and check-toolchain-pin.test.sh asserts it is
accepted. Against the previous version of the script that fixture exits 1, which is the false
positive you were describing.

Worth recording that the same pass found a real hole nearby, in the opposite direction: cargo +nightly test matched neither branch of the detector, because the pattern required a lowercase
letter immediately after cargo . That one is not a spurious red — cargo +<toolchain> overrides
rust-toolchain.toml, so it defeated the pin and the check guarding it at once. It is now rejected
outright rather than pin-checked.

`cargo +nightly build` beats `rust-toolchain.toml` outright — rustup honours the
`+toolchain` argument above the file — and the detector never saw it, because it
required a lowercase letter straight after `cargo ` and `+nightly` starts with a
`+`. One line in one workflow defeated the pin *and* the check protecting it,
while the check reported success. It is now banned rather than pin-checked: there
is no version it could name that would be safe, since the point of the file is to
be the single answer.

Two smaller corrections come with it. A Rust build spelled `npx tauri build` —
already how `tauri-smoke` builds in this very workflow — was not recognised as
building Rust at all, so `tauri build` now counts alongside a cargo subcommand and
the tauri-action. And full-line comments are stripped before the detector runs:
the word `cargo` in a comment used to demand a toolchain pin from a workflow that
builds nothing.

The comment on that last check was wrong and is rewritten. It claimed an unpinned
job "silently gets whatever the runner ships", which stopped being true the moment
this branch added `rust-toolchain.toml` — rustup walks up from the checkout and
installs the channel it names. What the action actually supplies is `targets`, and
the macOS release matrices cannot build `--target aarch64-apple-darwin` without it.

`scripts/tests/toolchain-pin/` holds one deliberately broken repository per rule
and `check-toolchain-pin.test.sh` asserts each is rejected, wired into CI ahead of
the real run. Without it a loosened regex still exits 0 here, because this
repository is correct. Against the previous script the fixtures read:

    cargo-plus-toolchain        exit 0  ->  1
    unpinned-tauri-cli-build    exit 0  ->  1
    cargo-only-in-a-comment     exit 1  ->  0
    (the other four unchanged, now guarded)

The script takes optional workflow-dir and toolchain-file arguments so the
fixtures can drive it; nothing else should pass them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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

0