From aa2679162d4fe68061060e8a0b57acccf17bad7e Mon Sep 17 00:00:00 2001 From: funman300 Date: Tue, 11 Aug 2026 16:20:16 +0000 Subject: [PATCH] redirector.sh: never leave it ambiguous which binary is under test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two defects, both found by the guards misfiring rather than by reading: 1. BIN preferred target/debug and fell back to release only when debug was absent. `cargo build --release` therefore produced a correct binary while the script kept inspecting a stale debug one, and the build guard refused with a message naming a commit nobody was trying to run. The guard was right that something was stale — it just pointed at the wrong artifact. Disagreement between the two is now an explicit refusal naming both, with OPENFUT_REDIRECTOR_BIN as the deliberate override. The refusal is recorded at load and raised only by `verify` and `start`. `stop` and `status` must work in any build-tree state: rollback can never be blocked by a question about which artifact would have been started. 2. `verify-running` read the stamp file without checking the process still existed. The stamp outlives the process, so after a stop it reported on a corpse — either "identity OK" or a REFUSAL naming a commit, both implying something was running when nothing was. Co-Authored-By: Claude Opus 5 --- openfut-redirector-host/redirector.sh | 46 +++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/openfut-redirector-host/redirector.sh b/openfut-redirector-host/redirector.sh index 3741b80..789d5eb 100755 --- a/openfut-redirector-host/redirector.sh +++ b/openfut-redirector-host/redirector.sh @@ -22,8 +22,36 @@ PORTFILE="$RUNDIR/redirector.port" # when the branch ref moves) can silently advance past the live process. STAMPFILE="$RUNDIR/redirector.commit" LOGFILE="${OPENFUT_REDIRECTOR_LOG:-$RUNDIR/redirector.log}" -BIN="$ROOT/target/debug/openfut-redirector-host" -[[ -x "$BIN" ]] || BIN="$ROOT/target/release/openfut-redirector-host" +# Which artifact is under test must never be ambiguous. Preferring debug and +# falling back to release meant `cargo build --release` could produce a fresh +# binary while this kept launching a stale debug one — the guard then compared +# the WRONG artifact against HEAD and refused with a message naming a commit +# nobody was trying to run. Both present and disagreeing is an error, not a +# preference. Set OPENFUT_REDIRECTOR_BIN to choose deliberately. +DEBUG_BIN="$ROOT/target/debug/openfut-redirector-host" +RELEASE_BIN="$ROOT/target/release/openfut-redirector-host" +BIN_ERR="" +if [[ -n "${OPENFUT_REDIRECTOR_BIN:-}" ]]; then + BIN="$OPENFUT_REDIRECTOR_BIN" + [[ -x "$BIN" ]] || { echo "redirector: OPENFUT_REDIRECTOR_BIN is not executable: $BIN" >&2; exit 1; } +elif [[ -x "$DEBUG_BIN" && -x "$RELEASE_BIN" ]]; then + d="$("$DEBUG_BIN" --identity 2>&1 | sed -nE 's/.*commit=([0-9a-f]+).*/\1/p' | head -1)" + r="$("$RELEASE_BIN" --identity 2>&1 | sed -nE 's/.*commit=([0-9a-f]+).*/\1/p' | head -1)" + if [[ "$d" != "$r" ]]; then + # Recorded, NOT fatal here: `stop` and `status` must keep working no matter + # what state the build tree is in. Rolling back can never be blocked by a + # question about which artifact would have been started. + BIN_ERR="REFUSING — two binaries exist and disagree. + debug $DEBUG_BIN commit=$d + release $RELEASE_BIN commit=$r + Rebuild both, delete one, or set OPENFUT_REDIRECTOR_BIN." + fi + BIN="$RELEASE_BIN" +elif [[ -x "$DEBUG_BIN" ]]; then + BIN="$DEBUG_BIN" +else + BIN="$RELEASE_BIN" +fi die() { echo "redirector: $*" >&2; exit 1; } pid_alive() { kill -0 "$1" 2>/dev/null; } @@ -48,16 +76,21 @@ list_procs() { return 0 } +# Only the commands that actually run a binary care which one it is. +need_bin() { [[ -z "$BIN_ERR" ]] || die "$BIN_ERR"; } + # The binary prints `commit=` in its banner; ask it rather than guessing. stamped_commit() { "$BIN" --identity 2>&1 | sed -nE 's/.*commit=([0-9a-f]+).*/\1/p' | head -1; } cmd_verify() { + need_bin local c; c="$(stamped_commit)" [[ -n "$c" ]] || die "could not read the binary's commit stamp" "$ROOT/scripts/verify-build-identity.sh" "$c" } cmd_start() { + need_bin [[ -x "$BIN" ]] || die "not built: cargo build -p openfut-redirector-host" : "${OPENFUT_REDIRECTOR_HOST_PORT:?set OPENFUT_REDIRECTOR_HOST_PORT (no default: runs beside Python)}" local strays; strays="$(list_procs)" @@ -115,6 +148,15 @@ cmd_status() { } cmd_verify_running() { + # The stamp outlives the process it describes. Without this check the command + # happily reports on a corpse — either "OK" or a REFUSAL naming a commit, + # both implying something is running when nothing is. + local pid="" + [[ -f "$PIDFILE" ]] && pid="$(cat "$PIDFILE" 2>/dev/null)" + if [[ -z "$pid" ]] || ! pid_alive "$pid"; then + echo "REFUSING: nothing is running — the stamp describes a process that has exited." >&2 + return 1 + fi [[ -f "$STAMPFILE" ]] || die "no running-process stamp — was it started by this script?" local running head running="$(cat "$STAMPFILE")"; head="$(git -C "$ROOT" rev-parse --short=7 HEAD 2>/dev/null)"