From 92d7af45b08784f92d72351f21df1f5f96db2d47 Mon Sep 17 00:00:00 2001 From: amackillop Date: Wed, 29 Jul 2026 11:35:19 -0700 Subject: [PATCH 1/2] Pin one Rust toolchain for the dev shell and CI The dev shell and CI resolved toolchains from independent clocks: fenix "stable" moves on nix flake update (was 1.95), while dtolnay/rust-toolchain@stable moves on every Rust release (1.97). The gap meant CI could lint code the dev shell's clippy had never seen, which is exactly how PR #46 went red on untouched code. rust-toolchain.toml is now the single pin: the flake builds the dev shell from it (fenix fromToolchainFile) and CI installs from it via plain rustup, so neither side can move alone. Bumping the channel means updating the toml plus the sha256 next to it (build once with lib.fakeSha256 to learn the new one), and possibly the fenix input. Also disables nix's fortify hardening in the shell: combined with cargo's -O0 it makes glibc emit a #warning that jemalloc's -Werror configure probes turn into "cannot determine return type of strerror_r", so cargo check never got off the ground in the shell. just ci now passes in the dev shell under the same clippy CI runs. The napi release matrix keeps its own RUST_VERSION pin (1.85) in CI.yml; prebuilt binaries are a separate decision from lint parity. --- .github/workflows/CI.yml | 9 +++++---- flake.lock | 12 ++++++------ flake.nix | 27 ++++++++++++++------------- rust-toolchain.toml | 9 +++++++++ 4 files changed, 34 insertions(+), 23 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 9be19c4..bcef2cf 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -37,10 +37,11 @@ jobs: node-version: 22 cache: 'yarn' - - name: Install - uses: dtolnay/rust-toolchain@stable - with: - components: clippy, rustfmt + # Reads rust-toolchain.toml (version and components), the same pin the + # nix dev shell builds from — a floating stable here once linted code + # the dev shell's clippy had never seen. + - name: Install Rust from rust-toolchain.toml + run: rustup toolchain install - name: Install dependencies run: yarn install diff --git a/flake.lock b/flake.lock index 8c20521..b9d9772 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1779790483, - "narHash": "sha256-2wCMtmVmkCcyHaH6hkrbx7XdUgLYP5E1wl/jc1YxxTY=", + "lastModified": 1785314864, + "narHash": "sha256-imz9J5iMNersDeQ1ymenFg35N6C2R3MCaGg2i0XCIrE=", "owner": "nix-community", "repo": "fenix", - "rev": "6012e5463531342033571efe294ec880bf13dd95", + "rev": "594418b2c9ea0731bee6988236ef5bfd97e81dca", "type": "github" }, "original": { @@ -81,11 +81,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1779742949, - "narHash": "sha256-Dk0hnFTXbmNmigsJyQkCz2NEEgtpe+MN500dPnki9Ic=", + "lastModified": 1785261141, + "narHash": "sha256-sA+DHPejWD68mLA7gtTiHGd5T41F6W+NKf0g+ibFCW4=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "462d95ca60fa7360b44258be94105bc20e203684", + "rev": "bec66814323579659ffd77c909b3d963af118ece", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index af0fed2..6070a90 100644 --- a/flake.nix +++ b/flake.nix @@ -28,19 +28,14 @@ fenixPkgs = fenix.packages.${localSystem}; - # Crane needs cargo >= 1.91 (`cargo package --exclude-lockfile`). - # Cargo.toml's `rust-version = "1.85"` remains the MSRV for downstream - # consumers; this toolchain is only for the dev shell and CI checks. - rustToolchain = fenixPkgs.combine [ - (fenixPkgs.stable.withComponents [ - "cargo" - "clippy" - "rust-src" - "rustc" - "rustfmt" - ]) - fenixPkgs.stable.rust-analyzer - ]; + # Pinned by rust-toolchain.toml so the dev shell runs the exact + # toolchain CI lints with; see the comment there. The sha256 pins the + # channel's component set and must be bumped together with the + # channel (build once with lib.fakeSha256 to learn the new one). + rustToolchain = fenixPkgs.fromToolchainFile { + file = ./rust-toolchain.toml; + sha256 = "sha256-OATSZm98Es5kIFuqaba+UvkQtFsVgJEBMmS+t6od5/U="; + }; craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; src = craneLib.cleanCargoSource ./.; @@ -73,6 +68,12 @@ devShells.default = pkgs.mkShell { name = "lightning-js-dev"; + # Nix's fortify hardening breaks tikv-jemalloc-sys debug builds: the + # wrapper injects _FORTIFY_SOURCE, cargo passes -O0, glibc emits a + # #warning, and jemalloc's -Werror configure probes all fail + # ("cannot determine return type of strerror_r"). + hardeningDisable = [ "fortify" ]; + packages = with pkgs; [ nodejs_22 yarn diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..80ce98a --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,9 @@ +# Single source of truth for the dev-shell and CI-check toolchain: the flake +# reads this via fenix fromToolchainFile and rustup reads it natively in CI, +# so the two cannot drift (a floating CI "stable" once linted code the dev +# shell's clippy had never seen). Cargo.toml's `rust-version = "1.85"` stays +# the MSRV for downstream consumers; the napi release builds pin their own +# RUST_VERSION in CI.yml. +[toolchain] +channel = "1.97.0" +components = ["clippy", "rustfmt", "rust-src", "rust-analyzer"] From 34a48023530a03efa8e331743170157dcfb9b895 Mon Sep 17 00:00:00 2001 From: amackillop Date: Wed, 29 Jul 2026 11:51:30 -0700 Subject: [PATCH 2/2] Keep release builds on RUST_VERSION despite the toml Codex caught what the toolchain pin broke: rust-toolchain.toml is a rustup directory override, so it outranked the release matrix's `rustup default 1.85` and every build ran under 1.97, whose cross-targets were never installed (android, windows, and darwin jobs failed on missing targets; the docker jobs would have followed). RUSTUP_TOOLCHAIN outranks the directory override, so the host Build step sets it and the docker run forwards it, both derived from the existing RUST_VERSION. The check job is untouched and keeps following the toml. --- .github/workflows/CI.yml | 6 ++++++ rust-toolchain.toml | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index bcef2cf..f67cedd 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -188,6 +188,7 @@ jobs: docker run --rm \ --user 0:0 \ -e RUST_VERSION=${{ env.RUST_VERSION }} \ + -e RUSTUP_TOOLCHAIN=${{ env.RUST_VERSION }} \ -v /tmp/build.sh:/tmp/build.sh \ -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db \ -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache \ @@ -196,10 +197,15 @@ jobs: -w /build \ ${{ matrix.settings.docker }} \ sh /tmp/build.sh + # RUSTUP_TOOLCHAIN outranks rust-toolchain.toml's directory override, + # which would otherwise hijack these release builds onto the lint + # toolchain (whose cross-targets are not installed). - name: Build run: ${{ matrix.settings.build }} if: ${{ !matrix.settings.docker }} shell: bash + env: + RUSTUP_TOOLCHAIN: ${{ env.RUST_VERSION }} - name: Upload artifact uses: actions/upload-artifact@v4 with: diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 80ce98a..903eaf9 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,8 +2,10 @@ # reads this via fenix fromToolchainFile and rustup reads it natively in CI, # so the two cannot drift (a floating CI "stable" once linted code the dev # shell's clippy had never seen). Cargo.toml's `rust-version = "1.85"` stays -# the MSRV for downstream consumers; the napi release builds pin their own -# RUST_VERSION in CI.yml. +# the MSRV for downstream consumers. The napi release builds pin their own +# RUST_VERSION in CI.yml and set RUSTUP_TOOLCHAIN, which outranks this file's +# directory override; without that they would silently build under this +# toolchain with no cross-targets installed. [toolchain] channel = "1.97.0" components = ["clippy", "rustfmt", "rust-src", "rust-analyzer"]