Repository navigation
fix(ci): migrate nightly jobs to new dtolnay/rust-toolchain schema - #2850
Conversation
The dtolnay/rust-toolchain action removed the `toolchain:` input (it now installs the rust-toolchain.toml toolchain). Bumping the pin (as #2847 does) silently installs stable 1.96.0 in nightly jobs, breaking the Pyodide wheel (-Z flags), Miri, ASAN (-Z build-std) and fuzz jobs. Install the pinned nightlies explicitly via `rustup toolchain install` (targets/components preserved) and drop the now-dead matrix toolchain input. Supersedes #2847.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | 671d2d0 | Commit Preview URL Branch Preview URL |
Nov 07 2026, 01:21 PM |
Review summary (head
|
The toolchain action dropped its toolchain: input, so nightly jobs now install via run: rustup toolchain install nightly-.... The exempt-nightly detector only knew the legacy # nightly action-ref spelling and failed the migrated jobs (plus misclassified cargo-fuzz). Detect both; the discovery guard accepts either.
…ain migration The toolchain action no longer accepts `toolchain:`, so the nightly jobs install the pinned nightly alongside a stable default and select it per command. `cargo install` does not follow that selection: both cargo-fuzz installs (the cache-cargo-install-action step in ci.yml's fuzz-check and the bare `cargo install` in fuzz.yml) silently moved onto the pinned stable, where an unpinned source build resolves to the newest release and an upstream MSRV bump breaks an unchanged tree. That is the cargo-geiger 0.14.0 failure the pin test exists to prevent. test_pinned_ci_tools read the nightly exemption per job, so a job that merely installed a nightly somewhere exempted every source build in it. It now reads per step: a step is exempt only when its own cargo resolves to a nightly, via `RUSTUP_TOOLCHAIN` or `cargo +nightly-...`. The check also covers bare `cargo install` run steps, which carry the same hazard in a spelling the test did not look at. Also re-indents the nightly pin comment the migration orphaned at `with:` depth in ci.yml, fuzz.yml and nightly.yml. Claude-Session: https://claude.ai/code/session_01Wy7MByvAMwapenBYpmq9HN
The nightly soak job added in #2874 has never passed. It runs python_tenant_stress_tests at BASHKIT_STRESS_ROUNDS=300, and one_session_reuses_its_budget_across_many_calls makes 10 * rounds() calls in a single session: 3,000 against a default max_exec_calls of 1,000. It died at call 1,000 on "session exec() call limit exceeded", never reaching what it asserts, which is that memory charged in one call is released at its end. The session cap is not what these tests measure, so tenant() now sets its own with room for the largest soak the file can ask for. MAX_ROUNDS is one constant behind both the BASHKIT_STRESS_ROUNDS bound and that headroom, so the two cannot drift apart again the way they just did. Reproduced at BASHKIT_STRESS_ROUNDS=101 (1,010 calls), which fails identically on the cap and passes with this change. Claude-Session: https://claude.ai/code/session_01Wy7MByvAMwapenBYpmq9HN
|
It only shows up here because I dispatched Not a flake. The cause is exact: The test loops Reproduced locally at The fix gives Migration validation (the reason for dispatching)
Generated by Claude Code |
The nightly detector required a literal `nightly` token, so a job naming its
nightly through a variable was read as not having one. Both Pyodide jobs do
exactly that — `rustup toolchain install ${{ env.RUST_NIGHTLY }}` with
`RUSTUP_TOOLCHAIN` set to the same expression — which is the opt-in route this
same change introduced, so the "either spelling" claim was not true of the
tree it runs against. Nothing is mis-exempted today (neither job builds a tool
from source), but a source build added there would be told to pin a tool that
is already on a nightly.
`${{ env.NAME }}` is now resolved against step, job and workflow `env` before
the nightly test. An unresolved reference is left as written so the variable's
own name cannot stand in for its value: `RUST_NIGHTLY` is not evidence that
what it holds is a nightly.
The new test asserts it over the real workflows rather than a fixture: every
job installing a toolchain through rustup must be discovered, and a step
pinning `RUSTUP_TOOLCHAIN` to its job's nightly must count as running on it.
Six jobs covered, including the two that were missed.
Claude-Session: https://claude.ai/code/session_01Wy7MByvAMwapenBYpmq9HN
What changed
Nightly CI jobs (Pyodide wheel, Miri, ASAN, fuzz) install their pinned nightly explicitly via
rustup toolchain installinstead of the removedtoolchain:action input, which unblocks thedtolnay/rust-toolchainbump. Includes the other two safe bumps from #2847 (pnpm/action-setup, taiki-e/install-action). Supersedes #2847.Then one consequence of that migration, found while reviewing it:
cargo installdoes not follow a per-command toolchain selection, so both cargo-fuzz installs silently moved onto the pinned stable.The migrated jobs install nightly alongside a stable default and select it per command (
cargo +nightly-2026-10-30 fuzz build).cargo installin those jobs gets stable 1.96.0, where an unpinned source build resolves to the newest release — so an upstream MSRV bump breaks a tree that has not changed. That is exactly the cargo-geiger 0.14.0 failuretest_pinned_ci_tools.pywas written to prevent (nightly run 259 went red the next morning with the unsafe-code audit skipped).The test did not catch it because it read the nightly exemption per job: a job that installed a nightly anywhere exempted every source build in it. It now reads per step — a step is exempt only when its own cargo resolves to a nightly (
RUSTUP_TOOLCHAIN, orcargo +nightly-…) — and additionally covers barecargo installrun steps, which carry the same hazard in a spelling the test never looked at.Also re-indents the nightly pin comment the migration orphaned at
with:depth inci.yml,fuzz.ymlandnightly.yml.Why
The
dtolnay/rust-toolchainbump in #2847 (5b84223 → d86e0fa) removes thetoolchain:input — the action now always installs therust-toolchain.tomltoolchain (stable 1.96.0). Nightly jobs silently got stable: Pyodide wheel failed (can't find crate for core, target never installed), and Miri/ASAN/fuzz would follow. Verified against upstreamaction.yml: valid inputs are onlytargets/target/components.Before / After
The pin test, before the fix was applied (the regression it now catches):
After: 4 passed, and 247 repo-script tests green.
Because
nightly.ymlandfuzz.ymlonly run on schedule, PR checks cannot exercise them — so both were dispatched on this branch and report here:Build wheel (Pyodide/Emscripten)— success (the original failure mode)Fuzz Compile Check— success (validates theRUSTUP_TOOLCHAINroute inci.yml)Fuzz Test (×9),Miri,AddressSanitizer,Security Analysis,Python multi-tenant stress soak— dispatched from this branchpublish-python.ymlandpython.ymlboth setRUSTUP_TOOLCHAINon thepyodide buildstep itself, so the stable default never reaches it.Risk
miri; ASAN addsrust-src) — covered by the dispatched runs above rather than assumed.rust_version, so the stable install happened to work; the fix is about the next upstream release, not a current break.Checklist
cargo installknowledge/operations/dependencies.md)Generated by Claude Code