diff --git a/openfut-blaze-host/build.rs b/openfut-blaze-host/build.rs index 4d33901..f6eea38 100644 --- a/openfut-blaze-host/build.rs +++ b/openfut-blaze-host/build.rs @@ -49,10 +49,18 @@ fn main() { println!("cargo:rustc-env=OPENFUT_BUILD_COMMIT={commit}"); println!("cargo:rustc-env=OPENFUT_BUILD_DIRTY={dirty}"); - // Re-stamp when HEAD moves. Working-tree edits are not tracked by cargo's - // dependency graph, so `dirty` can go stale until something forces a - // rebuild — the startup banner says which commit it was stamped from, and - // the sidecar script re-checks the working tree independently at launch. + // Re-stamp when HEAD moves. + // + // IMPORTANT LIMITATION: this flag is best-effort and CAN BE STALE. Cargo + // will not re-run a build script because some other crate's source changed, + // so editing the adapter and rebuilding the host can leave `dirty` reading + // "clean". Verified: appending a line to the adapter and rebuilding did not + // flip it. + // + // So the compiled-in value is useful for naming the commit, and is NOT the + // safeguard. `sidecar.sh` re-checks the working tree at launch and + // `check-live-parity.sh` refuses to produce evidence from a dirty tree — + // those run at the right moment and cannot go stale. for p in ["../.git/HEAD", "../.git/index"] { if std::path::Path::new(p).exists() { println!("cargo:rerun-if-changed={p}"); diff --git a/openfut-blaze-host/check-live-parity.sh b/openfut-blaze-host/check-live-parity.sh index aed2f23..f78f115 100755 --- a/openfut-blaze-host/check-live-parity.sh +++ b/openfut-blaze-host/check-live-parity.sh @@ -38,6 +38,23 @@ if [[ ! -x "$PROBE" ]]; then exit 2 fi +# This script produces the artefact a migration decision is made from, so it +# refuses to run against a tree that does not correspond to a commit. The +# compiled-in build stamp cannot be trusted for this (cargo will not re-run +# build.rs for another crate's edit), so the check happens here, now. +if git rev-parse --git-dir >/dev/null 2>&1; then + DIRT="$(git status --porcelain --untracked-files=no -- \ + openfut-blaze-host openfut-adapter-fifa17 openfut-protocol-blaze 2>/dev/null)" + if [[ -n "$DIRT" && "${ALLOW_DIRTY:-}" != "1" ]]; then + echo "REFUSING: migration crates have uncommitted changes:" >&2 + echo "$DIRT" | sed 's/^/ /' >&2 + echo >&2 + echo "A parity result from an unidentifiable build is not evidence." >&2 + echo "Commit first, or re-run with ALLOW_DIRTY=1 for a throwaway check." >&2 + exit 2 + fi +fi + mkdir -p "$OUT" fail=0 frames=0 diff --git a/openfut-blaze-host/sidecar.sh b/openfut-blaze-host/sidecar.sh index 280b548..2cc00a9 100755 --- a/openfut-blaze-host/sidecar.sh +++ b/openfut-blaze-host/sidecar.sh @@ -32,6 +32,22 @@ BIN="$ROOT/target/debug/openfut-blaze-host" die() { echo "sidecar: $*" >&2; exit 1; } +# Authoritative working-tree check, run at LAUNCH. +# +# The commit stamped into the binary by build.rs can be stale — cargo does not +# re-run a build script when another crate's source changes — so the compiled-in +# "dirty" flag is not a safeguard. This is. It runs now, against the tree as it +# is now, over exactly the crates the binary is built from. +# +# Echoes "DIRTY" or "clean" (or "unknown" outside a git tree). +tree_state() { + git -C "$ROOT" rev-parse --git-dir >/dev/null 2>&1 || { echo unknown; return; } + local out + out="$(git -C "$ROOT" status --porcelain --untracked-files=no -- \ + openfut-blaze-host openfut-adapter-fifa17 openfut-protocol-blaze 2>/dev/null)" + [[ -n "$out" ]] && echo DIRTY || echo clean +} + port_listening() { local port="$1" if command -v ss >/dev/null 2>&1; then @@ -100,6 +116,13 @@ cmd_start() { die "port $OPENFUT_BLAZE_HOST_PORT is already in use" fi + local tree + tree="$(tree_state)" + if [[ "$tree" == "DIRTY" ]]; then + echo "WARNING: migration crates have uncommitted changes — this binary may not" >&2 + echo " match any commit. Do not treat its output as parity evidence." >&2 + fi + mkdir -p "$RUNDIR" echo "$OPENFUT_BLAZE_HOST_PORT" > "$PORTFILE"