From 4af6ed0f9836d3de86f81a0ac9cb6885936268ce Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Thu, 20 Aug 2026 19:35:51 +0200 Subject: [PATCH] build(rust): pin the toolchain to 1.97.1 for dev and CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Rust toolchain was unpinned on both sides, and the two sides had drifted five releases apart: the CI builder image ships rustc 1.97.1, the development machine was on 1.92.0. Clippy's lint set and rustfmt's output both change between releases, so a green `cargo clippy` / `cargo fmt --check` locally said nothing about CI and vice versa — which is the reason the clippy gate could not be trusted enough to turn on. src-tauri/rust-toolchain.toml pins channel 1.97.1 with the rustfmt and clippy components. Deliberately no `targets` list: that would make rustup fetch the Android and Windows std libraries on every plain `cargo test`, including on machines that never cross-compile. The image already has them. Dockerfile.builder installs that exact version instead of "latest stable at rebuild time", and prints rustc/clippy versions so a mismatch is visible in the build log. The pin only becomes authoritative once the image is rebuilt and pushed (scripts/build-builder-image.sh). Until then CI still runs whatever rustc the current image has, and if that is not 1.97.1 rustup will download the pinned toolchain at job time — a toolchain install in CI, which CLAUDE.md forbids. Both files carry that warning next to the version. Note: the clippy step in .gitea/workflows/build-and-test.yml is left advisory here; tightening it wants a warning count measured on 1.97.1 first. --- Dockerfile.builder | 27 ++++++++++++++++++++++++--- src-tauri/rust-toolchain.toml | 26 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src-tauri/rust-toolchain.toml diff --git a/Dockerfile.builder b/Dockerfile.builder index 8371546d..853b9db8 100644 --- a/Dockerfile.builder +++ b/Dockerfile.builder @@ -52,13 +52,34 @@ RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ RUN curl -fsSL https://bun.sh/install | bash && \ ln -s /root/.bun/bin/bun /usr/local/bin/bun -# Install Rust using rustup -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \ +# Install Rust using rustup, pinned to an exact release. +# +# 🔴 RUST_VERSION must equal `channel` in src-tauri/rust-toolchain.toml. +# +# The two are a pair. rust-toolchain.toml is what makes a developer's `cargo +# clippy` agree with CI's; this line is what makes the image already contain that +# toolchain. If they drift, rustup silently downloads the pinned version the +# first time cargo runs inside a job — a toolchain install at job time, which +# CLAUDE.md's "🔴 CI installs no system tools" rule forbids (and which costs +# ~1min plus a network dependency on every build). +# +# 🔴 Changing this line does NOT change CI on its own: the image must be +# rebuilt and pushed (`scripts/build-builder-image.sh`) before the new pin is +# authoritative. Bump rust-toolchain.toml and this line together, rebuild, push, +# then merge. +# +# Was: `sh -s -- -y` (latest stable, whatever it happened to be on rebuild day). +ENV RUST_VERSION=1.97.1 +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ + sh -s -- -y --profile minimal --default-toolchain "$RUST_VERSION" && \ . $HOME/.cargo/env && \ + rustup default "$RUST_VERSION" && \ rustup target add aarch64-linux-android && \ rustup target add armv7-linux-androideabi && \ rustup target add x86_64-linux-android && \ - rustup component add rustfmt clippy + rustup component add rustfmt clippy && \ + rustc --version && \ + cargo clippy --version # Setup Android SDK RUN mkdir -p $ANDROID_HOME && \ diff --git a/src-tauri/rust-toolchain.toml b/src-tauri/rust-toolchain.toml new file mode 100644 index 00000000..bfb8ff59 --- /dev/null +++ b/src-tauri/rust-toolchain.toml @@ -0,0 +1,26 @@ +# Pinned Rust toolchain for the JellyTau backend. +# +# TRACES: | DR-206 +# +# Why pin: the toolchain was unpinned, so the CI builder image (rustc 1.97.1) +# and developer machines (as low as 1.92.0) were five releases apart. Clippy's +# lint set and rustfmt's output both move between releases, which means a green +# `cargo clippy` / `cargo fmt --check` locally proved nothing about CI — and vice +# versa. Everything in this file exists to make both sides run the same compiler. +# +# 🔴 This value MUST match the rustc that Dockerfile.builder installs (see +# RUST_VERSION there). If they drift, rustup downloads the pinned toolchain at +# job time inside the container — a toolchain install in CI, which is exactly +# what CLAUDE.md's "CI installs no system tools" rule forbids. To move the pin: +# bump BOTH this file and Dockerfile.builder, then rebuild and push the image +# with scripts/build-builder-image.sh before merging. +# +# No `targets` key on purpose: listing the Android/Windows targets here would +# make rustup fetch all of them on every plain `cargo test`, including on +# machines that never cross-compile. The builder image already carries them +# (`rustup target add` in Dockerfile.builder), and the cross-build scripts add +# them locally when needed. + +[toolchain] +channel = "1.97.1" +components = ["rustfmt", "clippy"]