From 0584d6779c2ab39833bee87fe94185fdec7f7632 Mon Sep 17 00:00:00 2001 From: CodeWhale Bot Date: Mon, 31 Aug 2026 22:26:11 -0700 Subject: [PATCH] ci(buildkite): put the Linux toolchain where both users can reach it Build 1445 confirmed the re-exec works -- the suite reached uid 1000 -- and then died on `cargo: command not found`. rustup had installed into `/root/.cargo`, which mode 0700 makes unreadable the moment the job stops being root. Install the toolchain into /opt/cargo + /opt/rustup on the Linux agent and mark it a+rX, pass an explicit HOME through the re-exec, and hand CARGO_HOME and ./target to the build user so cargo can still write its registry, git checkouts and target dir. macOS is unaffected: it is not root, so it keeps the HOME-relative paths. That leg has now passed twice at 328s (builds 1443 and 1445). Signed-off-by: CodeWhale Bot --- .buildkite/steps/common.sh | 30 +++++++++++++++++++++++------- .buildkite/steps/test.sh | 3 +++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.buildkite/steps/common.sh b/.buildkite/steps/common.sh index 6ee3499c8..7f60f2f8d 100644 --- a/.buildkite/steps/common.sh +++ b/.buildkite/steps/common.sh @@ -17,19 +17,35 @@ if [ "$(uname -s)" = "Linux" ]; then ca-certificates curl pkg-config libdbus-1-dev build-essential fi +# The Linux job runs as root, and test.sh re-execs the suite as an +# unprivileged user (root ignores permission bits, which silently defeats every +# read-only assertion). A toolchain under /root is unreadable after that swap -- +# build 1445 got `cargo: command not found` at uid 1000 -- so install it +# somewhere both users can reach. +if [ "$(id -u)" = "0" ] && [ "$(uname -s)" = "Linux" ]; then + export CARGO_HOME=/opt/cargo + export RUSTUP_HOME=/opt/rustup +else + export CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}" + export RUSTUP_HOME="${RUSTUP_HOME:-$HOME/.rustup}" +fi +export PATH="$CARGO_HOME/bin:$PATH" + # rust-toolchain.toml pins `stable`; rustup honours it on first cargo call. if ! command -v cargo >/dev/null 2>&1; then curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ - | sh -s -- -y --profile minimal --default-toolchain stable + | sh -s -- -y --profile minimal --default-toolchain stable --no-modify-path fi # shellcheck disable=SC1091 -[ -f "$HOME/.cargo/env" ] && . "$HOME/.cargo/env" - -# Export toolchain homes explicitly so the unprivileged re-exec in test.sh can -# inherit them; rustup's default HOME-relative paths do not survive a user swap. -export CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}" -export RUSTUP_HOME="${RUSTUP_HOME:-$HOME/.rustup}" +[ -f "$CARGO_HOME/env" ] && . "$CARGO_HOME/env" export PATH="$CARGO_HOME/bin:$PATH" +# Readable+traversable by the unprivileged user; cargo still needs to write +# into CARGO_HOME for `cargo install`, so that stays root-owned until test.sh +# hands it over. +if [ "$(id -u)" = "0" ] && [ "$(uname -s)" = "Linux" ]; then + chmod -R a+rX "$CARGO_HOME" "$RUSTUP_HOME" 2>/dev/null || true +fi + cargo --version rustc --version diff --git a/.buildkite/steps/test.sh b/.buildkite/steps/test.sh index f00bf1176..8a15c2952 100755 --- a/.buildkite/steps/test.sh +++ b/.buildkite/steps/test.sh @@ -31,9 +31,12 @@ run_suite() { if [ "$(id -u)" = "0" ] && [ "$(uname -s)" = "Linux" ]; then id -u builder >/dev/null 2>&1 || useradd -m -s /bin/bash builder + # cargo writes into CARGO_HOME (registry, git checkouts) and ./target, so + # both must belong to the user that will actually run the suite. chown -R builder:builder . "$CARGO_HOME" "$RUSTUP_HOME" 2>/dev/null || true echo "--- re-exec as unprivileged user (root ignores permission bits)" exec runuser -u builder -- env \ + HOME=/home/builder \ PATH="$PATH" CARGO_HOME="$CARGO_HOME" RUSTUP_HOME="$RUSTUP_HOME" \ CARGO_TERM_COLOR="${CARGO_TERM_COLOR:-always}" \ CARGO_INCREMENTAL="${CARGO_INCREMENTAL:-0}" \