From 11a2b05e3afad97b94ae7411a704c8bb51153582 Mon Sep 17 00:00:00 2001 From: "usehoplite[bot]" <288093033+usehoplite[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 06:14:55 +0000 Subject: [PATCH 01/14] =?UTF-8?q?test(mcpverbscheck):=20pin=20the=20exact?= =?UTF-8?q?=20advertised=20MCP=20verb=20roster=20=E2=80=94=20a=20constant-?= =?UTF-8?q?count=20swap=20must=20not=20slip=20a=20verb=20in?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds (6b)/(6c) to the L4 section. L4_COUNT==31 fails closed on a verb ADDED and the per-name arms pin the L4/field-notes verbs individually, but a rename or swap that keeps the count at 31 and touches a verb no arm names (analyze, grep, the edit trio, ...) passes every existing arm — CONTRIBUTING §2 shape 7 ('true but narrower'). (6b) pins the full sorted advertised roster so ANY add/remove/rename reddens until a human signs for it; (6c) is the mutation control proving (6b) can see a new verb, plus a named tripwire asserting no shell/exec-shaped verb is advertised (--run-trace stays CLI-only). Context: security-audit follow-up. Both audit findings closed clean — M1 (report XSS) not-a-bug, verified end-to-end: jsonesc::escapeHtml \uXXXX-escapes <>& at emission and all 8 innerHTML sinks escape repo-derived values or interpolate integers/constexpr vocab. L1 (--run-trace reachable from MCP) was never a vuln: no such verb exists. This arm is invariant-hardening so that stays true, not a vuln fix. Verified on a real build: planted lego->run_trace in kMcpVerbTable + the tools/list stanza (constant-count swap) — L4_COUNT==31 stayed green, (6b) reddened with the diff, (6c) tripwire reddened; reverted, gate ALL PASS. New arm in an existing gate file — no regression.sh or gate-count ride-along. --- test/mcpverbscheck.sh | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/test/mcpverbscheck.sh b/test/mcpverbscheck.sh index b7f433be6..ae3c35234 100755 --- a/test/mcpverbscheck.sh +++ b/test/mcpverbscheck.sh @@ -302,6 +302,76 @@ if [ "$L4_EDITCHK" = "True" ]; then ok "tools/list includes 'edit_check'"; else [ "$L4_PACKTASK" = "False" ] && ok "'pack_task' is NOT separately advertised in tools/list (dispatch-only alias)" \ || no "'pack_task' unexpectedly appears in tools/list" +# ── (6b) THE EXACT ADVERTISED ROSTER — a constant-count swap must not slip a verb in ───────────── +# WHY THIS ARM. The L4_COUNT==31 assertion above fails closed on a verb ADDED; the per-name checks pin +# the L4/field-notes verbs individually. Neither catches a RENAME or SWAP that keeps the count at 31 and +# touches a verb no arm names (analyze, grep, the edit trio, …) — CONTRIBUTING §2 shape 7 ("true but +# narrower"): "same count + these names present" is strictly weaker than "the roster is EXACTLY this set". +# A verb that reaches a subprocess (a hypothetical run_trace MCP twin of the CLI-only --run-trace) could +# replace an unnamed read verb at count 31 with every arm above still green. Pinning the FULL sorted +# roster reddens on ANY add/remove/rename until a human updates this list — the point being that a new +# MCP verb, above all one that reaches an exec, is signed for, never a silent drift. +# The set is the ADVERTISED roster (kMcpVerbTable, mcp.h); pack_task stays out (dispatch-only alias, +# already asserted absent above). Sorted so the diff reads name-by-name. +EXPECTED_VERBS="analyze +batch +cochange +connect +doc_drift +edit_check +exemplar +explore +fetch_body +find_referencing_symbols +find_symbol +flags +for +from_trace +grep +impact +insert_after_symbol +insert_before_symbol +lego +memory_recall +mentions +owners +path_between +quality_baseline +quality_delta +replace_symbol_body +situational_awareness +slice +stray_content +uses +whereis" + +LIVE_VERBS_SORTED="$( l4_field 'chr(10).join(sorted(names))' )" +EXPECTED_SORTED="$( printf '%s\n' "$EXPECTED_VERBS" | sort )" + +if [ "$LIVE_VERBS_SORTED" = "$EXPECTED_SORTED" ]; then + ok "(6b) advertised roster matches the pinned set exactly ($L4_COUNT verbs; no unpinned add/rename/swap)" +else + no "(6b) advertised roster DRIFTED from the pinned set — a verb was added, removed, or renamed; review it (a subprocess-reaching verb must never join silently), then update EXPECTED_VERBS consciously:" + diff <(printf '%s\n' "$EXPECTED_SORTED") <(printf '%s\n' "$LIVE_VERBS_SORTED") | sed 's/^/ /' +fi + +# ── (6c) LIVENESS of (6b) + the named shell-exec tripwire (CONTRIBUTING §2: prove the arm can fail) ─ +# (6b) is only as live as its ability to SEE a new verb. Prove it on a mutated copy of the live list: +# inject a synthetic run_trace and assert the SAME comparison reddens. Guards shape 3 (empty==empty) if +# a future edit ever broke the extraction. Computed here, run every time — never a fixture of the server. +MUT_LIVE="$( printf '%s\nrun_trace\n' "$LIVE_VERBS_SORTED" | sort )" +if [ "$MUT_LIVE" != "$EXPECTED_SORTED" ]; then + ok "(6c) mutation control: a synthetic 'run_trace' verb is correctly seen as roster drift" +else + no "(6c) mutation control VACUOUS: injecting 'run_trace' did not disturb the comparison — (6b) cannot fail" +fi +# The invariant, named for the reader who greps for it: no shell/exec-shaped verb is advertised. +if printf '%s\n' "$LIVE_VERBS_SORTED" | grep -qxE 'run_trace|run|shell|exec'; then + no "(6c) an MCP verb named like a shell/exec entry point is advertised — --run-trace must stay CLI-only (runtracecheck.sh)" +else + ok "(6c) no shell/exec-shaped verb advertised (MCP surface reaches no subprocess exec; --run-trace stays CLI-only)" +fi + # ── explore round-trip: a pack-task-shaped bundle (same shape as CLI --pack-task) ──────────────── EXPLORE_MSGS=( '{"jsonrpc":"2.0","id":1,"method":"initialize"}' From 393c85ce00f79e3405f8933f00bed6e11297fe00 Mon Sep 17 00:00:00 2001 From: joyful-ii-V-I Date: Sun, 20 Sep 2026 15:10:25 -0400 Subject: [PATCH 02/14] fix(test): re-derive EXPECTED_VERBS in mcpverbscheck.sh for train 10's roster MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #291 (@pt-act) pinned the pre-train-10 31-verb MCP roster in test/mcpverbscheck.sh's (6b)/(6c) arms. Train 10 (#300) added two MCP verbs, affected and rank_by, taking the live roster to 33, which reddened the PR's own gate on rebase. EXPECTED_VERBS is by design a hand-maintained pin, but the VALUE was derived from the live binary rather than typed from memory: built HEAD, called tools/list over --mcp, and took the sorted 33-name output verbatim. Reproved the arm's whole point on this binary before committing: planted an add, a remove, and a count-preserving rename (lego -> run_probe) in src/mcp.h's tools/list stanza (not the kMcpVerbTable mirror near the top of that file, which is not what's served over the wire) and confirmed all three redden (6b), with the rename case also proving the pre-existing count-only arm stays green while (6b) catches it — the gap this PR exists to close. Credit: @pt-act (PR #291, mechanism and (6b)/(6c) arms). Co-Authored-By: Claude Sonnet 5 --- test/mcpverbscheck.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/mcpverbscheck.sh b/test/mcpverbscheck.sh index ae3c35234..553e6a622 100755 --- a/test/mcpverbscheck.sh +++ b/test/mcpverbscheck.sh @@ -313,7 +313,8 @@ if [ "$L4_EDITCHK" = "True" ]; then ok "tools/list includes 'edit_check'"; else # MCP verb, above all one that reaches an exec, is signed for, never a silent drift. # The set is the ADVERTISED roster (kMcpVerbTable, mcp.h); pack_task stays out (dispatch-only alias, # already asserted absent above). Sorted so the diff reads name-by-name. -EXPECTED_VERBS="analyze +EXPECTED_VERBS="affected +analyze batch cochange connect @@ -338,6 +339,7 @@ owners path_between quality_baseline quality_delta +rank_by replace_symbol_body situational_awareness slice From b4e1bd811a9f514e75b9d363504f9d2ec57119e6 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Sat, 19 Sep 2026 22:14:22 +0100 Subject: [PATCH 03/14] test: centralize GNU-vs-BSD stat compat; close a real-write env leak in codexpromptroutecheck MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Twelve gates independently hand-rolled the same detect-GNU-vs-BSD-stat fix (a `stat -f ... || stat -c ...` one-liner never reaches its `-c` fallback on Linux, because GNU's `-f` is a different, valid flag — filesystem stat, not BSD's format string — so it succeeds with junk instead of failing). test/lib/statcompat.sh centralizes the flavour detection and provides ready-to-call functions (mtime_of/inode_of/ mode_of/size_of/inode_mtime_of) so sourcing it replaces each file's own copy-pasted block; two gates (evictioncheck.sh, qsnapprefetchcheck.sh) keep a one-line local wrapper for their own fallback-string convention. mcpeditmodecheck.sh's separately-named `file_mode` was the same function under a different name; renamed its call sites to `mode_of` instead of keeping a second name for one thing. codexpromptroutecheck.sh's `skills install --codex --hook` calls only override HOME/CODEX_HOME/AGENTS_HOME, not RIPWIRE_DATA_HOME — a real write into an ambient store path once the embedded-skills feature (redhat-et/ripwire#225) lands, same class of leak as the CLAUDE_CONFIG_DIR incident test/lib/unset-agent-env-variables.sh documents on that branch (not yet on main). test/lib/clean-env.sh is this PR's main-side equivalent, scoped to the vars gates on main actually read. Verified: full pargates suite, alone and under added CPU contention; --quality-delta gating=0; determinism + xmllint clean. The three gates that fail under -j6 parallel load (legendcoveragecheck.sh, pargatescheck.sh, rootrelemitcheck.sh) all pass alone and are unrelated to any file this commit touches — confirmed pre-existing/ environmental, not introduced here. Co-Authored-By: Claude Sonnet 5 --- test/cachehashcheck.sh | 13 +------------ test/cachesplitcheck.sh | 11 +---------- test/clonecachecheck.sh | 16 +--------------- test/codexpromptroutecheck.sh | 5 +++-- test/evictioncheck.sh | 12 ++---------- test/g1freshcheck.sh | 14 +------------- test/headsnapcachecheck.sh | 11 +---------- test/lib/clean-env.sh | 6 ++++++ test/lib/statcompat.sh | 20 ++++++++++++++++++++ test/mcpeditmodecheck.sh | 17 +++-------------- test/portablecachecheck.sh | 16 +--------------- test/prcontextcheck.sh | 13 +------------ test/qsnapcachecheck.sh | 11 +---------- test/qsnapprefetchcheck.sh | 12 ++---------- test/statgatecheck.sh | 12 ------------ 15 files changed, 44 insertions(+), 145 deletions(-) create mode 100644 test/lib/clean-env.sh create mode 100644 test/lib/statcompat.sh diff --git a/test/cachehashcheck.sh b/test/cachehashcheck.sh index a3d3d8222..ffdeba791 100755 --- a/test/cachehashcheck.sh +++ b/test/cachehashcheck.sh @@ -42,6 +42,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT @@ -94,18 +95,6 @@ touch -r "$TMP/f.cpp.ref" "$WORK/f.cpp" touch -r "$DIR_REF" "$WORK" 2>/dev/null || true # Confirm the mtime restore actually worked (sanity on the attack itself, not the tool under test). -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then # GNU coreutils - mtime_of(){ stat -c '%Y' "$1" 2>/dev/null; } -else # BSD / macOS - mtime_of(){ stat -f '%m' "$1" 2>/dev/null; } -fi ref_mtime="$( mtime_of "$TMP/f.cpp.ref" )" new_mtime="$( mtime_of "$WORK/f.cpp" )" if [ "$ref_mtime" = "$new_mtime" ]; then diff --git a/test/cachesplitcheck.sh b/test/cachesplitcheck.sh index 622d804d0..21b99e61b 100755 --- a/test/cachesplitcheck.sh +++ b/test/cachesplitcheck.sh @@ -29,6 +29,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT @@ -46,16 +47,6 @@ CORPUS="$ROOT/test/fixture" XDG="$TMP/xdg"; mkdir -p "$XDG" CACHEDIR="$XDG/ripwire" -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then inode_of(){ stat -c %i "$1" 2>/dev/null; } # GNU coreutils -else inode_of(){ stat -f %i "$1" 2>/dev/null; } # BSD / macOS -fi # glob helper: echo the single matching class file (or empty). Y4: shard-aware lookup — a blob may # live flat under $CACHEDIR or under $CACHEDIR// (2-hex-char shard), so search both via find -maxdepth 2. richfile(){ find "$CACHEDIR" -maxdepth 2 -type f -name 'ripwire-*-rich.bin' 2>/dev/null | head -1; } diff --git a/test/clonecachecheck.sh b/test/clonecachecheck.sh index 95bec3299..00ece6b04 100755 --- a/test/clonecachecheck.sh +++ b/test/clonecachecheck.sh @@ -29,6 +29,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT @@ -66,21 +67,6 @@ FIVE_DAYS_AGO=$(( $(date +%s) - 5*86400 )) touch -t "$(date -r "$FIVE_DAYS_AGO" +%Y%m%d%H%M.%S 2>/dev/null || date -d "@$FIVE_DAYS_AGO" +%Y%m%d%H%M.%S)" "$CACHEDIR" 2>/dev/null \ || touch -d "@$FIVE_DAYS_AGO" "$CACHEDIR" 2>/dev/null -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then # GNU coreutils - mtime_of(){ stat -c '%Y' "$1" 2>/dev/null; } - mode_of(){ stat -c '%a' "$1" 2>/dev/null; } -else # BSD / macOS - mtime_of(){ stat -f '%m' "$1" 2>/dev/null; } - mode_of(){ stat -f '%Lp' "$1" 2>/dev/null; } -fi - BEFORE_MTIME="$( mtime_of "$CACHEDIR" )" env -u TMPDIR XDG_CACHE_HOME="$XDG" "$BIN" "$URL" >"$TMP/a_stdout" 2>"$TMP/a_stderr" diff --git a/test/codexpromptroutecheck.sh b/test/codexpromptroutecheck.sh index 7ee619b13..c6f0ec124 100755 --- a/test/codexpromptroutecheck.sh +++ b/test/codexpromptroutecheck.sh @@ -4,6 +4,7 @@ # and length, never prompt text, and hook installation stays idempotent. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" HOOK="$ROOT/hooks/ripwire-codex-route.sh" @@ -137,9 +138,9 @@ OFF="$( printf '%s\n' "{\"prompt\":\"$PROMPT\",\"cwd\":\"$TMP/repo\",\"session_i && ok "routing-meter opt-out keeps advice but writes no log or pending state" \ || no "routing-meter opt-out suppressed advice or wrote state" -HOME="$TMP/home" CODEX_HOME="$TMP/home/.codex" AGENTS_HOME="$TMP/home/.agents" \ +HOME="$TMP/home" CODEX_HOME="$TMP/home/.codex" AGENTS_HOME="$TMP/home/.agents" RIPWIRE_DATA_HOME="$TMP/home/.local/share/ripwire" \ bash "$ROOT/skills/install.sh" --codex --hook >/dev/null -HOME="$TMP/home" CODEX_HOME="$TMP/home/.codex" AGENTS_HOME="$TMP/home/.agents" \ +HOME="$TMP/home" CODEX_HOME="$TMP/home/.codex" AGENTS_HOME="$TMP/home/.agents" RIPWIRE_DATA_HOME="$TMP/home/.local/share/ripwire" \ bash "$ROOT/skills/install.sh" --codex --hook >/dev/null SETTINGS="$TMP/home/.codex/hooks.json" jq -e --arg cmd "$HOOK" '[.hooks.UserPromptSubmit[]?.hooks[]? | select(.command == $cmd)] | length == 1' "$SETTINGS" >/dev/null 2>&1 \ diff --git a/test/evictioncheck.sh b/test/evictioncheck.sh index cfa20964e..45afa8b4d 100755 --- a/test/evictioncheck.sh +++ b/test/evictioncheck.sh @@ -48,6 +48,7 @@ # Usage: test/evictioncheck.sh | RIPWIRE_BIN=build_r2a1/ripwire test/evictioncheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 @@ -63,16 +64,7 @@ REPO="$TMP/repo"; mkdir -p "$REPO" # apparent (logical) byte size of a file — what fs::file_size measures, NOT `du`'s block-usage view # (a sparse file's disk usage is ~0 but its apparent size is what the sweep's byte budget compares against). -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then apparentsize(){ stat -c %s "$1" 2>/dev/null || echo 0; } # GNU coreutils -else apparentsize(){ stat -f %z "$1" 2>/dev/null || echo 0; } # BSD / macOS -fi +apparentsize(){ size_of "$1" || echo 0; } # Y4: shard-aware — every blob glob below now looks at both the flat top-level AND any 2-hex-char shard # subdir (mindepth/maxdepth bound it to exactly the layouts the sweep itself understands; never an # open-ended walk of a shared $TMPDIR). diff --git a/test/g1freshcheck.sh b/test/g1freshcheck.sh index 2e8079966..d1f4fbdcc 100755 --- a/test/g1freshcheck.sh +++ b/test/g1freshcheck.sh @@ -18,6 +18,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" ASAN_BIN="$ROOT/asan/ripwire" ASAN_DIR="$ROOT/asan" SRC_DIR="$ROOT/src" @@ -46,19 +47,6 @@ if [ ! -f "$ASAN_BIN" ]; then fi # Both asan/ripwire and src/ exist. Check if the binary is older than the newest src file. -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then # GNU coreutils - mtime_of(){ stat -c '%Y' "$1" 2>/dev/null; } -else # BSD / macOS - mtime_of(){ stat -f '%m' "$1" 2>/dev/null; } -fi - asan_mtime="$( mtime_of "$ASAN_BIN" )" || { no "could not stat asan/ripwire" exit 1 diff --git a/test/headsnapcachecheck.sh b/test/headsnapcachecheck.sh index 5c432c051..d001daad8 100755 --- a/test/headsnapcachecheck.sh +++ b/test/headsnapcachecheck.sh @@ -28,6 +28,7 @@ # Usage: test/headsnapcachecheck.sh | RIPWIRE_BIN=build_w2e/ripwire test/headsnapcachecheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 @@ -41,16 +42,6 @@ REPO="$( mktemp -d )"; TMP="$( mktemp -d )"; trap 'rm -rf "$REPO" "$TMP"' EXIT XDG="$TMP/xdg"; mkdir -p "$XDG" CACHEDIR="$XDG/ripwire" -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then inode_of(){ stat -c %i "$1" 2>/dev/null; } # GNU coreutils -else inode_of(){ stat -f %i "$1" 2>/dev/null; } # BSD / macOS -fi # Y4: shard-aware lookup — a blob may be flat under $CACHEDIR or under $CACHEDIR// (2-hex shard). snapfiles(){ find "$CACHEDIR" -maxdepth 2 -type f -name 'ripwire-qheadsnap-*.bin' 2>/dev/null; } nsnap(){ snapfiles | wc -l | tr -d ' '; } diff --git a/test/lib/clean-env.sh b/test/lib/clean-env.sh new file mode 100644 index 000000000..a5e14e354 --- /dev/null +++ b/test/lib/clean-env.sh @@ -0,0 +1,6 @@ +# clean-env.sh — the agent-home-relocating env vars a gate must clear before it varies HOME= per +# invocation: CODEX_HOME/AGENTS_HOME/HERMES_HOME/CLAUDE_CONFIG_DIR/RIPWIRE_DATA_HOME override the +# default derived from HOME, so a gate that only sets HOME= is not sandboxed on a machine where any of +# these is already exported ambiently. SOURCED, not run. Source this FIRST, then set whatever homes +# the gate actually needs. +unset CODEX_HOME AGENTS_HOME HERMES_HOME CLAUDE_CONFIG_DIR RIPWIRE_DATA_HOME diff --git a/test/lib/statcompat.sh b/test/lib/statcompat.sh new file mode 100644 index 000000000..0f782b2ed --- /dev/null +++ b/test/lib/statcompat.sh @@ -0,0 +1,20 @@ +# statcompat.sh — GNU-vs-BSD `stat` compat, in one place. SOURCED, not run. +# +# GNU coreutils' `-f` is a different, valid flag (filesystem stat, not BSD's format string): it +# succeeds with junk instead of failing, so a caller-local `stat -f ... || stat -c ...` one-liner never +# reaches its own fallback on Linux. Twelve gates hand-rolled that same detect-once-and-redefine fix +# independently before this file existed. Sourcing this gives every one of them a ready-to-call +# function; no caller branches on the flavour itself. +if stat --version >/dev/null 2>&1; then # GNU coreutils + mtime_of() { stat -c '%Y' "$1" 2>/dev/null; } + inode_of() { stat -c '%i' "$1" 2>/dev/null; } + mode_of() { stat -c '%a' "$1" 2>/dev/null; } + size_of() { stat -c '%s' "$1" 2>/dev/null; } + inode_mtime_of() { stat -c '%i %Y' "$1" 2>/dev/null; } +else # BSD / macOS + mtime_of() { stat -f '%m' "$1" 2>/dev/null; } + inode_of() { stat -f '%i' "$1" 2>/dev/null; } + mode_of() { stat -f '%Lp' "$1" 2>/dev/null; } + size_of() { stat -f '%z' "$1" 2>/dev/null; } + inode_mtime_of() { stat -f '%i %m' "$1" 2>/dev/null; } +fi diff --git a/test/mcpeditmodecheck.sh b/test/mcpeditmodecheck.sh index a6d1f99d2..4d3c0d1d7 100755 --- a/test/mcpeditmodecheck.sh +++ b/test/mcpeditmodecheck.sh @@ -18,6 +18,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT @@ -30,18 +31,6 @@ no(){ printf ' FAIL %s\n' "$*"; fail=1; } echo "mcpeditmodecheck: BIN=$BIN" -# portable "octal mode of a file" (BSD/macOS stat -f vs GNU stat -c). -# L3 (Linux probe): the `stat -f FMT ... || stat -c FMT ...` fallback this used is a TRAP. On GNU, `-f` means -# FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on coreutils -# 9.11, `stat -f '%Lp' FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1, so the `||` -# arm appends the right mode under six lines of junk and `[ "$PERM" = "700" ]` can never hold. Detect the -# flavour ONCE, use one form. -file_mode(){ - if stat --version >/dev/null 2>&1; then stat -c '%a' "$1" 2>/dev/null # GNU coreutils - else stat -f '%Lp' "$1" 2>/dev/null # BSD / macOS - fi -} - # drive one replace_symbol_body call through the MCP server (spec-conforming params.arguments form), # echo the tools/call response line. mcp_replace(){ # $1=dir $2=symbol $3=new_body @@ -64,11 +53,11 @@ int run_tool( int x ) } CPP chmod 0755 "$W1/exec.cpp" -BEFORE_MODE="$( file_mode "$W1/exec.cpp" )" +BEFORE_MODE="$( mode_of "$W1/exec.cpp" )" [ "$BEFORE_MODE" = "755" ] || { echo " (setup) could not set fixture mode to 0755 (got $BEFORE_MODE)"; } R1="$( mcp_replace "$W1" run_tool 'int run_tool( int x )\n{\n return x + 2;\n}' )" -AFTER_MODE="$( file_mode "$W1/exec.cpp" )" +AFTER_MODE="$( mode_of "$W1/exec.cpp" )" case "$R1" in *applied*) : ;; diff --git a/test/portablecachecheck.sh b/test/portablecachecheck.sh index d1270726f..d6054416e 100755 --- a/test/portablecachecheck.sh +++ b/test/portablecachecheck.sh @@ -37,6 +37,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT @@ -193,21 +194,6 @@ fi # ════════════════════════════════════════════════════════════════════════════════════════════════════ DIRTY_PROBE="$TMP/dirty_probe.cache" "$BIN" "$PATH_A" --cache="$DIRTY_PROBE" --no-stable >/dev/null 2>&1 # cold populate -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then # GNU coreutils - mtime_of(){ stat -c '%Y' "$1" 2>/dev/null; } - size_of(){ stat -c '%s' "$1" 2>/dev/null; } -else # BSD / macOS - mtime_of(){ stat -f '%m' "$1" 2>/dev/null; } - size_of(){ stat -f '%z' "$1" 2>/dev/null; } -fi - BEFORE_SIZE="$( size_of "$DIRTY_PROBE" )" # touch nothing; re-run warm — the cache file must NOT be rewritten (Win-2 dirty-flag: unchanged tree # skips saveCache entirely), which only happens if every file HASH-MATCHED against a re-absolutized key. diff --git a/test/prcontextcheck.sh b/test/prcontextcheck.sh index afcb4e8af..6938d9528 100755 --- a/test/prcontextcheck.sh +++ b/test/prcontextcheck.sh @@ -19,6 +19,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT @@ -119,18 +120,6 @@ echo "$OUT_REF" | grep -q 'base="HEAD"[^>]*files="1"' \ # ── A3-F10: a pure mode flip (chmod, content untouched) must NOT count as a changed file, and the # skipped count must be reported so the information isn't silently lost. Flip src/user.cpp to 755 # (content already committed, unmodified) alongside the real core.cpp content edit above. -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then # GNU coreutils - mode_of(){ stat -c '%a' "$1" 2>/dev/null; } -else # BSD / macOS - mode_of(){ stat -f '%Lp' "$1" 2>/dev/null; } -fi ORIG_MODE="$( mode_of "$REPO/src/user.cpp" )" chmod 755 "$REPO/src/user.cpp" MODEOUT="$( "$BIN" "$REPO" --pr-context --no-cache 2>/dev/null )" diff --git a/test/qsnapcachecheck.sh b/test/qsnapcachecheck.sh index 09fdb6d41..0336832ff 100755 --- a/test/qsnapcachecheck.sh +++ b/test/qsnapcachecheck.sh @@ -28,6 +28,7 @@ # Usage: test/qsnapcachecheck.sh | RIPWIRE_BIN=build_r2a1/ripwire test/qsnapcachecheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 @@ -41,16 +42,6 @@ REPO="$( mktemp -d )"; TMP="$( mktemp -d )"; trap 'rm -rf "$REPO" "$TMP"' EXIT XDG="$TMP/xdg"; mkdir -p "$XDG" CACHEDIR="$XDG/ripwire" -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then inode_of(){ stat -c %i "$1" 2>/dev/null; } # GNU coreutils -else inode_of(){ stat -f %i "$1" 2>/dev/null; } # BSD / macOS -fi # Y4: shard-aware lookup — a blob may be flat under $CACHEDIR or under $CACHEDIR// (2-hex shard). qsnapfiles(){ find "$CACHEDIR" -maxdepth 2 -type f -name 'ripwire-qsnap-*.bin' 2>/dev/null; } nqsnap(){ qsnapfiles | wc -l | tr -d ' '; } diff --git a/test/qsnapprefetchcheck.sh b/test/qsnapprefetchcheck.sh index 2fa17ebe2..0f1fd1b26 100755 --- a/test/qsnapprefetchcheck.sh +++ b/test/qsnapprefetchcheck.sh @@ -46,6 +46,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/fixture" @@ -110,16 +111,7 @@ wait_for_id() { local i; for i in $( seq 1 200 ); do grep -q "\"id\":$2" "$1" 2> blob_paths() { find "$1" -maxdepth 3 -type f -name "$2" 2>/dev/null; } blob_first() { blob_paths "$1" "$2" | head -1; } qsnap_count() { blob_paths "$1" 'ripwire-qsnap-*.bin' | grep -c . ; } -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -if stat --version >/dev/null 2>&1; then inode_mtime(){ stat -c '%i %Y' "$1" 2>/dev/null || echo "MISSING"; } # GNU coreutils -else inode_mtime(){ stat -f '%i %m' "$1" 2>/dev/null || echo "MISSING"; } # BSD / macOS -fi +inode_mtime(){ inode_mtime_of "$1" || echo "MISSING"; } skip(){ printf ' SKIP %s\n' "$*"; } # The no-warning row only measures something on a ThreadSanitizer build; on any other binary it is a SKIP by name, never # a PASS, because a plain binary prints no warning whether or not the race is there (arm (f) passes on the unfixed diff --git a/test/statgatecheck.sh b/test/statgatecheck.sh index 863cb28c4..839ed0530 100755 --- a/test/statgatecheck.sh +++ b/test/statgatecheck.sh @@ -49,18 +49,6 @@ note(){ printf ' NOTE %s\n' "$*"; } [ -x "$BIN" ] || { echo "no ripwire binary at $BIN — build first (cmake --build build -j)"; exit 2; } echo "statgatecheck: BIN=$BIN TMP=$TMP" -# L3 (Linux probe): portable stat reader(s). GNU coreutils and BSD/macOS disagree on both the flag and the -# format directives, and the `stat -f FMT ... || stat -c FMT ...` fallback this gate used is a TRAP. On GNU, -# `-f` means FILESYSTEM status and takes NO format argument, so FMT is parsed as a second FILE: measured on -# coreutils 9.11, `stat -f %i FILE` PRINTS a six-line filesystem block for FILE on stdout and exits 1. The -# `||` arm then appends the right number under six lines of junk -- so a string compare fails, a numeric -# compare dies with "integer expression expected", and a `|| echo MISSING` variant reports MISSING forever -# (a gate that then passes by comparing nothing to nothing). Detect the flavour ONCE, use one form. -# (ns precision where the FS/stat supports it: BSD %Fm, GNU %.9Y) -if stat --version >/dev/null 2>&1; then mtime_ns(){ stat -c '%.9Y' "$1" 2>/dev/null; } # GNU coreutils -else mtime_ns(){ stat -f '%Fm' "$1" 2>/dev/null; } # BSD / macOS -fi - # ── case (a): warm no-change run is byte-identical ──────────────────────────────────────────────── WA="$TMP/a"; mkdir -p "$WA"; CA="$TMP/a.bin" printf 'int alpha( void )\n{\n return 1;\n}\n' > "$WA/f.cpp" From da85a2d27c52895ef83c15e8f07077099a28911f Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Sun, 20 Sep 2026 12:26:34 +0100 Subject: [PATCH 04/14] test: fold four more gates onto statcompat.sh; close claudeconfigdircheck's own hermetic leak Addresses the two before-merge items from PR #298's review: - cacheisolationcheck.sh, qsnapproducercheck.sh, sidecarsymlinkcheck.sh and tempfilesymlinkcheck.sh hand-rolled the same GNU-vs-BSD stat detect-once block this PR already extracted from twelve other gates. All four now source test/lib/statcompat.sh instead. - claudeconfigdircheck.sh's "UNSET IS UNCHANGED" arm relied on CLAUDE_CONFIG_DIR being absent from the environment rather than clearing it, so an ambiently exported CLAUDE_CONFIG_DIR made the gate write real files into it and then fail against its own contaminated baseline. It now sources test/lib/clean-env.sh first, same as skillinstallcheck.sh and hermesinstallcheck.sh, which had the identical gap and are consolidated onto the same helper instead of a narrower ad hoc unset. CHANGELOG.md folds these into the two stat/env entries covering the whole PR. Verified: all seven touched gates ALL PASS; claudeconfigdircheck.sh reproduces the review's exact leak scenario clean with CLAUDE_CONFIG_DIR exported ambiently; --quality-delta gating=0; determinism + xmllint clean. Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 24 ++++++++++++++++++++++++ test/cacheisolationcheck.sh | 3 ++- test/claudeconfigdircheck.sh | 1 + test/hermesinstallcheck.sh | 1 + test/qsnapproducercheck.sh | 4 +--- test/sidecarsymlinkcheck.sh | 7 ++----- test/skillinstallcheck.sh | 3 +-- test/tempfilesymlinkcheck.sh | 5 ++--- 8 files changed, 34 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc4a1c4bf..a108fd55d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -228,6 +228,30 @@ the arm compares normally. When an arm is still refused, the root carries `reaso debug trace. Both `ok=` postures and `reason=` are defined in the legend. Gates: `test/scoutheadconflictcheck.sh` arms T9(a)–(e), `test/mergescoutcheck.sh`. (CodeRabbit review on #295) +### Fixed — sixteen gates now share one GNU/BSD `stat` compat helper instead of a per-gate copy + +`stat -f` is GNU coreutils' filesystem-stat flag, not BSD's format-string flag, so it succeeds with junk +instead of failing — a caller-local `stat -f ... || stat -c ...` one-liner never reaches its own fallback on +Linux. Sixteen gates each hand-rolled the same detect-once-and-redefine fix independently: +`cachehashcheck.sh`, `cachesplitcheck.sh`, `clonecachecheck.sh`, `codexpromptroutecheck.sh`, +`evictioncheck.sh`, `g1freshcheck.sh`, `headsnapcachecheck.sh`, `mcpeditmodecheck.sh`, +`portablecachecheck.sh`, `prcontextcheck.sh`, `qsnapcachecheck.sh`, `qsnapprefetchcheck.sh`, +`statgatecheck.sh`, `cacheisolationcheck.sh`, `qsnapproducercheck.sh`, `sidecarsymlinkcheck.sh` and +`tempfilesymlinkcheck.sh` all now source the new shared `test/lib/statcompat.sh` instead — one place defines +the GNU-vs-BSD `stat` compat logic, not seventeen. + +### Fixed — a gate that varies `HOME=` per invocation could still leak into an ambiently-set agent-home variable + +`CODEX_HOME`/`AGENTS_HOME`/`HERMES_HOME`/`CLAUDE_CONFIG_DIR`/`RIPWIRE_DATA_HOME` override the default an +agent's tools derive from `HOME`, so a gate that only sets `HOME=` per invocation is not actually sandboxed +on a machine where any of these is already exported ambiently. `codexpromptroutecheck.sh`, +`claudeconfigdircheck.sh`, `skillinstallcheck.sh` and `hermesinstallcheck.sh` now source the new shared +`test/lib/clean-env.sh` before varying `HOME=`, closing that leak in each. `claudeconfigdircheck.sh` — the +gate that exists specifically to test `CLAUDE_CONFIG_DIR` relocation — was the one this hit hardest: with +`CLAUDE_CONFIG_DIR` exported ambiently (a developer whose real Claude Code config is relocated, exactly the +case this gate tests for), its "unset" baseline arm wrote real files into that directory and then failed +comparing against its own contaminated baseline. + ### Fixed — an ambiguous `--expand` buried its body behind the ranked map, and the escape hatch was stderr-only Reported by @mariadb-KyleHutchinson in #289: `--expand=SYM` on a name matching more than one definition, in a diff --git a/test/cacheisolationcheck.sh b/test/cacheisolationcheck.sh index d31059e2a..147bf96ec 100755 --- a/test/cacheisolationcheck.sh +++ b/test/cacheisolationcheck.sh @@ -3,6 +3,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 @@ -30,7 +31,7 @@ PRIVATE="$SHARED/ripwire" if [ -d "$PRIVATE" ]; then ok "creates a dedicated TMPDIR/ripwire directory"; else no "missing private directory: $PRIVATE"; fi if [ -d "$PRIVATE" ]; then - if stat --version >/dev/null 2>&1; then mode="$( stat -c %a "$PRIVATE" )"; else mode="$( stat -f %Lp "$PRIVATE" )"; fi + mode="$( mode_of "$PRIVATE" )" if [ "$mode" = "700" ]; then ok "private directory mode is 0700"; else no "private directory mode is $mode, expected 700"; fi fi diff --git a/test/claudeconfigdircheck.sh b/test/claudeconfigdircheck.sh index 61f6146ec..ae5204646 100755 --- a/test/claudeconfigdircheck.sh +++ b/test/claudeconfigdircheck.sh @@ -43,6 +43,7 @@ # otherwise fall back to it. Exits non-zero on any failure. Does NOT edit regression.sh. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/hermesinstallcheck.sh b/test/hermesinstallcheck.sh index 94d0bf04c..43be35089 100755 --- a/test/hermesinstallcheck.sh +++ b/test/hermesinstallcheck.sh @@ -13,6 +13,7 @@ # Exits non-zero on any failure. Does NOT edit regression.sh. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" SK="$ROOT/skills" fail=0 ok(){ echo " PASS $1" || { fail=1; echo " FAIL could not write the PASS line for: $1"; }; return 0; } diff --git a/test/qsnapproducercheck.sh b/test/qsnapproducercheck.sh index 9ee02eb92..359085048 100755 --- a/test/qsnapproducercheck.sh +++ b/test/qsnapproducercheck.sh @@ -57,6 +57,7 @@ # Usage: test/qsnapproducercheck.sh | RIPWIRE_BIN=build/ripwire test/qsnapproducercheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" QSRC="$ROOT/src/quality.h" @@ -218,9 +219,6 @@ h=14695981039346656037 for c in sys.argv[1].encode(): h=((h^c)*1099511628211)&((1<<64)-1) print("%016x"%h)' "$1"; } blob_for(){ find "$CACHEDIR" -maxdepth 2 -type f -name "ripwire-qsnap-*-$( shakey "$1" ).bin" 2>/dev/null | head -1; } -if stat --version >/dev/null 2>&1; then inode_of(){ stat -c %i "$1" 2>/dev/null; } -else inode_of(){ stat -f %i "$1" 2>/dev/null; } -fi # ── (D) the blob records this tree's identity ────────────────────────────────────────────────────────────── echo "// touch" >> "$REPO/src/use.cpp" # a working-tree change, HEAD untouched diff --git a/test/sidecarsymlinkcheck.sh b/test/sidecarsymlinkcheck.sh index 9ad568b41..d1166ca0a 100755 --- a/test/sidecarsymlinkcheck.sh +++ b/test/sidecarsymlinkcheck.sh @@ -166,6 +166,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" # BOTH seams: regression.sh and every differential run pass the binary POSITIONALLY; RIPWIRE_BIN is the # env form. A gate reading only one of them comes back ALL PASS against whatever is in build/ during a # red-first run against a BASE binary — the exact way a red-first check fakes itself green (archcheck.sh @@ -534,11 +535,7 @@ fi # ── (g) MODE CONTROL: the hand-written mode must equal what ofstream/fopen asked for ────────────────── # umask 000 is what makes this discriminating: under the usual 022 a wrong 0644 is indistinguishable from # the correct 0666. GNU stat and BSD stat disagree about -f, so pick the flavour once (CONTRIBUTING §1). -if stat --version >/dev/null 2>&1; then - fileMode(){ stat -c '%a' "$1"; } -else - fileMode(){ stat -f '%Lp' "$1"; } -fi +fileMode(){ mode_of "$1"; } modeArm() { diff --git a/test/skillinstallcheck.sh b/test/skillinstallcheck.sh index 8fd6ff40c..b47fb893e 100755 --- a/test/skillinstallcheck.sh +++ b/test/skillinstallcheck.sh @@ -10,6 +10,7 @@ # Exits non-zero on any failure. Does NOT edit regression.sh or ~/.claude. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" SK="$ROOT/skills" fail=0 ok(){ echo " PASS $1" || { fail=1; echo " FAIL could not write the PASS line for: $1"; }; return 0; } @@ -18,8 +19,6 @@ no(){ echo " FAIL $1"; fail=1; } [ -f "$SK/install.sh" ] || { echo "no skills/install.sh"; exit 2; } TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT -# Each invocation below owns its HOME; inherited agent overrides must not escape it. -unset CODEX_HOME AGENTS_HOME HERMES_HOME DST="$TMP/skills" # ---- 1) install.sh deploys EVERY user-facing shipped skill (the deployment-drift catch) ---- diff --git a/test/tempfilesymlinkcheck.sh b/test/tempfilesymlinkcheck.sh index d4117324c..e1d8e8122 100644 --- a/test/tempfilesymlinkcheck.sh +++ b/test/tempfilesymlinkcheck.sh @@ -42,6 +42,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow repo-relative RIPWIRE_BIN fail=0 @@ -63,9 +64,7 @@ OUTSIDE_MODE=700 place_outside(){ printf '%s' "$OUTSIDE_BYTES" > "$1"; chmod "$OUTSIDE_MODE" "$1"; } # filemode FILE — permission bits in octal (GNU coreutils stat, else BSD / macOS stat). -if stat --version >/dev/null 2>&1; then filemode(){ stat -c %a "$1" 2>/dev/null; } -else filemode(){ stat -f %Lp "$1" 2>/dev/null; } -fi +filemode(){ mode_of "$1"; } # assert_outside TAG OUTSIDE_FILE — (a) bytes and (b) mode are unchanged. assert_outside(){ From 16c1e72b94556f44b1435c97e96023a9db2a613c Mon Sep 17 00:00:00 2001 From: llvm-x86 Date: Sun, 20 Sep 2026 10:59:42 -0500 Subject: [PATCH 05/14] docs(readme,skills): the --top-k/--for inertness trap, first-run anti-patterns, and what ripwire does not replace Field report from a first-time agent session (moderate-high friction, cold parse itself was fine at 0.8s / 759 files): the pain was discovering the right verb/flag shape, and three of the traps trace to documentation gaps this change closes: - README's budget item said '--top-k=N caps the rows' with no scope qualifier. On --for the flag is read by nothing: the run prints the stderr note and emits the full bundle anyway, so the agent believes it narrowed the output and did not. The item now names the flags --top-k actually shapes and points --for at --signatures-only / --token-budget / --detail=N. - New WRONG -> RIGHT table beside the budget guidance: --top-k on --for, --query as a default lens (the binary's own help calls it debug; the navigate skill already frames it as vocabulary hunting), --expand without --top-k=0 (the ~200-symbol map rides along), --callers on a framework route handler (empty by design), and a directory-of-repos root. - New 'what ripwire does not replace' table: route-to-handler lookup from a URL, templates/i18n/migrations, one exact string in a named file, UX flow through frontend handlers. - skills/ripwire-navigate: the same budgeting trap warning at the --query-vs---for section, where an agent meets --for first. - skills/ripwire-orient: step 6's '--top-k=50' tip now scopes itself to the default map and names the --for bounding flags. No behavior change: the DISCLOSE-not-refuse design in cli.h (noticeShapingFlagIgnored) is deliberate and stays. Docs-only. Verified: every quoted string (--top-k is not read by --for, raw BM25 ranking (debug); use --for) confirmed verbatim in src/cli.h at HEAD; readmedriftcheck.sh failure count identical before/after this change (18, all pre-existing 0.3.8-binary vs HEAD skew; local toolchain is g++-11, too old for , so gates ran against the installed binary). --- README.md | 28 +++++++++++++++++++++++++++- skills/ripwire-navigate/SKILL.md | 5 +++++ skills/ripwire-orient/SKILL.md | 4 +++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fdfa6b211..755e2f232 100644 --- a/README.md +++ b/README.md @@ -682,7 +682,12 @@ to do with it.** Two shapes get the most out of it, and one gets nothing.
The three controls that decide what it costs — a budget (--token-budget / --top-k), routing (--help-task), and the skills that teach an agent when not to reach for it -1. **A budget.** `--token-budget=N` caps the bundle; `--top-k=N` caps the rows. Unbudgeted `--for` returns +1. **A budget.** `--token-budget=N` caps the bundle; `--top-k=N` caps the rows **of the default map, + `--query`, `--format=candidates`, `--recall` and `--graph-query` — it does not shape `--for`**. On + `--for` it is read by nothing: the run prints a stderr note (`--top-k is not read by --for`) and + still emits the full bundle. Narrow `--for` with its own arguments instead — `--signatures-only` + (drop the auto-bodies), `--token-budget=N` (shapes the bundle to fit), `--detail=N` (full bodies for + just the top N). Unbudgeted `--for` returns a rich terminal bundle by design — right when it ends the question, wasteful when it does not. 2. **Routing.** `ripwire . --help-task=""` names the ONE command the task actually wants, and abstains when the evidence is thin. It is advice, it never runs anything. An answer of "just grep @@ -692,6 +697,27 @@ to do with it.** Two shapes get the most out of it, and one gets nothing. time — including the times it should not.
+
+The invocations first-time users get wrong — WRONG → RIGHT, each row a real failure reported from the field + +| WRONG | RIGHT | why | +|---|---|---| +| `ripwire . --for="…" --top-k=5` | `ripwire . --for="…" --signatures-only` (or `--token-budget=N`, `--detail=N`) | `--top-k` is inert on `--for`: the run warns on stderr and emits the full bundle anyway, so the agent *believes* it narrowed the output and did not. | +| `ripwire . --query="…"` as the default lens | `ripwire . --for="…"` | `--query` is the raw BM25 ranking — the binary's own help calls it debug and says "use --for". It is the right tool for hunting a vocabulary, the wrong default for a task. | +| `ripwire . --expand=SYM` | `ripwire . --expand=SYM --top-k=0` | Without `--top-k=0` the ~200-symbol ranked map (~10K est_tokens) rides along with the one body you asked for. | +| `--callers=` expecting routes | find the URL in the project's own docs (e.g. a feature map), then `--expand` the handler | Framework route handlers have no callers in the graph — the decorator reaches them, not project code. Empty `--callers` on a handler is the design, not a bug. | +| `ripwire …` | `cd` into ONE checkout first | The map is per-repository; pointing it at a directory *of* repositories is the expensive mistake the wrapper guards exist to refuse. | + +**What ripwire does not replace** — reach for `grep`/`read` here even when a verb looks close: + +| still use grep/read for | why | +|---|---| +| route → handler lookup from a URL | ripwire ranks symbols, not URLs; it does not know your routes | +| templates, i18n catalogs, SQL migrations | not call-graph territory | +| one exact string in one file you can already name | `--grep=TERM` works, but `rg` is fine too — and the map is a fixed cost you did not need | +| UX flow through frontend event handlers | the JS is in the graph, but the flow needs line context, not a ranking | +
+
What is measured and what is not — these are single-agent figures; that the saving grows with the number of cold orientations is pre-registered and unrun, not a published result diff --git a/skills/ripwire-navigate/SKILL.md b/skills/ripwire-navigate/SKILL.md index 60a3dc70d..d3342653b 100644 --- a/skills/ripwire-navigate/SKILL.md +++ b/skills/ripwire-navigate/SKILL.md @@ -227,6 +227,11 @@ field un-places every field after it. A `modeled="1"` number that agrees with th - Rule of thumb: `--for` for a task you're about to do; `--query` for a vocabulary you're hunting. Both shine on specific technical wording; for broad common-word asks, plain `rg` + one read can still win. +**Budgeting trap:** `--top-k` is inert on `--for` — the run warns on stderr and emits the full bundle anyway. +Narrow `--for` with its own arguments: `--signatures-only` (no auto-bodies), `--token-budget=N` (shapes the +bundle to fit), `--detail=N` (full bodies for just the top N). `--top-k` does shape `--query` — and pair it +with `--expand` as `--top-k=0` whenever you want one body without the ranked map riding along. + ## When the fixed verbs can't phrase the question Compose filters over the call graph with `--graph-query=EXPR` — see **ripwire-graph-query** for the diff --git a/skills/ripwire-orient/SKILL.md b/skills/ripwire-orient/SKILL.md index d6176fa2c..3ec3c0185 100644 --- a/skills/ripwire-orient/SKILL.md +++ b/skills/ripwire-orient/SKILL.md @@ -99,7 +99,9 @@ cluster looks like the one you'll be working in and five names aren't enough to **5. Maintenance pain** — `ripwire --hotspots --legend=compact` — files ranked by `score = churn × ccx`; `top=` names the gnarliest function. Plan edits around this list. -**6. Budget it** if the map is large — `--max-tokens=8000` or `--top-k=50`. +**6. Budget it** if the map is large — `--max-tokens=8000` or `--top-k=50`. Both shape the default map; +`--top-k` is inert on `--for` (it warns on stderr and emits the full bundle) — bound a `--for` call with +`--signatures-only`, `--token-budget=N` or `--detail=N` instead. ## Orienting N agents at once, not yourself — `--partition=N` From d75c41a1cbc6d4c0ea9c22b7365f334274b7be80 Mon Sep 17 00:00:00 2001 From: llvm-x86 Date: Sun, 20 Sep 2026 11:59:38 -0500 Subject: [PATCH 06/14] docs(readme,skills): scope the --for budgeting rule, the --expand row, and the dir-of-repos row to what the binary actually does Review pass on #302 (three findings, all verified against src/ at HEAD): 1. --for budgeting rule was unqualified. The notice+full-bundle path is POSITIVE, EXPLICIT --top-k on plain --for only (cli.h noticeShapingFlagIgnored: isTopKConsumedBeside = c.candidates || c.topK == 0 suppresses it). --for --format=candidates --top-k=N consumes the flag; --for --top-k=0 is refused by the payload-only guard (c.ok = false), not warned. README item 1 + both skills now say so. 2. --expand row was stale against the #289 reorder. An unambiguous single match already defaults to --top-k=0 (main.cpp exactNameExpandDefault, disclosed as topk_default="0"); only an AMBIGUOUS bare name keeps the map. Row + navigate SKILL.md sentence scoped to the ambiguous case. 3. dir-of-repos row claimed "the wrapper guards exist to refuse". No such guard exists in this repo; the crawl silently merges nested checkouts into one corpus. Row now describes the silent over-broad merge and distinguishes it from the real multi-root feature (N explicit positional roots, 2-16). --- README.md | 14 +++++++++----- skills/ripwire-navigate/SKILL.md | 11 +++++++---- skills/ripwire-orient/SKILL.md | 4 ++-- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 755e2f232..75989fee3 100644 --- a/README.md +++ b/README.md @@ -683,9 +683,13 @@ to do with it.** Two shapes get the most out of it, and one gets nothing. The three controls that decide what it costs — a budget (--token-budget / --top-k), routing (--help-task), and the skills that teach an agent when not to reach for it 1. **A budget.** `--token-budget=N` caps the bundle; `--top-k=N` caps the rows **of the default map, - `--query`, `--format=candidates`, `--recall` and `--graph-query` — it does not shape `--for`**. On - `--for` it is read by nothing: the run prints a stderr note (`--top-k is not read by --for`) and - still emits the full bundle. Narrow `--for` with its own arguments instead — `--signatures-only` + `--query`, `--format=candidates`, `--recall` and `--graph-query` — it does not shape plain `--for`**. + On `--for`, a *positive, explicit* `--top-k` is read by nothing: the run prints a stderr note + (`--top-k is not read by --for`) and still emits the full bundle. Two neighbours of that shape are + different and neither warns: `--for --format=candidates --top-k=N` *does* consume the flag (the + candidate export composes with it and caps the rows), and `--for --top-k=0` is refused outright by the + payload-only guard (`--top-k=0` needs a payload verb), not warned-and-emitted. Narrow plain `--for` + with its own arguments instead — `--signatures-only` (drop the auto-bodies), `--token-budget=N` (shapes the bundle to fit), `--detail=N` (full bodies for just the top N). Unbudgeted `--for` returns a rich terminal bundle by design — right when it ends the question, wasteful when it does not. @@ -704,9 +708,9 @@ to do with it.** Two shapes get the most out of it, and one gets nothing. |---|---|---| | `ripwire . --for="…" --top-k=5` | `ripwire . --for="…" --signatures-only` (or `--token-budget=N`, `--detail=N`) | `--top-k` is inert on `--for`: the run warns on stderr and emits the full bundle anyway, so the agent *believes* it narrowed the output and did not. | | `ripwire . --query="…"` as the default lens | `ripwire . --for="…"` | `--query` is the raw BM25 ranking — the binary's own help calls it debug and says "use --for". It is the right tool for hunting a vocabulary, the wrong default for a task. | -| `ripwire . --expand=SYM` | `ripwire . --expand=SYM --top-k=0` | Without `--top-k=0` the ~200-symbol ranked map (~10K est_tokens) rides along with the one body you asked for. | +| `ripwire . --expand=SYM` where SYM is an **ambiguous** bare name | `ripwire . --expand=SYM --top-k=0` (or name it exactly: `--expand=FILE:NAME`) | A multi-match name keeps the ranked map — there IS something to disambiguate — so ~9K est_tokens of map ride along with the bodies. An **unambiguous** single match already defaults to `--top-k=0` on its own (disclosed as `topk_default="0"`); no flag needed there. | | `--callers=` expecting routes | find the URL in the project's own docs (e.g. a feature map), then `--expand` the handler | Framework route handlers have no callers in the graph — the decorator reaches them, not project code. Empty `--callers` on a handler is the design, not a bug. | -| `ripwire …` | `cd` into ONE checkout first | The map is per-repository; pointing it at a directory *of* repositories is the expensive mistake the wrapper guards exist to refuse. | +| `ripwire …` (ONE root that happens to contain checkouts) | `cd` into ONE checkout first | Nothing refuses this: the crawl silently walks the nested repos and merges them into one corpus, so you pay for a map of everything and rank across unrelated codebases. Distinct from the real multi-root feature, which is N **explicit** positional roots (`ripwire dir1 dir2 … `, 2–16 checkouts merged on purpose). | **What ripwire does not replace** — reach for `grep`/`read` here even when a verb looks close: diff --git a/skills/ripwire-navigate/SKILL.md b/skills/ripwire-navigate/SKILL.md index d3342653b..b17ce3f0b 100644 --- a/skills/ripwire-navigate/SKILL.md +++ b/skills/ripwire-navigate/SKILL.md @@ -227,10 +227,13 @@ field un-places every field after it. A `modeled="1"` number that agrees with th - Rule of thumb: `--for` for a task you're about to do; `--query` for a vocabulary you're hunting. Both shine on specific technical wording; for broad common-word asks, plain `rg` + one read can still win. -**Budgeting trap:** `--top-k` is inert on `--for` — the run warns on stderr and emits the full bundle anyway. -Narrow `--for` with its own arguments: `--signatures-only` (no auto-bodies), `--token-budget=N` (shapes the -bundle to fit), `--detail=N` (full bodies for just the top N). `--top-k` does shape `--query` — and pair it -with `--expand` as `--top-k=0` whenever you want one body without the ranked map riding along. +**Budgeting trap:** a positive, explicit `--top-k` is inert on plain `--for` — the run warns on stderr and +emits the full bundle anyway. (`--for --format=candidates --top-k=N` is different: the export consumes the +flag and caps the rows, no warning. `--for --top-k=0` is refused by the payload-only guard.) +Narrow plain `--for` with its own arguments: `--signatures-only` (no auto-bodies), `--token-budget=N` (shapes +the bundle to fit), `--detail=N` (full bodies for just the top N). `--top-k` does shape `--query` — and pair +it with `--expand` as `--top-k=0` when SYM is an *ambiguous* bare name; an unambiguous single match already +drops the map by default (`topk_default="0"`). ## When the fixed verbs can't phrase the question diff --git a/skills/ripwire-orient/SKILL.md b/skills/ripwire-orient/SKILL.md index 3ec3c0185..53edf33d6 100644 --- a/skills/ripwire-orient/SKILL.md +++ b/skills/ripwire-orient/SKILL.md @@ -100,8 +100,8 @@ cluster looks like the one you'll be working in and five names aren't enough to the gnarliest function. Plan edits around this list. **6. Budget it** if the map is large — `--max-tokens=8000` or `--top-k=50`. Both shape the default map; -`--top-k` is inert on `--for` (it warns on stderr and emits the full bundle) — bound a `--for` call with -`--signatures-only`, `--token-budget=N` or `--detail=N` instead. +a positive, explicit `--top-k` is inert on plain `--for` (it warns on stderr and emits the full bundle) — +bound a `--for` call with `--signatures-only`, `--token-budget=N` or `--detail=N` instead. ## Orienting N agents at once, not yourself — `--partition=N` From a7281dea662eb684a629dbd794d0372403c6d051 Mon Sep 17 00:00:00 2001 From: joyful-ii-V-I Date: Sun, 20 Sep 2026 15:18:33 -0400 Subject: [PATCH 07/14] fix(test): close six more hermetic-isolation leaks past PR #298's own sweep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #298 (@s0undt3ch) centralized the GNU-vs-BSD stat trap and, after the review posted publicly on this PR, pushed a follow-up commit closing the hermetic leak in claudeconfigdircheck.sh plus skillinstallcheck.sh/hermesinstallcheck.sh (test/lib/clean-env.sh). The task asked to extend that fix past the single call site the review reproduced, so I swept the rest of test/*.sh for gates that call skills/install.sh or scripts/install.sh with only HOME= varied per invocation, leaving CODEX_HOME/AGENTS_HOME/HERMES_HOME/CLAUDE_CONFIG_DIR/ RIPWIRE_DATA_HOME free to leak in from an ambient export the same way claudeconfigdircheck.sh did. Found and closed six more: - test/hookcheck.sh, test/routehookcheck.sh — both call `install.sh --hook` (the Claude path, reads CLAUDE_CONFIG_DIR) varying only HOME=. - test/agenttablecheck.sh, test/codexinstallhonestycheck.sh, test/meterdisclosurecheck.sh — same install.sh --hook / skills-install shape, CLAUDE_CONFIG_DIR left uncleared on at least one call site each. - test/releaseinstallcheck.sh already unset CODEX_HOME/AGENTS_HOME/HERMES_HOME for scripts/install.sh, which reads the identical five-variable set (confirmed: scripts/install.sh:375/383/391 read CLAUDE_CONFIG_DIR/ CODEX_HOME-or-AGENTS_HOME/HERMES_HOME the same way skills/install.sh does) but was missing CLAUDE_CONFIG_DIR and RIPWIRE_DATA_HOME from its unset line. Five sourced test/lib/clean-env.sh (the helper PR #298 already introduced); releaseinstallcheck.sh already had a bespoke unset line for installer-specific vars (RIPWIRE_NO_ACTIVATE etc.), so it keeps that line and gains the two missing names instead of switching shape. Red-first, reproduced the exact PR #298 review scenario against hookcheck.sh: with CLAUDE_CONFIG_DIR exported ambiently, the pre-fix script wrote a real settings.json + skills/ into that directory and then failed its own "file created" assertion against the sandboxed path (rc=1, `install.sh --hook: .../hookhome/.claude/settings.json not created`). The fixed script leaves the ambient directory untouched and reports ALL PASS under the same export. No other test/*.sh has the same call-then-check shape against these five variables (checked hookcheck.sh's stat -f fixture-string hit separately — literal test data for a different gate, not a live stat call, matching PR #298's own note). codexdoctorcheck.sh and similar Codex-only gates always pass --codex, which reads CODEX_HOME/AGENTS_HOME, not CLAUDE_CONFIG_DIR, and already set those explicitly per call. Verified: all 25 gates PR #298 touches or that I touch here pass, plus manifestcheck/gateexitcheck/gatecountcheck (no new gate files). No source changes; test-only. Credit: @s0undt3ch (PR #298, statcompat.sh/clean-env.sh + the first four migrated gates and the original claudeconfigdircheck.sh fix). Co-Authored-By: Claude Sonnet 5 --- test/agenttablecheck.sh | 1 + test/codexinstallhonestycheck.sh | 1 + test/hookcheck.sh | 1 + test/meterdisclosurecheck.sh | 1 + test/releaseinstallcheck.sh | 8 ++++++-- test/routehookcheck.sh | 1 + 6 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/agenttablecheck.sh b/test/agenttablecheck.sh index 6d1a29aef..d0d72bc04 100755 --- a/test/agenttablecheck.sh +++ b/test/agenttablecheck.sh @@ -10,6 +10,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/codexinstallhonestycheck.sh b/test/codexinstallhonestycheck.sh index 1d99f42e7..f610a883a 100755 --- a/test/codexinstallhonestycheck.sh +++ b/test/codexinstallhonestycheck.sh @@ -24,6 +24,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" : "$BIN" # unused by this gate (install.sh needs no ripwire binary), kept for the shared convention INSTALL="$ROOT/skills/install.sh" diff --git a/test/hookcheck.sh b/test/hookcheck.sh index 6c0f33a79..4e6eb9ff3 100755 --- a/test/hookcheck.sh +++ b/test/hookcheck.sh @@ -17,6 +17,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" HOOK="$ROOT/hooks/ripwire-nudge.sh" INSTALL="$ROOT/skills/install.sh" fail=0 diff --git a/test/meterdisclosurecheck.sh b/test/meterdisclosurecheck.sh index 33277fb21..b891b123c 100755 --- a/test/meterdisclosurecheck.sh +++ b/test/meterdisclosurecheck.sh @@ -25,6 +25,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" : "$BIN" # unused (this gate inspects install.sh's own source/output text, no ripwire binary needed) INSTALL="$ROOT/skills/install.sh" diff --git a/test/releaseinstallcheck.sh b/test/releaseinstallcheck.sh index 41c267b58..c36cdbefa 100755 --- a/test/releaseinstallcheck.sh +++ b/test/releaseinstallcheck.sh @@ -11,8 +11,12 @@ ok(){ printf ' PASS %s\n' "$*" || { fail=1; printf ' FAIL could not write th no(){ printf ' FAIL %s\n' "$*"; fail=1; } TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT -# Detection and activation must use only the per-invocation homes below. -unset CODEX_HOME AGENTS_HOME HERMES_HOME RIPWIRE_NO_ACTIVATE RIPWIRE_SKIP_CPU_CHECK RIPWIRE_CPUINFO +# Detection and activation must use only the per-invocation homes below. CLAUDE_CONFIG_DIR/ +# RIPWIRE_DATA_HOME added alongside the others (test/lib/clean-env.sh's set) after PR #298's review +# found scripts/install.sh's Claude-skills block (`${CLAUDE_CONFIG_DIR:-$HOME/.claude}`) reads it the +# same as skills/install.sh, so an ambient CLAUDE_CONFIG_DIR leaked past the HOME= override here too. +unset CODEX_HOME AGENTS_HOME HERMES_HOME CLAUDE_CONFIG_DIR RIPWIRE_DATA_HOME \ + RIPWIRE_NO_ACTIVATE RIPWIRE_SKIP_CPU_CHECK RIPWIRE_CPUINFO FAKE="$TMP/fake"; mkdir -p "$FAKE" "$TMP/assets/ripwire-0.3.6-macos-arm64/skills/ripwire-router" "$TMP/assets/ripwire-0.3.6-macos-arm64/hooks" printf '#!/bin/sh\necho "ripwire 0.3.6 (Release, Test)"\n' >"$TMP/assets/ripwire-0.3.6-macos-arm64/ripwire" diff --git a/test/routehookcheck.sh b/test/routehookcheck.sh index a29c46300..18511d9f7 100755 --- a/test/routehookcheck.sh +++ b/test/routehookcheck.sh @@ -29,6 +29,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" HOOK="$ROOT/hooks/ripwire-claude-route.sh" NUDGE="$ROOT/hooks/ripwire-nudge.sh" INSTALL="$ROOT/skills/install.sh" From 556fc49884049a2a709825f4698771cbf96ff9ba Mon Sep 17 00:00:00 2001 From: joyful-ii-V-I Date: Sun, 20 Sep 2026 15:53:45 -0400 Subject: [PATCH 08/14] =?UTF-8?q?fix(dead-code):=20drop=20the=20hardcoded?= =?UTF-8?q?=20confidence=3D"high"=20=E2=80=94=20a=20claim=20the=20code=20n?= =?UTF-8?q?ever=20supported?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --dead-code stamped confidence="high" as a literal on every finding, regardless of the symbol's shape (dynamic dispatch, reflection and macro-generated callers are all invisible to the name-based call graph the finding rests on). Nothing about the candidate loop varies that number, so it was decorative, not derived — the same overconfidence shape --adaptive was already known to have. Removed rather than faked: the root no longer carries confidence= at all. evidence= already states the one thing the code actually knows (internal linkage + zero callers in the index), and the full/compact legends, --help text for --dead-code and --safe-delete's dead_code_candidate=, and deadprecisioncheck.sh now agree with that. Co-Authored-By: Claude Sonnet 5 --- src/cli.h | 8 ++++---- src/compactlegend.h | 7 ++++--- src/verbs_navigate.h | 4 ++-- src/verbs_quality.h | 5 +++-- test/deadprecisioncheck.sh | 14 ++++++++++---- test/showcase_capture.py | 2 +- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/cli.h b/src/cli.h index 7596ae8ce..036f14393 100644 --- a/src/cli.h +++ b/src/cli.h @@ -297,7 +297,7 @@ struct Config bool compress = false; // --compress: strip comments + blank runs from --expand/--outline body output (P2-B) bool baseline = false; // --baseline: write .ripwire_arch_baseline sidecar (accept current debt), exit 0 bool baselineUpdate = false; // --baseline-update: merge current violations into baseline (accept new debt), exit 0 - bool deadCode = false; // --dead-code[=DIR]: internal source functions with zero indexed callers (high-confidence candidates) + bool deadCode = false; // --dead-code[=DIR]: internal source functions with zero indexed callers (a name-based graph reading, not a confidence score) std::string_view deadCodeDir; // --dead-code=DIR: restrict scan to DIR — matched as WHOLE path components (a dir, a nested dir, or a filename); a filter naming nothing indexed REFUSES (§P0.3). Leading ./ anchors DIR at the repo root instead of matching that component anywhere (§A10.6) bool qualityBaseline = false; // --quality-baseline: snapshot ccx/clones/dead to .ripwire_quality_baseline bool allowDirty = false; // --allow-dirty: let --quality-baseline pin on a tree that DIFFERS from HEAD (H11) — the sidecar is @@ -327,7 +327,7 @@ struct Config std::string_view safeDeleteSym; // --safe-delete=SYM: "can I delete this?" composed from signals the tool already // computes — 1-hop callers, the transitive --impact blast radius, every --uses // read/write/import/call/extends site, how much of the radius the tested= lens - // covers, and --dead-code's own high-confidence shape at defs=1. FACTS only: + // covers, and --dead-code's own zero-caller/internal-linkage shape at defs=1. FACTS only: // risk= names what was found (none-found/uses-exist/untested-radius), never a // go/no-go verdict. file:name disambiguates like --around/--lego. std::string_view sliceSpec; // --slice=SYM[:VAR] (lane/paper-slice): NAME-BASED intra-procedural def-use @@ -1609,7 +1609,7 @@ inline constexpr char kHelpHead[] = " An @FILE:LINE seed rebinds to the innermost enclosing definition (sym= names it) and\n" " analyses exactly that definition's file\n" " --dead-code[=DIR] list internal functions with no caller anywhere in the indexed tree\n" - " high-confidence internal source functions with no caller in the indexed tree; =DIR scopes to whole path components (dir or filename) and REFUSES a filter that names nothing indexed.\n" + " internal source functions with no caller found in the indexed tree — a name-based graph reading, not a confidence score (dynamic dispatch, reflection and macro-generated callers are invisible to it); =DIR scopes to whole path components (dir or filename) and REFUSES a filter that names nothing indexed.\n" " A symbol whose definition is produced by a SELF-REGISTERING test/benchmark macro is never reported: doctest TEST_CASE/\n" " TEST_CASE_FIXTURE/SCENARIO, gtest TEST/TEST_F/TEST_P, Catch2, Google Benchmark — a static initializer registers them, so a\n" " name-based call graph cannot see the caller and every one of them would be a false positive. Extend the list for your own\n" @@ -1801,7 +1801,7 @@ inline constexpr char kHelpHead[] = " already-resolved SYM: 1-hop callers=, the transitive --impact blast radius (impact_reaches=),\n" " every --uses read/write/import/call/extends site (uses=), how much of the blast radius the\n" " tested= lens covers (tested_self=/radius_tested=/radius_untested=), and --dead-code's own\n" - " high-confidence shape at defs=1 (dead_code_candidate=). ambiguous_callers= names callers\n" + " zero-caller/internal-linkage shape at defs=1 (dead_code_candidate=). ambiguous_callers= names callers\n" " whose own calls include an ambiguously-resolved one (g.ambOut) — a caveat, not a count of\n" " proven-wrong edges. FACTS only: risk= names what was found — none-found (zero callers AND\n" " zero uses), untested-radius (a radius exists and none of it is test-covered), or\n" diff --git a/src/compactlegend.h b/src/compactlegend.h index bc83ac5be..78bc0c8c1 100644 --- a/src/compactlegend.h +++ b/src/compactlegend.h @@ -138,7 +138,7 @@ inline constexpr CompactLegendSpec kCompactLegendSpecs[] = { "hotspots", "hotspots", "maintenance pain = churn x ccx over window=: ; unranked_*= no churn/complexity" }, { "clones", "clones", "similar normalized-token bodies: of ; dup_loc=/dup_pct=" }, { "deps", "deps", "file-to-file include/import view, heaviest cone first: , , , " }, - { "dead-code", "dead-code", "high-confidence dead functions (internal linkage, no caller in the index): ; filter= path component" }, + { "dead-code", "dead-code", "internal-linkage functions with no caller found in the index (not a confidence score): ; filter= path component" }, { "lint", "lint", "AST-only checks, facts not gates: of " }, { "lintcatalog", "lint-catalog", "the built-in lint rule registry: " }, { "external-surface", "external-surface", "names used but never defined in the index: " }, @@ -789,8 +789,9 @@ inline constexpr CompactCompletenessTerm kCompactAttributeReadings[] = { "changed", "changed=: the files/symbols argument as given", false, "affected", MapHeaderRead::No, {}, "affected" }, // connect: src/mcpverbs.h packConnect { "terminals", "terminals=/groups=/edges=: task symbols resolved, connected groups (g), e edges printed", false, "connect", MapHeaderRead::No, {}, "connect" }, - // dead-code: src/verbs_quality.h - { "confidence", "confidence=high count=: every row met the evidence= rule; count= the rows, a floor", false, "dead-code", MapHeaderRead::No, {}, "dead-code" }, + // dead-code: src/verbs_quality.h — T13/fix1: confidence="high" removed (a claim the code did not + // support); count= still needs its own reading now that the confidence row is gone. + { "count", "count=N: candidates meeting evidence= (a floor)", false, "dead-code", MapHeaderRead::No, {}, "dead-code" }, // doc-drift: src/docdrift.h { "drift", "drift=/dated=: anchors that no longer hold / anchors skipped as dated (unverifiable by date)", false, "doc-drift", MapHeaderRead::No, {}, "doc-drift" }, // edit-check: src/editcheck.h diff --git a/src/verbs_navigate.h b/src/verbs_navigate.h index 95d86fadc..b63b8984f 100644 --- a/src/verbs_navigate.h +++ b/src/verbs_navigate.h @@ -757,8 +757,8 @@ inline void emitSafeDeleteLegend( std::size_t defCount, std::size_t unprovenDefs "radius_tested= plus radius_untested= partition impact_reaches= by that same lens — radius_untested= equal " "to impact_reaches= means NOTHING downstream is covered by an indexed test, the strongest signal here. " "dead_code_candidate= is 1 ONLY when this selector resolves to exactly ONE definition and it is the " - "dead-code verb's own high-confidence shape (a source free function, non-header, internal/static linkage, " - "zero direct callers); a 0 never means \"in use\", only that this narrow detector's preconditions do not " + "dead-code verb's own zero-caller/internal-linkage shape (a source free function, non-header, internal/static " + "linkage, zero direct callers); a 0 never means \"in use\", only that this narrow detector's preconditions do not " "hold here — run the dead-code verb for the full-corpus scan. ambiguous_callers= counts callers whose OWN " "outgoing calls include at least one that resolved to more than one candidate definition (g.ambOut, the " "same counter a ranked row's amb= reads). {}{}risk= NAMES what was found, never a go/no-go verdict, and " diff --git a/src/verbs_quality.h b/src/verbs_quality.h index 7469b6a7c..edd6e1206 100644 --- a/src/verbs_quality.h +++ b/src/verbs_quality.h @@ -1933,7 +1933,8 @@ std::optional runQualityViews( const MainDispatch& d ) return sa.name < sb.name; } ); - rw::emitTo( stdout, ""; + "the guard (if/loop) deciding whether a def executes is never a row. " + "flow_redundant=\"1\" (unseeded both=): adds no line beyond the flat inventory; seed --at= for real gain. -->"; } } // H1: the residue clause, in BOTH dialects and as its own comment — opened ` +646 gate scripts, five contracts no unit test can hold, and the house rule: write the gate before the code it measures -`test/regression.sh` names **645 gate scripts** and is the authoritative list; +`test/regression.sh` names **646 gate scripts** and is the authoritative list; `python3 test/pargates.py . ./build/ripwire -j 6` runs the same set in parallel. On top of them sit the contracts that do not fit a unit test: two runs byte-identical, warm output identical to cold, output that pipes clean through `xmllint --noout`, a sanitizer build with `-fno-sanitize-recover=all`, and a diff --git a/docs/EVALS.md b/docs/EVALS.md index 5f5d7d878..33d6e1ff0 100644 --- a/docs/EVALS.md +++ b/docs/EVALS.md @@ -21,7 +21,7 @@ section, and it is not an afterthought. | **Co-change / known-item evals** | `--eval`, `--eval-retrieval` (see `bench/ANSWERQUALITY.md`) | Whether the tool surfaces the other files a real historical commit touched; and known-item retrieval across four rankers. | | **Ensemble calibration harness** | `bench/ensemblecal/` | Whether `--ensemble`'s four evidence families are actually orthogonal, how often each fires, how stable each is across commits — and the preset ladder derived from that (§9). | | **Differential argv harness** | `test/argvdiffcheck.sh` | That a refactor changed *nothing observable*: two binaries, every argv vector, stdout + stderr + exit code byte-identical. | -| **The gate suite** | `test/regression.sh`, `test/pargates.py` | 645 gate scripts plus the determinism, cache-transparency and golden contracts. | +| **The gate suite** | `test/regression.sh`, `test/pargates.py` | 646 gate scripts plus the determinism, cache-transparency and golden contracts. | | **`--quality-delta`** | `src/quality.h` | Ten measured code-quality failure modes, reported only where a change made them worse. | ### The labeling protocol (why the held-out eval is allowed to disagree with the ranker) @@ -5837,7 +5837,7 @@ copy here would be exactly the dialect divergence that gate exists to catch. Com tags, wrap, stable-order defaults), seven individually invoked standalone gates (`g1freshcheck`, `skillscan`, `htmlexport`, `compresscheck`, `handoffcheck`, `releaseinstallcheck`, `taskroutecheck`), and a single loop -naming **645 gate scripts**, all of which exist on disk. +naming **646 gate scripts**, all of which exist on disk. `python3 test/pargates.py . ./build/ripwire -j 6` runs the same scripts in parallel so a full verification fits in one sitting. It does not modify `regression.sh`. @@ -6849,7 +6849,7 @@ Listed because the reason is more useful than the silence. shipped**. See `bench/locbench/anchorhop_calib.json`. The mention anchor's reproducible numbers are the ablations in §4. - **A single round gate-count.** Two in-tree numbers disagree (`test/pargates.py`'s docstring says - ~210; `test/argvdiffcheck.sh` says 200+), while the loop in `test/regression.sh` names 645. The + ~210; `test/argvdiffcheck.sh` says 200+), while the loop in `test/regression.sh` names 646. The loop is the authority; the stale docstrings are a known drift. Since 2026-09-10 the number is not written by hand anywhere: `docs/gatecount_build.py` derives it from the loop and rewrites every published site, `test/gatecountcheck.sh` fails if any of them drifts, and `test/manifestcheck.sh` diff --git a/present/deck5_ripwire_build.js b/present/deck5_ripwire_build.js index cd0d456fc..c82f54b26 100644 --- a/present/deck5_ripwire_build.js +++ b/present/deck5_ripwire_build.js @@ -1123,7 +1123,7 @@ function storyCards(s, { kick, head, stories, footText }){ kicker(s, "// how it stays true", AMBER); title(s, "Proven, not promised"); const cards = [ - ["645 gate scripts", "the suite runs on every push — plus determinism, cache-transparency and golden contracts; the gate count itself is gated against the runner's own loop"], // gatecount + ["646 gate scripts", "the suite runs on every push — plus determinism, cache-transparency and golden contracts; the gate count itself is gated against the runner's own loop"], // gatecount ["byte-identical, always", "two runs over the same tree produce the same bytes; warm equals cold. Enforced in CI, twice — Release AND a plain flavour, because NDEBUG once blinded a whole class of checks"], ["differential refactoring", "a refactor must prove it changed nothing observable: two binaries, hundreds of argv vectors, stdout + stderr + exit codes byte-identical"], ["held-out labels, authored blind", "eval labels were written by reading source before the ranker ever ran on them — so the eval is allowed to say the ranker is wrong. It has."], @@ -1147,7 +1147,7 @@ function storyCards(s, { kick, head, stories, footText }){ title(s, "Claims you can trust, because we publish what failed", { size: 32 }); card(s, MX, 1.72, 3.86, 1.72); - stat(s, "645", "gate scripts named by test/regression.sh — and the COUNT itself is gated against the runner's own loop, so it cannot go stale quietly", // gatecount + stat(s, "646", "gate scripts named by test/regression.sh — and the COUNT itself is gated against the runner's own loop, so it cannot go stale quietly", // gatecount MX+0.15, 1.86, 3.56, CYAN, { bsize: 42, bh: 0.66, lsize: 9.5 }); card(s, 4.68, 1.72, 3.86, 1.72, CARD2); stat(s, "8", "registered NEGATIVES — changes built, gated green, measured against a band written before the code, and reverted rather than tuned", @@ -1397,7 +1397,7 @@ function storyCards(s, { kick, head, stories, footText }){ ["183 long flags · 34 slides", "bash test/deckclaimcheck.sh"], ["every --flag named here exists", "bash test/deckcheck.sh"], ["74.7% fewer element bytes", "bash test/showcasecapturecheck.sh"], - ["645 gate scripts", "bash test/manifestcheck.sh"], // gatecount + ["646 gate scripts", "bash test/manifestcheck.sh"], // gatecount ["49 repos · 71 papers · 237 surveyed","bash test/readmedriftcheck.sh"], ["the ten moments, any row", "ripwire . --callers=SYM | wc -c"], ["the head-to-head table", "bench/headtohead/r4-2026-08-06/"], diff --git a/test/a9disclosurecheck.sh b/test/a9disclosurecheck.sh index aa4796c9f..a650d69a5 100755 --- a/test/a9disclosurecheck.sh +++ b/test/a9disclosurecheck.sh @@ -27,6 +27,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/ackonlycheck.sh b/test/ackonlycheck.sh index 739dbaab7..7ed8fe796 100755 --- a/test/ackonlycheck.sh +++ b/test/ackonlycheck.sh @@ -11,6 +11,7 @@ # The gate runs on a synthetic repo so it never depends on ripwire's own current debt. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/agentloopclaudecheck.sh b/test/agentloopclaudecheck.sh index 8d4290a59..003eea616 100755 --- a/test/agentloopclaudecheck.sh +++ b/test/agentloopclaudecheck.sh @@ -16,6 +16,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT fail=0 diff --git a/test/atcheck.sh b/test/atcheck.sh index 825541572..29107d942 100755 --- a/test/atcheck.sh +++ b/test/atcheck.sh @@ -49,6 +49,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/baselinedirtycheck.sh b/test/baselinedirtycheck.sh index 4faa896b7..588f9c961 100755 --- a/test/baselinedirtycheck.sh +++ b/test/baselinedirtycheck.sh @@ -39,6 +39,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/binoverridecheck.sh b/test/binoverridecheck.sh index a24d2acc9..88e4429f9 100755 --- a/test/binoverridecheck.sh +++ b/test/binoverridecheck.sh @@ -97,6 +97,7 @@ EXEMPT = { "flagtablecheck.sh": "pure file/doc-table check; no binary invocation", "limitstablecheck.sh": "gates docs/LIMITS.md against the CAP DECLARATIONS in src/, so its subject is the generator and the source text, not the binary — it binds no ripwire binary at all (the file contains neither RIPWIRE_BIN nor $BIN), the same shape as formatgatecheck below", "capsweepcheck.sh": "gates bench/capsweep (a python harness) and the docs/TUNING.md it generates: the arms run the cap patcher against a SYNTHETIC tree, the corpus-freeze assertion against a SYNTHETIC corpus, and `emit --check` against the committed TSV records plus src/. The sweep those records came from does need a binary — a specially PATCHED one built into a scratch dir, never build/ripwire — but the gate never re-runs it, so no ripwire binary is bound here at all (the file contains neither RIPWIRE_BIN nor $BIN, verified by reading it), the same shape as limitstablecheck above", + "gitenvhermeticcheck.sh": "harness-hygiene gate for the GIT_* repository-selection variables: its subjects are test/lib/clean-env.sh and the gate scripts that source it, and the only executable it drives is git itself. It accepts $1 for regression.sh's uniform call shape and never binds it, so a broken ripwire cannot make it green or red -- the file contains neither RIPWIRE_BIN nor $BIN (verified by reading it), so (2b)'s static tell needs no exemption row for it, the same shape as gatecountcheck below", "gatecountcheck.sh": "gates the PUBLISHED GATE COUNT against the absorb loop in test/regression.sh, so its subject is docs/gatecount_build.py and three prose/JS site files — it binds no ripwire binary at all (the file contains neither RIPWIRE_BIN nor $BIN, so (2b)'s static tell needs no exemption row for it), exactly the shape of limitstablecheck above", "formatgatecheck.sh": "runs scripts/formatcheck.sh under a pinned clang-format; the subject is the FORMATTER and the gated file list, so no ripwire binary is bound at all — the file contains neither RIPWIRE_BIN nor $BIN (verified by reading it), which is also why (2b)'s static tell needs no exemption for it", "g1configcheck.sh": "greps CMakeLists.txt for the G1 sanitizer flag derivation; no binary invocation", diff --git a/test/cachefuzzcheck.sh b/test/cachefuzzcheck.sh index 8ab9dc2b7..b01cb606e 100755 --- a/test/cachefuzzcheck.sh +++ b/test/cachefuzzcheck.sh @@ -76,6 +76,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" ASAN_BIN="${RIPWIRE_ASAN_BIN:-$ROOT/asan/ripwire}" diff --git a/test/churndecaycheck.sh b/test/churndecaycheck.sh index 69ce5102c..e2d30588f 100755 --- a/test/churndecaycheck.sh +++ b/test/churndecaycheck.sh @@ -37,6 +37,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/churnjoincheck.sh b/test/churnjoincheck.sh index d13bc79c5..e495c2cba 100755 --- a/test/churnjoincheck.sh +++ b/test/churnjoincheck.sh @@ -45,6 +45,7 @@ # RIPWIRE_BIN=asan/ripwire test/churnjoincheck.sh # env seam set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" # BOTH seams — positional and env [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/clonededupcheck.sh b/test/clonededupcheck.sh index 31f5aa2f0..ba9561a9c 100755 --- a/test/clonededupcheck.sh +++ b/test/clonededupcheck.sh @@ -30,6 +30,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" GOLD="${GOLD_BIN:-$ROOT/build/ripwire}" diff --git a/test/cloneidiomcheck.sh b/test/cloneidiomcheck.sh index 061da12d4..1681eb7fe 100755 --- a/test/cloneidiomcheck.sh +++ b/test/cloneidiomcheck.sh @@ -39,6 +39,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/cloneidiomfix" diff --git a/test/cochangeboostcheck.sh b/test/cochangeboostcheck.sh index 009f55797..48ea76881 100755 --- a/test/cochangeboostcheck.sh +++ b/test/cochangeboostcheck.sh @@ -20,6 +20,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/cochangecliocheck.sh b/test/cochangecliocheck.sh index 6122dba75..7815bdf4c 100755 --- a/test/cochangecliocheck.sh +++ b/test/cochangecliocheck.sh @@ -76,6 +76,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/cochangesurprisecheck.sh b/test/cochangesurprisecheck.sh index 40421991b..e4d2c75c6 100755 --- a/test/cochangesurprisecheck.sh +++ b/test/cochangesurprisecheck.sh @@ -57,6 +57,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/codexdoctorcheck.sh b/test/codexdoctorcheck.sh index 195f0d990..c020f9db7 100755 --- a/test/codexdoctorcheck.sh +++ b/test/codexdoctorcheck.sh @@ -2,6 +2,7 @@ # codexdoctorcheck.sh — isolated active-surface gate for `--doctor --agent=codex`. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" [ -x "$BIN" ] || { echo "no ripwire binary at $BIN — build first"; exit 2; } diff --git a/test/compactlegendcheck.sh b/test/compactlegendcheck.sh index b43c16285..18530fe0a 100755 --- a/test/compactlegendcheck.sh +++ b/test/compactlegendcheck.sh @@ -48,6 +48,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${RIPWIRE_BIN:-$ROOT/build/ripwire}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/fixture" diff --git a/test/cppqualcheck.sh b/test/cppqualcheck.sh index d76ea3f05..b235f4c1f 100755 --- a/test/cppqualcheck.sh +++ b/test/cppqualcheck.sh @@ -46,6 +46,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" # BOTH seams: positional arg and RIPWIRE_BIN= [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # absolute BEFORE we cd away PROBE="$( dirname "$BIN" )/ripwire_probe" diff --git a/test/crashsweepcheck.sh b/test/crashsweepcheck.sh index 17165f3c9..60a5b4626 100755 --- a/test/crashsweepcheck.sh +++ b/test/crashsweepcheck.sh @@ -73,6 +73,7 @@ # Usage: bash test/crashsweepcheck.sh [BIN] RIPWIRE_ASAN_BIN=asan/ripwire bash test/crashsweepcheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" ASAN_BIN="${RIPWIRE_ASAN_BIN:-}" diff --git a/test/crawlescapecheck.sh b/test/crawlescapecheck.sh index 762172064..927d07d7d 100755 --- a/test/crawlescapecheck.sh +++ b/test/crawlescapecheck.sh @@ -39,6 +39,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/decltodefcheck.sh b/test/decltodefcheck.sh index 96018a78b..9aa06ef66 100755 --- a/test/decltodefcheck.sh +++ b/test/decltodefcheck.sh @@ -117,6 +117,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/defaultceilingcheck.sh b/test/defaultceilingcheck.sh index 0db24942c..18de4ebc5 100755 --- a/test/defaultceilingcheck.sh +++ b/test/defaultceilingcheck.sh @@ -26,6 +26,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${RIPWIRE_BIN:-$ROOT/build/ripwire}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/deplangscheck.sh b/test/deplangscheck.sh index 31e6ba09d..bc44fd1b6 100755 --- a/test/deplangscheck.sh +++ b/test/deplangscheck.sh @@ -26,6 +26,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/dispatchordercheck.sh b/test/dispatchordercheck.sh index 82207eef7..6cc0800b5 100755 --- a/test/dispatchordercheck.sh +++ b/test/dispatchordercheck.sh @@ -35,6 +35,7 @@ set -u +. "$( cd "$( dirname "$0" )" && pwd )/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-./build/ripwire}}" # CA4: this gate ignored $1, so a caller passing a binary SRCFIX="${FIX:-test/queryfix}" # positionally silently measured build/ripwire instead (trap #20) fails=0 @@ -61,8 +62,10 @@ fail() { echo " FAIL $1"; fails=$((fails + 1)); } # by this per-run root is left in the shared cache dir. Not --no-cache: that would hide a cache-dependent # difference instead of ruling one out. [ -d "$SRCFIX/src" ] || { echo "dispatchordercheck: no fixture at $SRCFIX"; exit 2; } -unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE # inherited from a hook running the suite, these would aim every git - # and ripwire call below at the caller's repository instead +# The GIT_* clearing this gate used to hand-roll here (GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE — inherited +# from a hook running the suite, they would aim every git and ripwire call below at the caller's +# repository) now lives in test/lib/clean-env.sh, sourced at the top: pagingsweepcheck had independently +# hand-rolled the same list plus GIT_COMMON_DIR, and neither copy had the object-directory names. GATETMP="$( mktemp -d )"; trap 'rm -rf "$GATETMP"' EXIT FIX="$GATETMP/queryfix" if ! ( fixgit(){ GIT_AUTHOR_DATE="$1" GIT_COMMITTER_DATE="$1" git -C "$FIX" -c user.name=ripwire -c user.email=ripwire@example.invalid \ diff --git a/test/dmmcheck.sh b/test/dmmcheck.sh index ed649bdaa..1323333ee 100755 --- a/test/dmmcheck.sh +++ b/test/dmmcheck.sh @@ -69,6 +69,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/doctorcheck.sh b/test/doctorcheck.sh index b36c0b3fb..1d2904bff 100755 --- a/test/doctorcheck.sh +++ b/test/doctorcheck.sh @@ -21,6 +21,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/donelegendcheck.sh b/test/donelegendcheck.sh index b086474ae..6c69f7d38 100755 --- a/test/donelegendcheck.sh +++ b/test/donelegendcheck.sh @@ -36,6 +36,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # make BIN absolute BEFORE we cd away fail=0 diff --git a/test/editcheckanswercheck.sh b/test/editcheckanswercheck.sh index 72a444a45..35a646a81 100755 --- a/test/editcheckanswercheck.sh +++ b/test/editcheckanswercheck.sh @@ -41,6 +41,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/editcheckcheck.sh b/test/editcheckcheck.sh index a06093d0b..f871fb230 100755 --- a/test/editcheckcheck.sh +++ b/test/editcheckcheck.sh @@ -17,6 +17,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" # BOTH seams: `bash test/editcheckcheck.sh asan/ripwire` and RIPWIRE_BIN= [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # make BIN absolute BEFORE we cd away fail=0 diff --git a/test/editchecknotecheck.sh b/test/editchecknotecheck.sh index 46e19d93f..8ac774172 100755 --- a/test/editchecknotecheck.sh +++ b/test/editchecknotecheck.sh @@ -24,6 +24,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # make BIN absolute BEFORE we cd away BASE="${RIPWIRE_BASE_BIN:-}" diff --git a/test/editplanrollbackmsgcheck.sh b/test/editplanrollbackmsgcheck.sh index a9f17489f..a03def6d2 100755 --- a/test/editplanrollbackmsgcheck.sh +++ b/test/editplanrollbackmsgcheck.sh @@ -32,6 +32,7 @@ # Usage: test/editplanrollbackmsgcheck.sh [BIN] set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )" diff --git a/test/editpreviewcheck.sh b/test/editpreviewcheck.sh index 3e6979472..52ea31e9c 100755 --- a/test/editpreviewcheck.sh +++ b/test/editpreviewcheck.sh @@ -49,6 +49,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/editpreviewfix" diff --git a/test/editroundtripcheck.sh b/test/editroundtripcheck.sh index b19c38448..4bc0ca857 100755 --- a/test/editroundtripcheck.sh +++ b/test/editroundtripcheck.sh @@ -30,6 +30,7 @@ # Usage: bash test/editroundtripcheck.sh (RIPWIRE_BIN=… for another binary) set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${RIPWIRE_BIN:-$ROOT/build/ripwire}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/elixirnamearitycheck.sh b/test/elixirnamearitycheck.sh index 685119404..2a0c8d78a 100755 --- a/test/elixirnamearitycheck.sh +++ b/test/elixirnamearitycheck.sh @@ -70,6 +70,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/elixirnamearityfix" diff --git a/test/emittertruthcheck.sh b/test/emittertruthcheck.sh index b91a50ad0..9c6e662ea 100755 --- a/test/emittertruthcheck.sh +++ b/test/emittertruthcheck.sh @@ -37,6 +37,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/emptyvaluerefusecheck.sh b/test/emptyvaluerefusecheck.sh index 16824e943..53b2e3d27 100755 --- a/test/emptyvaluerefusecheck.sh +++ b/test/emptyvaluerefusecheck.sh @@ -24,6 +24,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative binary TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/estchargecheck.sh b/test/estchargecheck.sh index 1ea3f0431..9199b8494 100755 --- a/test/estchargecheck.sh +++ b/test/estchargecheck.sh @@ -28,6 +28,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/evalcheck.sh b/test/evalcheck.sh index 017a6e319..2053d752c 100755 --- a/test/evalcheck.sh +++ b/test/evalcheck.sh @@ -21,6 +21,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/evictioncheck.sh b/test/evictioncheck.sh index 45afa8b4d..da1382dec 100755 --- a/test/evictioncheck.sh +++ b/test/evictioncheck.sh @@ -48,6 +48,7 @@ # Usage: test/evictioncheck.sh | RIPWIRE_BIN=build_r2a1/ripwire test/evictioncheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" . "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" diff --git a/test/extentcheck.sh b/test/extentcheck.sh index da4c0348d..3d10fdb30 100644 --- a/test/extentcheck.sh +++ b/test/extentcheck.sh @@ -68,6 +68,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/floormarkcheck.sh b/test/floormarkcheck.sh index 8c6706f2c..b511c1595 100755 --- a/test/floormarkcheck.sh +++ b/test/floormarkcheck.sh @@ -57,6 +57,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/forlenscheck.sh b/test/forlenscheck.sh index e4506f1e2..7dd58ccce 100755 --- a/test/forlenscheck.sh +++ b/test/forlenscheck.sh @@ -18,6 +18,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/fornotesbudgetcheck.sh b/test/fornotesbudgetcheck.sh index 588d0a38f..54d0fe262 100755 --- a/test/fornotesbudgetcheck.sh +++ b/test/fornotesbudgetcheck.sh @@ -173,6 +173,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/forrankordercheck.sh b/test/forrankordercheck.sh index b9e1c40cb..caf49e060 100755 --- a/test/forrankordercheck.sh +++ b/test/forrankordercheck.sh @@ -34,6 +34,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${RIPWIRE_BIN:-$ROOT/build/ripwire}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/forrootlegendcheck.sh b/test/forrootlegendcheck.sh index abb8dc784..88ecb160e 100755 --- a/test/forrootlegendcheck.sh +++ b/test/forrootlegendcheck.sh @@ -21,6 +21,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/freshclonecheck.sh b/test/freshclonecheck.sh index 44d3813c6..29f73146c 100755 --- a/test/freshclonecheck.sh +++ b/test/freshclonecheck.sh @@ -62,6 +62,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/gateexitcheck.sh b/test/gateexitcheck.sh index a80765eca..116ae44d2 100755 --- a/test/gateexitcheck.sh +++ b/test/gateexitcheck.sh @@ -50,6 +50,7 @@ # Own exit path: the canonical `exit "$fail"`, and this file is swept by its own arm (B) like any other. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" fail=0 ok(){ printf ' PASS %s\n' "$*" || { fail=1; printf ' FAIL could not write the PASS line for: %s\n' "$*"; }; return 0; } no(){ printf ' FAIL %s\n' "$*"; fail=1; } diff --git a/test/gitenvhermeticcheck.sh b/test/gitenvhermeticcheck.sh new file mode 100755 index 000000000..668891f91 --- /dev/null +++ b/test/gitenvhermeticcheck.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +# gitenvhermeticcheck.sh — a gate that builds a throwaway git repository must not let the CALLER's +# environment choose which repository it actually talked to. +# +# WHY THIS FILE EXISTS. `git -C DIR` changes the working DIRECTORY. It does not override the +# ENVIRONMENT, and GIT_DIR / GIT_WORK_TREE / GIT_COMMON_DIR / GIT_INDEX_FILE / GIT_OBJECT_DIRECTORY / +# GIT_ALTERNATE_OBJECT_DIRECTORIES / GIT_PREFIX all outrank it. So +# REPO="$( mktemp -d )"; git -C "$REPO" init -q; …; HEADSHA="$( git -C "$REPO" rev-parse HEAD )" +# hands back a sha from SOMEBODY ELSE'S repository whenever one of those is exported — a git hook +# running the suite, a CI job that set GIT_DIR, `git rebase --exec`, a shell inside `git filter-branch`. +# The gate then passes or fails on data it never selected, which is worse than a red: it is a green that +# measured the wrong tree. `git init` is affected too (with GIT_DIR set it initialises THERE). +# +# It is the #298 story a second time. Two gates had already found this independently and hand-rolled a +# fix at the call site — dispatchordercheck (GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE) and pagingsweepcheck +# (the same three plus GIT_COMMON_DIR) — and NEITHER copy carried the object-directory names. Two +# partial copies and 155 unprotected siblings is exactly the shape that made #298 centralise the +# agent-home variables, so the git names went into the same helper, test/lib/clean-env.sh, rather than +# into a 156th copy. +# +# ARMS +# (A) LIVENESS — the defect is real HERE, on this git, not merely in the documentation. Two throwaway +# repositories with different HEADs; `git -C rev-parse HEAD` is asked once with GIT_DIR +# aimed at the OTHER one. It must answer the OTHER repository's sha. If this git ever stops +# honouring GIT_DIR over -C the gate cannot conclude anything and exits 2 rather than pass +# vacuously — (B) and (C) would both be green for the wrong reason. +# (B) THE FIX — the identical call, in a shell that sourced test/lib/clean-env.sh first, must answer +# the FIXTURE's own sha. (A) and (B) differ in exactly one thing: the source line. +# (C) THE LIST — every name (A) can be run against must actually appear in the helper's unset lines. +# The list is derived from the helper and compared with the pinned set below, so adding a name to +# one without the other is a red, and the agent-home family #298 introduced is pinned the same way +# (this gate is the only place both families are written down together). +# (D) THE SWEEP — every test/*.sh that initialises a git repository must source the helper. The +# population is derived, never pinned as a number: a gate that starts building a repo tomorrow is +# in it automatically. A CONTROL copies one real gate, strips its source line, and requires the +# same classifier to flag the copy — without it (D) would pass on a tree where nothing is +# detectable. +# +# Usage: bash test/gitenvhermeticcheck.sh [ripwire-binary] (the binary is accepted and unused: this is +# a harness-hygiene gate, and every gate in regression.sh is called with it.) + +set -u +ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" +HELPER="$ROOT/test/lib/clean-env.sh" +TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT +fail=0 + +ok(){ printf ' PASS %s\n' "$*" || { fail=1; printf ' FAIL could not write the PASS line for: %s\n' "$*"; }; return 0; } +no(){ printf ' FAIL %s\n' "$*"; fail=1; } + +[ -f "$HELPER" ] || { echo "gitenvhermeticcheck: no helper at $HELPER"; exit 2; } +command -v git >/dev/null 2>&1 || { echo "gitenvhermeticcheck: git missing (gate cannot run)"; exit 2; } + +echo "gitenvhermeticcheck: HELPER=$HELPER" + +mkrepo(){ # $1 = dir, $2 = file content; echoes the resulting HEAD sha + mkdir -p "$1" + git -C "$1" init -q + git -C "$1" config user.email gate@example.invalid + git -C "$1" config user.name gate + printf '%s\n' "$2" > "$1/f.txt" + git -C "$1" add -A + git -C "$1" commit -qm "$2" + git -C "$1" rev-parse HEAD +} + +# ═══════════════════════════════════════════════════════════════════════════ +echo +echo "=== (A) LIVENESS: git -C is overridden by GIT_DIR on this git ===" +# ═══════════════════════════════════════════════════════════════════════════ +OTHERSHA="$( mkrepo "$TMP/other" theirs )" +FIXSHA="$( mkrepo "$TMP/fix" ours )" +[ -n "$OTHERSHA" ] && [ -n "$FIXSHA" ] && [ "$OTHERSHA" != "$FIXSHA" ] \ + || { echo "gitenvhermeticcheck: could not build two distinct throwaway repos — cannot conclude"; exit 2; } + +LEAKED="$( GIT_DIR="$TMP/other/.git" git -C "$TMP/fix" rev-parse HEAD 2>/dev/null )" +if [ "$LEAKED" = "$OTHERSHA" ]; then + ok "(A) with GIT_DIR set, \`git -C rev-parse HEAD\` answers the OTHER repo (${OTHERSHA%%??????????????????????????????}…) — the defect is live" +elif [ "$LEAKED" = "$FIXSHA" ]; then + echo "gitenvhermeticcheck: this git ignores GIT_DIR in favour of -C, so (B) and (D) would be green" + echo " for the wrong reason. Cannot conclude — exiting 2 rather than passing." + exit 2 +else + echo "gitenvhermeticcheck: the GIT_DIR probe answered neither repo ('$LEAKED') — cannot conclude" + exit 2 +fi + +# ═══════════════════════════════════════════════════════════════════════════ +echo +echo "=== (B) THE FIX: the same call, after sourcing the helper, answers the fixture ===" +# ═══════════════════════════════════════════════════════════════════════════ +# Run in a CHILD shell so the export is real and the source line is the only difference from (A). +FIXED="$( GIT_DIR="$TMP/other/.git" sh -c '. "$1" ; git -C "$2" rev-parse HEAD' sh "$HELPER" "$TMP/fix" 2>/dev/null )" +[ "$FIXED" = "$FIXSHA" ] \ + && ok "(B) after sourcing test/lib/clean-env.sh the same call answers the FIXTURE's own sha" \ + || no "(B) the helper did not restore the fixture's sha: got '$FIXED', want '$FIXSHA'" + +# Every git-selecting name, not just GIT_DIR: each must be neutralised on its own. GIT_PREFIX and the +# object directories cannot flip a rev-parse, so they are asserted to be CLEARED rather than to change an +# answer — a weaker claim, stated as the weaker claim rather than dressed up as a behavioural one. +for V in GIT_DIR GIT_WORK_TREE GIT_COMMON_DIR GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_PREFIX; do + SEEN="$( env "$V=/nonexistent/leak" sh -c '. "$1" ; eval "printf %s \"\${$2-}\""' sh "$HELPER" "$V" 2>/dev/null )" + [ "$SEEN" = "" ] \ + && ok "(B) $V is cleared by the helper" \ + || no "(B) $V survived the helper as '$SEEN'" +done + +# ═══════════════════════════════════════════════════════════════════════════ +echo +echo "=== (C) THE LIST: the helper clears exactly the pinned names ===" +# ═══════════════════════════════════════════════════════════════════════════ +PINNED="AGENTS_HOME CLAUDE_CONFIG_DIR CODEX_HOME GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_DIR GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_PREFIX GIT_WORK_TREE HERMES_HOME RIPWIRE_DATA_HOME" +DERIVED="$( grep -E '^unset ' "$HELPER" | sed 's/^unset //' | tr ' ' '\n' | grep -v '^$' | LC_ALL=C sort | tr '\n' ' ' | sed 's/ *$//' )" +[ "$DERIVED" = "$PINNED" ] \ + && ok "(C) the helper's unset lines name exactly the pinned set ($( printf '%s' "$PINNED" | wc -w | tr -d ' ' ) variables, both families)" \ + || no "(C) the helper's list drifted from the pin. derived={$DERIVED} pinned={$PINNED}" + +# ═══════════════════════════════════════════════════════════════════════════ +echo +echo "=== (D) THE SWEEP: every gate that builds a git repo sources the helper ===" +# ═══════════════════════════════════════════════════════════════════════════ +# Population derived, never pinned: whatever initialises a repo today is in scope today. +sources_helper(){ grep -qE '^[[:space:]]*\.[[:space:]]+.*lib/clean-env\.sh' "$1"; } +builds_repo(){ grep -qE 'git (-C [^ ]+ )?init' "$1"; } + +pop=0; bad="" +for g in "$ROOT"/test/*.sh; do + builds_repo "$g" || continue + pop=$(( pop + 1 )) + sources_helper "$g" || bad="$bad $( basename "$g" )" +done +[ "$pop" -gt 0 ] \ + || { echo "gitenvhermeticcheck: the sweep found ZERO gates building a repo — the classifier broke"; exit 2; } +[ -z "$bad" ] \ + && ok "(D) all $pop gate(s) that initialise a git repository source test/lib/clean-env.sh" \ + || no "(D) $pop gate(s) build a repo;$bad do not source test/lib/clean-env.sh" + +# CONTROL: strip the source line from a copy of a real member and require the classifier to flag it. +CTRL_SRC="$ROOT/test/qsnapproducercheck.sh" +if [ -f "$CTRL_SRC" ]; then + grep -vE '^[[:space:]]*\.[[:space:]]+.*lib/clean-env\.sh' "$CTRL_SRC" > "$TMP/ctrl.sh" + if builds_repo "$TMP/ctrl.sh" && ! sources_helper "$TMP/ctrl.sh"; then + ok "(D) control: a copy of qsnapproducercheck.sh with its source line stripped IS flagged — the sweep discriminates" + else + no "(D) control: the stripped copy was not flagged; the sweep cannot detect the defect it reports" + fi +else + no "(D) control source test/qsnapproducercheck.sh is missing — the control cannot run" +fi + +echo +[ "$fail" = 0 ] && echo "ALL PASS" || echo "FAILURES ABOVE" +exit $fail diff --git a/test/gitignorecheck.sh b/test/gitignorecheck.sh index 0bd214b5a..da2818dc8 100755 --- a/test/gitignorecheck.sh +++ b/test/gitignorecheck.sh @@ -33,6 +33,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/gitquotepathcheck.sh b/test/gitquotepathcheck.sh index c8f23dbd8..e2fe8a466 100755 --- a/test/gitquotepathcheck.sh +++ b/test/gitquotepathcheck.sh @@ -17,6 +17,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/grepignorecheck.sh b/test/grepignorecheck.sh index af4b3b6ef..fdce597de 100755 --- a/test/grepignorecheck.sh +++ b/test/grepignorecheck.sh @@ -49,6 +49,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/handoffcheck.sh b/test/handoffcheck.sh index 74f4e476d..eafe5f1e8 100755 --- a/test/handoffcheck.sh +++ b/test/handoffcheck.sh @@ -26,6 +26,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # make BIN absolute BEFORE we cd away fail=0 diff --git a/test/headbinstagecheck.sh b/test/headbinstagecheck.sh index b5e1baa87..431c59301 100644 --- a/test/headbinstagecheck.sh +++ b/test/headbinstagecheck.sh @@ -36,6 +36,7 @@ # Usage: bash test/headbinstagecheck.sh | RIPWIRE_BIN=asan/ripwire bash test/headbinstagecheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" LIB="$ROOT/test/lib/headbinlib.sh" diff --git a/test/headsnapcachecheck.sh b/test/headsnapcachecheck.sh index cb40b9b82..36c89cbd7 100755 --- a/test/headsnapcachecheck.sh +++ b/test/headsnapcachecheck.sh @@ -28,6 +28,7 @@ # Usage: test/headsnapcachecheck.sh | RIPWIRE_BIN=build_w2e/ripwire test/headsnapcachecheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" . "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" diff --git a/test/historyoraclecheck.sh b/test/historyoraclecheck.sh index f919a22a5..7300efc39 100755 --- a/test/historyoraclecheck.sh +++ b/test/historyoraclecheck.sh @@ -24,6 +24,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/htmlcolorcheck.sh b/test/htmlcolorcheck.sh index 4c8963446..67a1d90cc 100755 --- a/test/htmlcolorcheck.sh +++ b/test/htmlcolorcheck.sh @@ -37,6 +37,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" CORPUS="$ROOT/test/fixture" diff --git a/test/htmlhostcheck.sh b/test/htmlhostcheck.sh index a66c72e70..8a8106d3d 100755 --- a/test/htmlhostcheck.sh +++ b/test/htmlhostcheck.sh @@ -48,6 +48,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/identitycheck.sh b/test/identitycheck.sh index f6ea79a63..e1eee23cd 100755 --- a/test/identitycheck.sh +++ b/test/identitycheck.sh @@ -26,6 +26,7 @@ # Runs on a synthetic git repo so it never depends on ripwire's own current debt or ack ledger. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/indexoutcheck.sh b/test/indexoutcheck.sh index c36c47ee6..057b08f9a 100755 --- a/test/indexoutcheck.sh +++ b/test/indexoutcheck.sh @@ -27,6 +27,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/jsoncheck.sh b/test/jsoncheck.sh index 407cf35de..cbfaea3e9 100755 --- a/test/jsoncheck.sh +++ b/test/jsoncheck.sh @@ -27,6 +27,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/jsverbscheck.sh b/test/jsverbscheck.sh index cad6230be..d893a4c82 100755 --- a/test/jsverbscheck.sh +++ b/test/jsverbscheck.sh @@ -18,6 +18,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="test/jslangfix" # relative — cd "$ROOT" below, so emitted p="..." matches this diff --git a/test/landingcheck.sh b/test/landingcheck.sh index d825064bf..7e73f2148 100755 --- a/test/landingcheck.sh +++ b/test/landingcheck.sh @@ -18,6 +18,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/langcensuscheck.sh b/test/langcensuscheck.sh index 9fa5370ec..546c38a46 100755 --- a/test/langcensuscheck.sh +++ b/test/langcensuscheck.sh @@ -19,6 +19,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/legendrefcheck.sh b/test/legendrefcheck.sh index 864ff2007..c9a5dd9e9 100755 --- a/test/legendrefcheck.sh +++ b/test/legendrefcheck.sh @@ -38,6 +38,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" ROSTER_BIN="${LEGENDREF_ROSTER_BIN:-$BIN}" diff --git a/test/lib/clean-env.sh b/test/lib/clean-env.sh index a5e14e354..dfba35488 100644 --- a/test/lib/clean-env.sh +++ b/test/lib/clean-env.sh @@ -1,6 +1,26 @@ -# clean-env.sh — the agent-home-relocating env vars a gate must clear before it varies HOME= per -# invocation: CODEX_HOME/AGENTS_HOME/HERMES_HOME/CLAUDE_CONFIG_DIR/RIPWIRE_DATA_HOME override the -# default derived from HOME, so a gate that only sets HOME= is not sandboxed on a machine where any of -# these is already exported ambiently. SOURCED, not run. Source this FIRST, then set whatever homes -# the gate actually needs. +# clean-env.sh — the ambient environment a gate must not inherit. SOURCED, not run. Source this FIRST, +# then set whatever homes, repos and variables the gate actually needs. +# +# TWO families, found the same way and fixed in the same place. +# +# (1) AGENT HOMES (#298, @s0undt3ch). CODEX_HOME/AGENTS_HOME/HERMES_HOME/CLAUDE_CONFIG_DIR/ +# RIPWIRE_DATA_HOME override the default an agent's tools derive from HOME, so a gate that only sets +# HOME= per invocation is not sandboxed on a machine where any of these is already exported. +# +# (2) GIT REPOSITORY SELECTION (CodeRabbit on the train-13 branch). `git -C DIR` changes the working +# DIRECTORY; it does NOT override the ENVIRONMENT, and every variable below outranks it. So a gate +# that builds a throwaway repo and asks it a question — `git -C "$REPO" rev-parse HEAD`, +# `git -C "$REPO" log` — gets an answer from SOMEBODY ELSE'S repository when any of these is set, and +# then passes or fails on data it did not select. `git init` is affected too: with GIT_DIR set it +# initialises there. The exposure is ordinary, not exotic — a git hook running the suite, a CI job +# that exported GIT_DIR, `git rebase --exec`, a shell inside `git filter-branch`. +# +# GIT_PREFIX is in the list for a different reason than the rest: git sets it for its own aliases and +# subcommands, and a relative path inside a gate then resolves against it. +# +# Both families were first found as partial hand-rolled copies at the call sites — two for the git family +# (dispatchordercheck, pagingsweepcheck), each missing names the other had — which is why the clearing +# lives here and not there. test/gitenvhermeticcheck.sh pins the list and sweeps the tree for a gate that +# builds a repo without sourcing this file. unset CODEX_HOME AGENTS_HOME HERMES_HOME CLAUDE_CONFIG_DIR RIPWIRE_DATA_HOME +unset GIT_DIR GIT_WORK_TREE GIT_COMMON_DIR GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_PREFIX diff --git a/test/lintpayloadcapcheck.sh b/test/lintpayloadcapcheck.sh index d9a6343fb..84a69659c 100755 --- a/test/lintpayloadcapcheck.sh +++ b/test/lintpayloadcapcheck.sh @@ -39,6 +39,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/macroreparsecheck.sh b/test/macroreparsecheck.sh index 0c589b7f7..683885b7a 100644 --- a/test/macroreparsecheck.sh +++ b/test/macroreparsecheck.sh @@ -47,6 +47,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/mapdiffcheck.sh b/test/mapdiffcheck.sh index 8774bebd6..663c4785a 100755 --- a/test/mapdiffcheck.sh +++ b/test/mapdiffcheck.sh @@ -22,6 +22,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/mcpattrparitycheck.sh b/test/mcpattrparitycheck.sh index f82968d6e..5df6aab37 100755 --- a/test/mcpattrparitycheck.sh +++ b/test/mcpattrparitycheck.sh @@ -39,6 +39,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" [ -x "$BIN" ] || { echo "no ripwire binary at $BIN — build first (cmake --build build -j)"; exit 2; } diff --git a/test/mcpclidiffcheck.sh b/test/mcpclidiffcheck.sh index bf253c38e..f1c0b7b86 100755 --- a/test/mcpclidiffcheck.sh +++ b/test/mcpclidiffcheck.sh @@ -38,6 +38,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/mcpeditmodecheck.sh b/test/mcpeditmodecheck.sh index 4d3c0d1d7..e4f815636 100755 --- a/test/mcpeditmodecheck.sh +++ b/test/mcpeditmodecheck.sh @@ -18,6 +18,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" . "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" diff --git a/test/mcpflagshipcheck.sh b/test/mcpflagshipcheck.sh index 736fe9273..d24cd7f6f 100755 --- a/test/mcpflagshipcheck.sh +++ b/test/mcpflagshipcheck.sh @@ -26,6 +26,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/mcpframehonestycheck.sh b/test/mcpframehonestycheck.sh index abb0354d5..5c1d52764 100755 --- a/test/mcpframehonestycheck.sh +++ b/test/mcpframehonestycheck.sh @@ -45,6 +45,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/fixture" diff --git a/test/mcpincrementalcheck.sh b/test/mcpincrementalcheck.sh index 9b6559db3..239666aa2 100755 --- a/test/mcpincrementalcheck.sh +++ b/test/mcpincrementalcheck.sh @@ -41,6 +41,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN FIX="$ROOT/test/fixture" diff --git a/test/mcpremotecheck.sh b/test/mcpremotecheck.sh index d790c3af4..98b14bb1c 100755 --- a/test/mcpremotecheck.sh +++ b/test/mcpremotecheck.sh @@ -27,6 +27,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/fixture" diff --git a/test/mcpstalecheck.sh b/test/mcpstalecheck.sh index dd069748c..eeb9fe244 100755 --- a/test/mcpstalecheck.sh +++ b/test/mcpstalecheck.sh @@ -37,6 +37,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN FIX="$ROOT/test/fixture" diff --git a/test/mcptoolprunecheck.sh b/test/mcptoolprunecheck.sh index f645bd5bb..d4910d0db 100755 --- a/test/mcptoolprunecheck.sh +++ b/test/mcptoolprunecheck.sh @@ -47,6 +47,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'cleanup' EXIT diff --git a/test/mcpverbscheck.sh b/test/mcpverbscheck.sh index 553e6a622..f31aadb22 100755 --- a/test/mcpverbscheck.sh +++ b/test/mcpverbscheck.sh @@ -35,6 +35,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" CORPUS="$ROOT/test/zoomfix" diff --git a/test/mentioncapcheck.sh b/test/mentioncapcheck.sh index 4cd886d97..a3329acac 100755 --- a/test/mentioncapcheck.sh +++ b/test/mentioncapcheck.sh @@ -52,6 +52,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/mergechurncheck.sh b/test/mergechurncheck.sh index 225a35a62..940a3f62c 100755 --- a/test/mergechurncheck.sh +++ b/test/mergechurncheck.sh @@ -45,6 +45,7 @@ # RIPWIRE_BIN=asan/ripwire test/mergechurncheck.sh # env seam set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" # BOTH seams — positional and env [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/mergescoutcheck.sh b/test/mergescoutcheck.sh index a99f17193..45a5b591f 100755 --- a/test/mergescoutcheck.sh +++ b/test/mergescoutcheck.sh @@ -31,6 +31,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/mergescoutlonglinecheck.sh b/test/mergescoutlonglinecheck.sh index 2e0631f4d..4722eb753 100755 --- a/test/mergescoutlonglinecheck.sh +++ b/test/mergescoutlonglinecheck.sh @@ -30,6 +30,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/multirootcheck.sh b/test/multirootcheck.sh index c900380fe..c0b66b580 100755 --- a/test/multirootcheck.sh +++ b/test/multirootcheck.sh @@ -32,6 +32,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" # BOTH seams. This gate took RIPWIRE_BIN only, so `bash test/multirootcheck.sh /ripwire` SILENTLY ran # against build/ripwire — a red-first run against a pre-fix binary passed for the wrong reason (trap #20). BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" diff --git a/test/multiswecheck.sh b/test/multiswecheck.sh index 33ae4a57e..a6ea04f9c 100755 --- a/test/multiswecheck.sh +++ b/test/multiswecheck.sh @@ -18,6 +18,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/namingcalibrationcheck.sh b/test/namingcalibrationcheck.sh index 5d5adfa94..d3f33e073 100755 --- a/test/namingcalibrationcheck.sh +++ b/test/namingcalibrationcheck.sh @@ -37,6 +37,7 @@ # "insufficient", never a pass and never a fail. One fire is not a precision. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/nestedimportcheck.sh b/test/nestedimportcheck.sh index f2718f6b8..c3d4c13a7 100755 --- a/test/nestedimportcheck.sh +++ b/test/nestedimportcheck.sh @@ -70,6 +70,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN FIX="$ROOT/test/nestedimportfix" diff --git a/test/nextverbcheck.sh b/test/nextverbcheck.sh index f74123467..6a693a64e 100755 --- a/test/nextverbcheck.sh +++ b/test/nextverbcheck.sh @@ -20,6 +20,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${RIPWIRE_BIN:-$ROOT/build/ripwire}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/fixture" diff --git a/test/notecanoncheck.sh b/test/notecanoncheck.sh index aacedb615..f492aa9f1 100755 --- a/test/notecanoncheck.sh +++ b/test/notecanoncheck.sh @@ -47,6 +47,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/notescheck.sh b/test/notescheck.sh index a4edf5abb..1e0f5ca8a 100755 --- a/test/notescheck.sh +++ b/test/notescheck.sh @@ -18,6 +18,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" # Both seams: a positional argument wins, then RIPWIRE_BIN, then the dev build. The positional form is what # a red-first run uses (`bash test/notescheck.sh /base_w3`) and this gate only had the env one. BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" diff --git a/test/ownerscheck.sh b/test/ownerscheck.sh index 887e8241c..3effe3f47 100755 --- a/test/ownerscheck.sh +++ b/test/ownerscheck.sh @@ -14,6 +14,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" # BOTH seams: positional and RIPWIRE_BIN [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/packcallersharecheck.sh b/test/packcallersharecheck.sh index a1c29abd8..88b25f70e 100755 --- a/test/packcallersharecheck.sh +++ b/test/packcallersharecheck.sh @@ -20,6 +20,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # make BIN absolute BEFORE we cd away fail=0 diff --git a/test/packtaskcheck.sh b/test/packtaskcheck.sh index c499a7a27..34eb49dc1 100755 --- a/test/packtaskcheck.sh +++ b/test/packtaskcheck.sh @@ -24,6 +24,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # make BIN absolute BEFORE we cd away fail=0 diff --git a/test/packtaskmonotoncheck.sh b/test/packtaskmonotoncheck.sh index e73899d3e..b244ad1ce 100755 --- a/test/packtaskmonotoncheck.sh +++ b/test/packtaskmonotoncheck.sh @@ -24,6 +24,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # make BIN absolute BEFORE we cd away fail=0 diff --git a/test/packtaskquotacheck.sh b/test/packtaskquotacheck.sh index 477f10c1e..f879af596 100755 --- a/test/packtaskquotacheck.sh +++ b/test/packtaskquotacheck.sh @@ -37,6 +37,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/pagingsweepcheck.sh b/test/pagingsweepcheck.sh index 194bfe2ba..3c28f144e 100755 --- a/test/pagingsweepcheck.sh +++ b/test/pagingsweepcheck.sh @@ -95,6 +95,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" PREBIN="${RIPWIRE_PREBIN:-}" @@ -104,10 +105,12 @@ ok(){ printf ' PASS %s\n' "$*" || { fail=1; printf ' FAIL could not write th no(){ printf ' FAIL %s\n' "$*"; fail=1; } [ -x "$BIN" ] || { echo "no ripwire binary at $BIN — build first"; exit 2; } -# Inherited from a hook running the suite, these would aim every git and ripwire call below at the caller's -# repository (GIT_COMMON_DIR too: it redirects refs even when GIT_DIR is unset): the paging fixture's own init/commit/branch calls, and the ref scans of the --whereis and -# --stray-content rows, which must read ONLY the refs that fixture holds (see mkPagingFixture). -unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_COMMON_DIR +# Inherited from a hook running the suite, GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE/GIT_COMMON_DIR would aim +# every git and ripwire call below at the caller's repository (GIT_COMMON_DIR too: it redirects refs even +# when GIT_DIR is unset) — the paging fixture's own init/commit/branch calls, and the ref scans of the +# --whereis and --stray-content rows, which must read ONLY the refs that fixture holds (see +# mkPagingFixture). The clearing this gate used to hand-roll here is now test/lib/clean-env.sh's, sourced +# at the top, which also carries the object-directory names neither hand-rolled copy had. cd "$ROOT" || exit 2 echo "pagingsweepcheck: BIN=$BIN PREBIN=${PREBIN:-}" diff --git a/test/pargatescheck.sh b/test/pargatescheck.sh index 1d92a5279..e6f778fd0 100755 --- a/test/pargatescheck.sh +++ b/test/pargatescheck.sh @@ -25,6 +25,7 @@ # binary under test) set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" PARGATES="$ROOT/test/pargates.py" fail=0 ok(){ printf ' PASS %s\n' "$*" || { fail=1; printf ' FAIL could not write the PASS line for: %s\n' "$*"; }; return 0; } diff --git a/test/planlanescheck.sh b/test/planlanescheck.sh index 8d4a0147e..10355d016 100755 --- a/test/planlanescheck.sh +++ b/test/planlanescheck.sh @@ -37,6 +37,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/planlintcheck.sh b/test/planlintcheck.sh index 03fd79cfb..c932a0f13 100755 --- a/test/planlintcheck.sh +++ b/test/planlintcheck.sh @@ -34,6 +34,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/planlintfix/wave.md" diff --git a/test/pranchorcheck.sh b/test/pranchorcheck.sh index 7f75ded94..83a8b5630 100755 --- a/test/pranchorcheck.sh +++ b/test/pranchorcheck.sh @@ -34,6 +34,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/prbudgetcheck.sh b/test/prbudgetcheck.sh index 8677c0070..8c2dd2985 100755 --- a/test/prbudgetcheck.sh +++ b/test/prbudgetcheck.sh @@ -17,6 +17,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/prcontextcheck.sh b/test/prcontextcheck.sh index 6938d9528..526536677 100755 --- a/test/prcontextcheck.sh +++ b/test/prcontextcheck.sh @@ -19,6 +19,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" . "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" diff --git a/test/preproccondcheck.sh b/test/preproccondcheck.sh index 09efcd45a..f0d710cd2 100755 --- a/test/preproccondcheck.sh +++ b/test/preproccondcheck.sh @@ -63,6 +63,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN FIX="$ROOT/test/preproccondfix" diff --git a/test/prmaskanchorcheck.sh b/test/prmaskanchorcheck.sh index 1925371c0..6f37a80a2 100755 --- a/test/prmaskanchorcheck.sh +++ b/test/prmaskanchorcheck.sh @@ -34,6 +34,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/prnestedcapcheck.sh b/test/prnestedcapcheck.sh index 6839e260c..715c3c0a6 100755 --- a/test/prnestedcapcheck.sh +++ b/test/prnestedcapcheck.sh @@ -25,6 +25,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" # house convention: the suite passes the binary via RIPWIRE_BIN TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT fail=0 diff --git a/test/prrefsafecheck.sh b/test/prrefsafecheck.sh index af79f6d2e..5f6bc8f1d 100755 --- a/test/prrefsafecheck.sh +++ b/test/prrefsafecheck.sh @@ -43,6 +43,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/prrenamecheck.sh b/test/prrenamecheck.sh index a0d5dfc35..2ee7d674f 100755 --- a/test/prrenamecheck.sh +++ b/test/prrenamecheck.sh @@ -17,6 +17,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/qackconcurrencycheck.sh b/test/qackconcurrencycheck.sh index 2cfeedd15..117cb1cee 100755 --- a/test/qackconcurrencycheck.sh +++ b/test/qackconcurrencycheck.sh @@ -29,6 +29,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/qackorigincheck.sh b/test/qackorigincheck.sh index aefd6690e..4523a7e68 100755 --- a/test/qackorigincheck.sh +++ b/test/qackorigincheck.sh @@ -44,6 +44,7 @@ # Usage: test/qackorigincheck.sh | RIPWIRE_BIN=build/ripwire test/qackorigincheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/qbaselineproducercheck.sh b/test/qbaselineproducercheck.sh index 7b36b441d..7130093e1 100755 --- a/test/qbaselineproducercheck.sh +++ b/test/qbaselineproducercheck.sh @@ -51,6 +51,7 @@ # Usage: test/qbaselineproducercheck.sh | RIPWIRE_BIN=build/ripwire test/qbaselineproducercheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" IDSCRIPT="$ROOT/cmake/source_identity.cmake" diff --git a/test/qchurncheck.sh b/test/qchurncheck.sh index 53e85399d..3800e0ae9 100755 --- a/test/qchurncheck.sh +++ b/test/qchurncheck.sh @@ -24,6 +24,7 @@ # Usage: test/qchurncheck.sh | RIPWIRE_BIN=build_w2e/ripwire test/qchurncheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/qddialscheck.sh b/test/qddialscheck.sh index f59149a84..28a2f0500 100755 --- a/test/qddialscheck.sh +++ b/test/qddialscheck.sh @@ -22,6 +22,7 @@ # Usage: RIPWIRE_BIN=build/ripwire bash test/qddialscheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" # BOTH seams: positional AND env (a red-first run hands the pre-change binary in) [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/qdrefpaircheck.sh b/test/qdrefpaircheck.sh index 67680b6f6..3b1369b98 100755 --- a/test/qdrefpaircheck.sh +++ b/test/qdrefpaircheck.sh @@ -51,6 +51,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" . "$ROOT/test/lib/headbinlib.sh" # ripwire_private_checkout, for arm (E)'s scratch tree @@ -182,6 +183,19 @@ hdr "$TMP/bare.xml" | grep -q 'base_ref=' \ # ── (E) DECISIVE: ripwire's own recorded harvest wave, against the live-recomputed overlay oracle ───────── # RE-PIN LOG for the recorded literal below (it is a bare number, so its justification has to live here). +# 2026-09-20, integration/train-13 (lane/t13-honesty-fixes fix 2): 9 → 8 gating rows on this wave, and the +# row that left is EXACTLY the row train 12 added below. Fix 2 gives `reuse-decline` +# (new-clone-of-reused-helper) the two demotions its sibling `duplication` already had, one of which is +# the ALL-TEST-SCRIPT skip. Train 12's extra row was +# +# whose every member is a `test/`-pathed `.sh` gate script — precisely the population the skip exempts, +# and precisely the shape research-ai-smells measured as the kind's one real-history firing. `duplication` +# was already silent on that group; the two reporters now agree on it. Checked on the merged binary: the +# overlay carries NO new-clone-of-reused-helper row at all, and arm (E)'s row-for-row oracle comparison +# (5 rows) and its churn disclosure arm (3) both stayed green, so 5 + 3 = 8. Nothing else moved: the +# recorded dmm 0.530 reproduces unchanged. +# FOUND LATE, and worth recording as such: this gate greps src/quality.h and was missed by train 13's +# first-round gate selection, then caught by the wider sweep in the fix round. # 2026-09-20, integration/train-12 (issue #60, lane/t12-filescope-calls): 8 → 9 gating rows on this wave. # The message below offers three candidate causes — "the shas, the corpus or a kind's tier moved". It was a # FOURTH: a kind's EVIDENCE moved, in the direction #60 exists to move it. The extra row is @@ -234,9 +248,9 @@ else # the two RECORDED literals from the round record — a cross-check that these shas still name that wave overlayTotal=$(( oracleN + overlayChurn )) - [ "$overlayTotal" = 9 ] \ - && ok "(E) the overlay reproduces the pinned 9 gating rows (= $oracleN + $overlayChurn churn; 8 pre-#60, 18 pre-dial)" \ - || no "(E) the overlay gave $overlayTotal gating rows; this binary is pinned at 9 (8 before #60's file-scope callers, 18 before the 2026-09-10 dial round) — the shas, the corpus, a kind's tier or a kind's EVIDENCE moved; the RE-PIN LOG above arm (E) records how the last move was justified" + [ "$overlayTotal" = 8 ] \ + && ok "(E) the overlay reproduces the pinned 8 gating rows (= $oracleN + $overlayChurn churn; 9 between #60 and reuse-decline's test-script skip, 8 before #60, 18 pre-dial)" \ + || no "(E) the overlay gave $overlayTotal gating rows; this binary is pinned at 8 (9 between #60's file-scope callers and reuse-decline's all-test-script skip, 8 before #60, 18 before the 2026-09-10 dial round) — the shas, the corpus, a kind's tier or a kind's EVIDENCE moved; the RE-PIN LOG above arm (E) records how the last move was justified" dmmVal="$( "$BIN" "$ROOT" "--dmm=$WAVE_A..$WAVE_B" 2>/dev/null | grep -o ' dmm="[0-9.]*"' | head -1 | sed -E 's/.*"([0-9.]*)".*/\1/' )" # tolerance band, not equality: dmm is a float printed to 3 places (house float rule). if [ -n "$dmmVal" ] && awk -v v="$dmmVal" 'BEGIN{ exit !(v > 0.525 && v < 0.535) }'; then diff --git a/test/qextractionkeycheck.sh b/test/qextractionkeycheck.sh index 54d38e775..38221136d 100755 --- a/test/qextractionkeycheck.sh +++ b/test/qextractionkeycheck.sh @@ -34,6 +34,7 @@ # Usage: test/qextractionkeycheck.sh | RIPWIRE_BIN=build/ripwire test/qextractionkeycheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" QSRC="$ROOT/src/quality.h" diff --git a/test/qoriginoraclecheck.sh b/test/qoriginoraclecheck.sh index 40c6d4587..aa71b420b 100755 --- a/test/qoriginoraclecheck.sh +++ b/test/qoriginoraclecheck.sh @@ -35,6 +35,7 @@ # Usage: test/qoriginoraclecheck.sh | RIPWIRE_BIN=build/ripwire test/qoriginoraclecheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/qrevtokencheck.sh b/test/qrevtokencheck.sh index 832c05b4b..03a7b7ba5 100755 --- a/test/qrevtokencheck.sh +++ b/test/qrevtokencheck.sh @@ -28,6 +28,7 @@ # Usage: test/qrevtokencheck.sh | RIPWIRE_BIN=build/ripwire test/qrevtokencheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" QSRC="$ROOT/src/quality.h" diff --git a/test/qrowlocatorcheck.sh b/test/qrowlocatorcheck.sh index 4193cba55..7d98d7caf 100755 --- a/test/qrowlocatorcheck.sh +++ b/test/qrowlocatorcheck.sh @@ -22,6 +22,7 @@ # Usage: test/qrowlocatorcheck.sh | RIPWIRE_BIN=build/ripwire test/qrowlocatorcheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/qsnapcachecheck.sh b/test/qsnapcachecheck.sh index ab1da9074..4bd6274c4 100755 --- a/test/qsnapcachecheck.sh +++ b/test/qsnapcachecheck.sh @@ -28,6 +28,7 @@ # Usage: test/qsnapcachecheck.sh | RIPWIRE_BIN=build_r2a1/ripwire test/qsnapcachecheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" . "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" diff --git a/test/qsnapprefetchcheck.sh b/test/qsnapprefetchcheck.sh index f3aac8042..063fea064 100755 --- a/test/qsnapprefetchcheck.sh +++ b/test/qsnapprefetchcheck.sh @@ -46,6 +46,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" . "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" diff --git a/test/qsnapproducercheck.sh b/test/qsnapproducercheck.sh index dc60fb158..9115699cb 100755 --- a/test/qsnapproducercheck.sh +++ b/test/qsnapproducercheck.sh @@ -57,6 +57,7 @@ # Usage: test/qsnapproducercheck.sh | RIPWIRE_BIN=build/ripwire test/qsnapproducercheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" . "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" diff --git a/test/qualitycheck.sh b/test/qualitycheck.sh index eefb7492e..f537eb394 100755 --- a/test/qualitycheck.sh +++ b/test/qualitycheck.sh @@ -8,6 +8,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # make BIN absolute BEFORE we cd away fail=0 diff --git a/test/qualitycrosslangcheck.sh b/test/qualitycrosslangcheck.sh index 2d18d554d..8212a8a5a 100755 --- a/test/qualitycrosslangcheck.sh +++ b/test/qualitycrosslangcheck.sh @@ -10,6 +10,7 @@ # Usage: test/qualitycrosslangcheck.sh | RIPWIRE_BIN=asan/ripwire test/qualitycrosslangcheck.sh # Exits non-zero on any failure. Does NOT edit regression.sh. Needs git. set -u +. "$( cd "$( dirname "$0" )" && pwd )/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-./build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$PWD/$BIN" fail=0 diff --git a/test/qualityexcludecheck.sh b/test/qualityexcludecheck.sh index 6c456773d..b21a38da1 100755 --- a/test/qualityexcludecheck.sh +++ b/test/qualityexcludecheck.sh @@ -17,6 +17,7 @@ # Uses its OWN temp repo. Does NOT edit regression.sh. Needs git. # Usage: test/qualityexcludecheck.sh | RIPWIRE_BIN=build/ripwire test/qualityexcludecheck.sh set -u +. "$( cd "$( dirname "$0" )" && pwd )/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-./build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$PWD/$BIN" fail=0 diff --git a/test/qualitykeycheck.sh b/test/qualitykeycheck.sh index 2cdf81091..b05dc0fef 100755 --- a/test/qualitykeycheck.sh +++ b/test/qualitykeycheck.sh @@ -40,6 +40,7 @@ # Runs on synthetic git repos so it never depends on ripwire's own debt or ack ledger. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/qualitykindscheck.sh b/test/qualitykindscheck.sh index 19db169aa..d9fff1e33 100755 --- a/test/qualitykindscheck.sh +++ b/test/qualitykindscheck.sh @@ -12,6 +12,7 @@ # Usage: RIPWIRE_BIN=build_w3/ripwire bash test/qualitykindscheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # absolutize BEFORE we cd away fail=0 diff --git a/test/qualityorigincheck.sh b/test/qualityorigincheck.sh index efd668353..9947a8788 100755 --- a/test/qualityorigincheck.sh +++ b/test/qualityorigincheck.sh @@ -24,6 +24,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # make BIN absolute BEFORE we cd away fail=0 diff --git a/test/qualityscopecheck.sh b/test/qualityscopecheck.sh index 26200f283..cbe1324f9 100755 --- a/test/qualityscopecheck.sh +++ b/test/qualityscopecheck.sh @@ -32,6 +32,7 @@ # The gate runs on a synthetic two-writer repo so it never depends on ripwire's own current debt. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/qualitysignalcheck.sh b/test/qualitysignalcheck.sh index e812fc335..8c3b74e33 100755 --- a/test/qualitysignalcheck.sh +++ b/test/qualitysignalcheck.sh @@ -17,6 +17,7 @@ # Usage: RIPWIRE_BIN=build/ripwire bash test/qualitysignalcheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" # BOTH seams: positional AND env (a single-bound gate silently ignores the binary a red-first run hands it) [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # absolutize BEFORE we cd away fail=0 diff --git a/test/qualitystalecheck.sh b/test/qualitystalecheck.sh index 7d2a51fec..4d90d181a 100755 --- a/test/qualitystalecheck.sh +++ b/test/qualitystalecheck.sh @@ -29,6 +29,7 @@ # file was stale-and-just-dropped, or stale-and-STILL-THERE (arm 8). set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$PWD/$BIN" fail=0 diff --git a/test/qualitysymcheck.sh b/test/qualitysymcheck.sh index e65e008be..1d775d34d 100755 --- a/test/qualitysymcheck.sh +++ b/test/qualitysymcheck.sh @@ -21,6 +21,7 @@ # Usage: test/qualitysymcheck.sh | RIPWIRE_BIN=build/ripwire test/qualitysymcheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/rankbycheck.sh b/test/rankbycheck.sh index 46eae8351..4fd28d99c 100755 --- a/test/rankbycheck.sh +++ b/test/rankbycheck.sh @@ -16,6 +16,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/rankbyfix" diff --git a/test/receiptpostcheck.sh b/test/receiptpostcheck.sh index dec3503be..268398906 100755 --- a/test/receiptpostcheck.sh +++ b/test/receiptpostcheck.sh @@ -26,6 +26,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/recentscopecheck.sh b/test/recentscopecheck.sh index 95ff089b6..dec61d947 100755 --- a/test/recentscopecheck.sh +++ b/test/recentscopecheck.sh @@ -46,6 +46,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/refusaltailcheck.sh b/test/refusaltailcheck.sh index b1e2dab51..277fa195b 100755 --- a/test/refusaltailcheck.sh +++ b/test/refusaltailcheck.sh @@ -29,6 +29,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/registermacrocheck.sh b/test/registermacrocheck.sh index d8c7a435a..d8787d1d5 100755 --- a/test/registermacrocheck.sh +++ b/test/registermacrocheck.sh @@ -53,6 +53,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # absolutize BEFORE we cd away fail=0 diff --git a/test/regression.sh b/test/regression.sh index 776a867e7..a6b6b0676 100755 --- a/test/regression.sh +++ b/test/regression.sh @@ -277,7 +277,7 @@ else RIPWIRE_BIN="$BIN" bash "$ROOT/test/codexdoctorcheck.sh" 2>&1 | sed 's/^/ | /' fi # retired: cacheexclkeycheck — the per-configuration auto-cache key it pinned is a registered NEGATIVE (docs/EVALS.md, "The auto-cache key ignores --exclude", RUN 2026-09-03: a 158K-file root with >= 12 gate configurations thrashed the 2 GiB sweep); the retry design keeps ONE superset blob per root and will bring its own gate -for _g in a9disclosurecheck abicheck accessshapecheck ackonlycheck adaptivecheck adaptivecutshapecheck affectedcheck agentloopclaudecheck agentloopcodexcheck agentloopeditsuitecheck agentloopfollowupcheck agentloopgradercheck agentlooplockcheck agentloopopencodecheck agentsurfacecheck agenttablecheck aiderbytescheck anchorbodycheck anchorcheck archcheck archmetricscheck argvdiffcheck arisefollowupcheck ariseshimcheck aritycheck artifactcheck astqueryregexcheck atcheck atomscheck attrvocabcheck baselinecheck baselinedirtycheck baselineportcheck bashsourcecheck batchcheck binoverridecheck blindspotcheck bm25boundcheck bm25check bodiesshowncheck bodydialectcheck budgetpolicycheck buildtypestampcheck bundleidcheck cachefuzzcheck cachehashcheck cacheidentitycheck cacheisolationcheck cachelintcheck cacheoffsetcheck cachereservecheck cachesplitcheck callerscheck callformcheck callsrankordercheck candheadcheck candidatescheck canoncheck capdisclosurecheck capsweepcheck ccheck ccjsoncheck ceilingverdictcheck chacheck chaconecheck chainguardcheck chainidcheck childwalkscalecheck churndecaycheck churnjoincheck churnjsonstampcheck claudeconfigdircheck clicheck clonebandcheck clonecachecheck clonededupcheck cloneidiomcheck clonelexcheck clsrecvcheck cochangeboostcheck cochangecliocheck cochangesurprisecheck codexinstallhonestycheck codexplugincheck codexwrapcheck collectioncapcheck columnarattrcheck columnarcheck columnarcommacheck commentcoherencecheck communitydrillcheck communitylabelcheck compactlegendcheck compactroutecheck completecheck composelangcheck connectcheck connectcorecheck connectjoincheck constcheck contextratiocheck coplintcheck cppbenchcheck cppoperatorcheck cppqualcheck cpptmplscopecheck crashsweepcheck crawlescapecheck crossdirincludecheck crossrefcheck crossrefdegradecheck csharpcheck csharpcondcheck cudacheck cyclecutcheck dartcheck deadcheck deadfiltercheck deadprecisioncheck deckcheck deckclaimcheck declinecheck declinedlistcheck decltodefcheck deeptailcheck defaultceilingcheck defoverdeclcheck degradedhintcheck dependencypincheck deplangscheck depsprecisecheck detailcheck diagnoticecheck didyoumeancheck dispatchordercheck dmmcheck docanchorcheck docdemotecheck docdriftcheck docdriftcommentcheck docmdcachecheck docmentioncheck docscommandscheck doctorcheck donelegendcheck droppedpositivecheck duprowcheck dynmapsimdcheck editcheckanswercheck editcheckcheck editchecknotecheck edithandlehintcheck editpayloadbinarycheck editplancheck editplanpayloadconfinecheck editplanrecheckcheck editplanrollbackmsgcheck editpreviewcheck editroundtripcheck edittargetfileabscheck eliximportcheck elixircheck elixirnamearitycheck elixirsemanticcheck emitescapecheck emittertruthcheck emptycorpuscheck emptyvaluerefusecheck ensembleavailcheck ensemblecheck enumtablecheck essentialcxcheck estchargecheck evalcheck evictioncheck exemplarcheck exemplarconfcheck exercisescheck expandbodyfirstcheck expandcallscheck expandmodecheck expandrangecheck expandsibscheck expandtokencheck expandtopk0check extentcheck externalvetocheck fficheck fieldaffinitycheck fieldidcheck fieldnarrowcheck fieldusescheck filerootcheck fileselectorrefusecheck fillordercheck fixedbufsweep flagscheck flagsnoisecheck flagsurfacecheck flagtablecheck flipcheck floormarkcheck fnptrcheck forautobodycheck forblowupcheck forbudgetmonotoncheck forcalibfactscheck forcompresscheck fordisclosurecheck forhdrshapecheck forlenscheck formatgatecheck formaxtokenscheck fornotesbudgetcheck fornotesjsoncheck forrankordercheck forrootlegendcheck forsectioncollapsecheck forwidencheck freshclonecheck freshnesscheck g1configcheck gateabilitycheck gatecountcheck gateexitcheck gdscriptcheck genrecallcheck githardencheck gitignorecheck gitquotepathcheck gitstampcheck goinstcheck gointerfacecheck graphlegendbudgetcheck graphqueryrefusecheck grepanchorcheck grepandcheck grepbytescheck grepcheck grepcontextcheck grepcorpuscheck grepfastcheck grepfollowupcheck grepignorecheck grepscancheck grepseamcheck greptiercheck guardmsgcheck hasacheck hazardpatterncheck headbinstagecheck headsnapcachecheck helpbudgetcheck hermesinstallcheck historyoraclecheck hookcheck hostilecheck hotspotsincecheck htmlcolorcheck htmlhostcheck htmlrendercheck identitycheck impactimportcheck impactpartitioncheck importnarrowcheck includeanglecheck includeprecisecheck indexoutcheck infraportcheck isolateprovenancecheck javamethodrefcheck javarubycheck jslangcheck jsmetricscheck jsnestedcheck jsoncheck jsonlangcheck jsonparitycheck jsonredactcheck jsonrefusallegendcheck jsonwalkcheck jsshapecheck jsverbscheck jsxcallcheck knownitemcheck kotlincheck landingcheck langcensuscheck langcheck layerquerycheck layoutcheck lb3namecheck legendcostcheck legendcoveragecheck legenddriftcheck legendrefcheck legobundlecheck legocheck liftdisclosurecheck limitstablecheck lintbudgetcheck lintcatalogcheck lintcheck lintdedupcheck lintpayloadcapcheck lintprecisioncheck lintrulescheck lintscopecheck lintselectcheck listingpagingcheck localitycheck localscountcheck loopconservationcheck lpincheck luacheck luarequirecheck macroedgecheck macroreparsecheck manifestcheck mapdiffcheck matchcapturecheck matchgrammarcheck maxfilesizecheck mcpattrparitycheck mcpaudit4hardencheck mcpclidiffcheck mcpcodexmetacheck mcpcontractcheck mcpdegradedhintcheck mcpeditcheck mcpeditkindcheck mcpeditmodecheck mcpeditpresencecheck mcpeditracecheck mcpflagshipcheck mcpforparitycheck mcpframehonestycheck mcpgrepdegradedcheck mcphandlecheck mcpincrementalcheck mcpmanifestcheck mcprangeedgecheck mcpreadloopcheck mcpredactcheck mcpreloadcheck mcpremotecheck mcprobustcheck mcpslicecheck mcpstalecheck mcpstdiolinecapcheck mcpstrictschemacheck mcptoolprunecheck mcptranchecheck mcpverbscheck mcpw2fixcheck mcpw3fixcheck mcpwatchercheck mdembedcheck mdsectioncheck mentioncapcheck mentioncheck mentionsverbcheck mergechurncheck mergescoutcheck mergescoutlonglinecheck metalcheck meterdisclosurecheck metricscheck modifierguardcheck moduleconstcheck morecontractcheck mrowalkcheck multirootcheck multiswecheck namedfileinputcheck nameinfocheck namingcalibrationcheck namingconsistencycheck naminglenscheck naminglocalscheck narrowcheck narrowlangcheck neighbourcapcheck nestedimportcheck nestedqualcheck nestprofilecheck nextverbcheck noaliascheck nodekindcheck nongitqmetricscheck nonlocalstatecheck notecanoncheck notescheck notesdegradecheck nsfiltercheck nulbytecheck numericrefusecheck objcfieldcheck objcsniffcheck opencodewrapcheck optremarkscheck optremarkshotcheck ordercheck osswitchcheck outlinecheck overbudgetcommentcheck ownerscheck packcallersharecheck packtaskcheck packtaskmonotoncheck packtaskquotacheck padscalecheck paginationcheck pagingsweepcheck panellegendcheck pargatescheck parsehealthcheck partitioncheck patterncheck perfharnesscheck phpcheck pincensuscheck planlanescheck planlintcheck pmccheck portablebuildcheck portablecachecheck postingscheck ppaltcheck ppdeadrolescheck pranchorcheck prbudgetcheck prcheck prcontextcheck prconvergecheck precedencecheck preproccondcheck preprocdeadscalecheck prmaskanchorcheck prnestedcapcheck probecheck propcostcheck prrefsafecheck prrenamecheck pyimportprecisecheck pymodulealiascheck pyshapecheck qackconcurrencycheck qackorigincheck qbaselineproducercheck qchurncheck qchurnmemocheck qddialscheck qdrefpaircheck qextractionkeycheck qoriginoraclecheck qrevtokencheck qrowlocatorcheck qschemetripcheck qsnapcachecheck qsnapprefetchcheck qsnapproducercheck qualifiedresolvecheck qualitycheck qualitycrosslangcheck qualityexcludecheck qualitykeycheck qualitykindscheck qualityorigincheck qualitypanelcheck qualityscopecheck qualitysignalcheck qualitystalecheck qualitysymcheck qualnewcheck querycheck queryfilescancheck racymtimecheck radixsimdcheck rangecomposecheck rankbycheck reachcheck readabilitycheck readmedriftcheck readmeexamplecheck recallanchorcheck recallboundarycheck recallbudgetcheck recallbufcheck recallevalcheck recallparitycheck recallpassagecheck recallrankdepthcheck recallrelcheck recalltablecheck recalltotalcheck receiptpostcheck recentscopecheck redactcheck redactfixcheck refusaltailcheck regexbombcheck regexcheck regexguardcheck regexrefusecheck registermacrocheck relevancefloorcheck relinkcheck reportcheck resolvecheck resolverhonestycheck retrievalqualitycheck reusefirstworkflowcheck ripwirepubliccheck rootrelcheck rootrelemitcheck rootspellingcheck routecheck routeedgecheck routehookcheck routeoncecheck routingreportcheck rubyargcheck rubyconstcheck rubymetricscheck rubyrecvcheck rubyrecvnarrowcheck rubyrequirecheck rubyscopecheck rubysettercheck runhintcheck runtracecheck rustanccheck rustimportprecisecheck rustqualcheck safedeletecheck sarifcheck savecachecheck scipcheck scipjoincheck scorecardcheck scoutheadconflictcheck scoutkeycheck scroundtripcheck seedboundscheck selectorchaincheck selectorhonestycheck selectorrefusecheck selectorscopecheck selfcheckcheck selfcontainedcheck shadowcheck shapingflagcheck shellgateindexcheck showcasecapturecheck sibliftcheck sidecarsymlinkcheck sigredactcheck sincecheck sincecochangecheck sincewindowcheck singledefcheck situdiffcheck situshapecheck skilldescbudgetcheck skillevalcheck skillevalsplitcheck skillinstallcheck skillroutingjudgedcheck skillscanreadcheck skilltruthcheck skipclassifycheck skippedcheck skipreasoncheck slicecheck slicediffcheck sliceflowcheck sliceflowsenscheck spectimingcheck staleackcheck statgatecheck stdqualcheck strkerncheck structlayoutcheck sublistcountcheck substrfiltercheck subtokencheck svectorcheck swiftcheck swiftmemberscheck swiftshapecheck taskechocheck tempfilesymlinkcheck termmargincheck testedreachcheck testgatecheck testgatelegendbudgetcheck testgatepagecheck testgaterefusecheck testmacrocheck testrowruncheck testscopecheck textdocscheck timsortcheck tokenbudgetcheck tomllangcheck toolcallroutecheck tornreadcheck traceasanlinearcheck tracecheck tracehandoffcapcheck tracehopcheck traceminecheck treecheck truncvocabcheck tsimportprecisecheck tsshapecheck type3check type3clonecheck typerefcheck unreachablecheck unresolvedcheck usescheck usesselectorcheck usingdeclcheck utf8scrubcheck vendoredassetcheck vendoredbundlecheck vendorpatchcheck verifycheck versioncheck w2verbscheck w3fixbudgetcheck w3fixlegendcheck weaksignalcheck withgraphcheck withprofilecheck worktreeleakcheck wrapverbscheck writetargetcheck xmlwellformed yamllangcheck zonecheck zoneconsistencycheck zoomcheck; do +for _g in a9disclosurecheck abicheck accessshapecheck ackonlycheck adaptivecheck adaptivecutshapecheck affectedcheck agentloopclaudecheck agentloopcodexcheck agentloopeditsuitecheck agentloopfollowupcheck agentloopgradercheck agentlooplockcheck agentloopopencodecheck agentsurfacecheck agenttablecheck aiderbytescheck anchorbodycheck anchorcheck archcheck archmetricscheck argvdiffcheck arisefollowupcheck ariseshimcheck aritycheck artifactcheck astqueryregexcheck atcheck atomscheck attrvocabcheck baselinecheck baselinedirtycheck baselineportcheck bashsourcecheck batchcheck binoverridecheck blindspotcheck bm25boundcheck bm25check bodiesshowncheck bodydialectcheck budgetpolicycheck buildtypestampcheck bundleidcheck cachefuzzcheck cachehashcheck cacheidentitycheck cacheisolationcheck cachelintcheck cacheoffsetcheck cachereservecheck cachesplitcheck callerscheck callformcheck callsrankordercheck candheadcheck candidatescheck canoncheck capdisclosurecheck capsweepcheck ccheck ccjsoncheck ceilingverdictcheck chacheck chaconecheck chainguardcheck chainidcheck childwalkscalecheck churndecaycheck churnjoincheck churnjsonstampcheck claudeconfigdircheck clicheck clonebandcheck clonecachecheck clonededupcheck cloneidiomcheck clonelexcheck clsrecvcheck cochangeboostcheck cochangecliocheck cochangesurprisecheck codexinstallhonestycheck codexplugincheck codexwrapcheck collectioncapcheck columnarattrcheck columnarcheck columnarcommacheck commentcoherencecheck communitydrillcheck communitylabelcheck compactlegendcheck compactroutecheck completecheck composelangcheck connectcheck connectcorecheck connectjoincheck constcheck contextratiocheck coplintcheck cppbenchcheck cppoperatorcheck cppqualcheck cpptmplscopecheck crashsweepcheck crawlescapecheck crossdirincludecheck crossrefcheck crossrefdegradecheck csharpcheck csharpcondcheck cudacheck cyclecutcheck dartcheck deadcheck deadfiltercheck deadprecisioncheck deckcheck deckclaimcheck declinecheck declinedlistcheck decltodefcheck deeptailcheck defaultceilingcheck defoverdeclcheck degradedhintcheck dependencypincheck deplangscheck depsprecisecheck detailcheck diagnoticecheck didyoumeancheck dispatchordercheck dmmcheck docanchorcheck docdemotecheck docdriftcheck docdriftcommentcheck docmdcachecheck docmentioncheck docscommandscheck doctorcheck donelegendcheck droppedpositivecheck duprowcheck dynmapsimdcheck editcheckanswercheck editcheckcheck editchecknotecheck edithandlehintcheck editpayloadbinarycheck editplancheck editplanpayloadconfinecheck editplanrecheckcheck editplanrollbackmsgcheck editpreviewcheck editroundtripcheck edittargetfileabscheck eliximportcheck elixircheck elixirnamearitycheck elixirsemanticcheck emitescapecheck emittertruthcheck emptycorpuscheck emptyvaluerefusecheck ensembleavailcheck ensemblecheck enumtablecheck essentialcxcheck estchargecheck evalcheck evictioncheck exemplarcheck exemplarconfcheck exercisescheck expandbodyfirstcheck expandcallscheck expandmodecheck expandrangecheck expandsibscheck expandtokencheck expandtopk0check extentcheck externalvetocheck fficheck fieldaffinitycheck fieldidcheck fieldnarrowcheck fieldusescheck filerootcheck fileselectorrefusecheck fillordercheck fixedbufsweep flagscheck flagsnoisecheck flagsurfacecheck flagtablecheck flipcheck floormarkcheck fnptrcheck forautobodycheck forblowupcheck forbudgetmonotoncheck forcalibfactscheck forcompresscheck fordisclosurecheck forhdrshapecheck forlenscheck formatgatecheck formaxtokenscheck fornotesbudgetcheck fornotesjsoncheck forrankordercheck forrootlegendcheck forsectioncollapsecheck forwidencheck freshclonecheck freshnesscheck g1configcheck gateabilitycheck gatecountcheck gateexitcheck gdscriptcheck genrecallcheck gitenvhermeticcheck githardencheck gitignorecheck gitquotepathcheck gitstampcheck goinstcheck gointerfacecheck graphlegendbudgetcheck graphqueryrefusecheck grepanchorcheck grepandcheck grepbytescheck grepcheck grepcontextcheck grepcorpuscheck grepfastcheck grepfollowupcheck grepignorecheck grepscancheck grepseamcheck greptiercheck guardmsgcheck hasacheck hazardpatterncheck headbinstagecheck headsnapcachecheck helpbudgetcheck hermesinstallcheck historyoraclecheck hookcheck hostilecheck hotspotsincecheck htmlcolorcheck htmlhostcheck htmlrendercheck identitycheck impactimportcheck impactpartitioncheck importnarrowcheck includeanglecheck includeprecisecheck indexoutcheck infraportcheck isolateprovenancecheck javamethodrefcheck javarubycheck jslangcheck jsmetricscheck jsnestedcheck jsoncheck jsonlangcheck jsonparitycheck jsonredactcheck jsonrefusallegendcheck jsonwalkcheck jsshapecheck jsverbscheck jsxcallcheck knownitemcheck kotlincheck landingcheck langcensuscheck langcheck layerquerycheck layoutcheck lb3namecheck legendcostcheck legendcoveragecheck legenddriftcheck legendrefcheck legobundlecheck legocheck liftdisclosurecheck limitstablecheck lintbudgetcheck lintcatalogcheck lintcheck lintdedupcheck lintpayloadcapcheck lintprecisioncheck lintrulescheck lintscopecheck lintselectcheck listingpagingcheck localitycheck localscountcheck loopconservationcheck lpincheck luacheck luarequirecheck macroedgecheck macroreparsecheck manifestcheck mapdiffcheck matchcapturecheck matchgrammarcheck maxfilesizecheck mcpattrparitycheck mcpaudit4hardencheck mcpclidiffcheck mcpcodexmetacheck mcpcontractcheck mcpdegradedhintcheck mcpeditcheck mcpeditkindcheck mcpeditmodecheck mcpeditpresencecheck mcpeditracecheck mcpflagshipcheck mcpforparitycheck mcpframehonestycheck mcpgrepdegradedcheck mcphandlecheck mcpincrementalcheck mcpmanifestcheck mcprangeedgecheck mcpreadloopcheck mcpredactcheck mcpreloadcheck mcpremotecheck mcprobustcheck mcpslicecheck mcpstalecheck mcpstdiolinecapcheck mcpstrictschemacheck mcptoolprunecheck mcptranchecheck mcpverbscheck mcpw2fixcheck mcpw3fixcheck mcpwatchercheck mdembedcheck mdsectioncheck mentioncapcheck mentioncheck mentionsverbcheck mergechurncheck mergescoutcheck mergescoutlonglinecheck metalcheck meterdisclosurecheck metricscheck modifierguardcheck moduleconstcheck morecontractcheck mrowalkcheck multirootcheck multiswecheck namedfileinputcheck nameinfocheck namingcalibrationcheck namingconsistencycheck naminglenscheck naminglocalscheck narrowcheck narrowlangcheck neighbourcapcheck nestedimportcheck nestedqualcheck nestprofilecheck nextverbcheck noaliascheck nodekindcheck nongitqmetricscheck nonlocalstatecheck notecanoncheck notescheck notesdegradecheck nsfiltercheck nulbytecheck numericrefusecheck objcfieldcheck objcsniffcheck opencodewrapcheck optremarkscheck optremarkshotcheck ordercheck osswitchcheck outlinecheck overbudgetcommentcheck ownerscheck packcallersharecheck packtaskcheck packtaskmonotoncheck packtaskquotacheck padscalecheck paginationcheck pagingsweepcheck panellegendcheck pargatescheck parsehealthcheck partitioncheck patterncheck perfharnesscheck phpcheck pincensuscheck planlanescheck planlintcheck pmccheck portablebuildcheck portablecachecheck postingscheck ppaltcheck ppdeadrolescheck pranchorcheck prbudgetcheck prcheck prcontextcheck prconvergecheck precedencecheck preproccondcheck preprocdeadscalecheck prmaskanchorcheck prnestedcapcheck probecheck propcostcheck prrefsafecheck prrenamecheck pyimportprecisecheck pymodulealiascheck pyshapecheck qackconcurrencycheck qackorigincheck qbaselineproducercheck qchurncheck qchurnmemocheck qddialscheck qdrefpaircheck qextractionkeycheck qoriginoraclecheck qrevtokencheck qrowlocatorcheck qschemetripcheck qsnapcachecheck qsnapprefetchcheck qsnapproducercheck qualifiedresolvecheck qualitycheck qualitycrosslangcheck qualityexcludecheck qualitykeycheck qualitykindscheck qualityorigincheck qualitypanelcheck qualityscopecheck qualitysignalcheck qualitystalecheck qualitysymcheck qualnewcheck querycheck queryfilescancheck racymtimecheck radixsimdcheck rangecomposecheck rankbycheck reachcheck readabilitycheck readmedriftcheck readmeexamplecheck recallanchorcheck recallboundarycheck recallbudgetcheck recallbufcheck recallevalcheck recallparitycheck recallpassagecheck recallrankdepthcheck recallrelcheck recalltablecheck recalltotalcheck receiptpostcheck recentscopecheck redactcheck redactfixcheck refusaltailcheck regexbombcheck regexcheck regexguardcheck regexrefusecheck registermacrocheck relevancefloorcheck relinkcheck reportcheck resolvecheck resolverhonestycheck retrievalqualitycheck reusefirstworkflowcheck ripwirepubliccheck rootrelcheck rootrelemitcheck rootspellingcheck routecheck routeedgecheck routehookcheck routeoncecheck routingreportcheck rubyargcheck rubyconstcheck rubymetricscheck rubyrecvcheck rubyrecvnarrowcheck rubyrequirecheck rubyscopecheck rubysettercheck runhintcheck runtracecheck rustanccheck rustimportprecisecheck rustqualcheck safedeletecheck sarifcheck savecachecheck scipcheck scipjoincheck scorecardcheck scoutheadconflictcheck scoutkeycheck scroundtripcheck seedboundscheck selectorchaincheck selectorhonestycheck selectorrefusecheck selectorscopecheck selfcheckcheck selfcontainedcheck shadowcheck shapingflagcheck shellgateindexcheck showcasecapturecheck sibliftcheck sidecarsymlinkcheck sigredactcheck sincecheck sincecochangecheck sincewindowcheck singledefcheck situdiffcheck situshapecheck skilldescbudgetcheck skillevalcheck skillevalsplitcheck skillinstallcheck skillroutingjudgedcheck skillscanreadcheck skilltruthcheck skipclassifycheck skippedcheck skipreasoncheck slicecheck slicediffcheck sliceflowcheck sliceflowsenscheck spectimingcheck staleackcheck statgatecheck stdqualcheck strkerncheck structlayoutcheck sublistcountcheck substrfiltercheck subtokencheck svectorcheck swiftcheck swiftmemberscheck swiftshapecheck taskechocheck tempfilesymlinkcheck termmargincheck testedreachcheck testgatecheck testgatelegendbudgetcheck testgatepagecheck testgaterefusecheck testmacrocheck testrowruncheck testscopecheck textdocscheck timsortcheck tokenbudgetcheck tomllangcheck toolcallroutecheck tornreadcheck traceasanlinearcheck tracecheck tracehandoffcapcheck tracehopcheck traceminecheck treecheck truncvocabcheck tsimportprecisecheck tsshapecheck type3check type3clonecheck typerefcheck unreachablecheck unresolvedcheck usescheck usesselectorcheck usingdeclcheck utf8scrubcheck vendoredassetcheck vendoredbundlecheck vendorpatchcheck verifycheck versioncheck w2verbscheck w3fixbudgetcheck w3fixlegendcheck weaksignalcheck withgraphcheck withprofilecheck worktreeleakcheck wrapverbscheck writetargetcheck xmlwellformed yamllangcheck zonecheck zoneconsistencycheck zoomcheck; do [ -f "$ROOT/test/$_g.sh" ] || continue if RIPWIRE_BIN="$BIN" bash "$ROOT/test/$_g.sh" >/dev/null 2>&1; then ok "absorb gate ($_g.sh)" diff --git a/test/ripwirepubliccheck.sh b/test/ripwirepubliccheck.sh index c6640f7c2..9f5e397ac 100755 --- a/test/ripwirepubliccheck.sh +++ b/test/ripwirepubliccheck.sh @@ -29,6 +29,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" cd "$ROOT" || { printf 'ripwirepubliccheck: cannot cd to repo root %s\n' "$ROOT"; exit 2; } fail=0 diff --git a/test/rootrelemitcheck.sh b/test/rootrelemitcheck.sh index 7016864ba..fb8d1e39c 100755 --- a/test/rootrelemitcheck.sh +++ b/test/rootrelemitcheck.sh @@ -36,6 +36,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/rootspellingcheck.sh b/test/rootspellingcheck.sh index 5b49fd968..58a3e8f41 100755 --- a/test/rootspellingcheck.sh +++ b/test/rootspellingcheck.sh @@ -45,6 +45,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/rootspellfix" diff --git a/test/runhintcheck.sh b/test/runhintcheck.sh index 92529422b..7d3a3d9a5 100755 --- a/test/runhintcheck.sh +++ b/test/runhintcheck.sh @@ -23,6 +23,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/scoutheadconflictcheck.sh b/test/scoutheadconflictcheck.sh index a51d1820b..a7202141f 100755 --- a/test/scoutheadconflictcheck.sh +++ b/test/scoutheadconflictcheck.sh @@ -41,6 +41,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/scoutkeycheck.sh b/test/scoutkeycheck.sh index 2bbd7eb4b..2469effe9 100755 --- a/test/scoutkeycheck.sh +++ b/test/scoutkeycheck.sh @@ -14,6 +14,7 @@ # positive must be gone AND the true positives must survive. set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/selectorrefusecheck.sh b/test/selectorrefusecheck.sh index 7e947be96..a155612bc 100755 --- a/test/selectorrefusecheck.sh +++ b/test/selectorrefusecheck.sh @@ -22,6 +22,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/shapingflagcheck.sh b/test/shapingflagcheck.sh index 3eb42af2d..53f3b465c 100755 --- a/test/shapingflagcheck.sh +++ b/test/shapingflagcheck.sh @@ -35,6 +35,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/sidecarsymlinkcheck.sh b/test/sidecarsymlinkcheck.sh index d1166ca0a..50ca3eeae 100755 --- a/test/sidecarsymlinkcheck.sh +++ b/test/sidecarsymlinkcheck.sh @@ -166,6 +166,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" . "$ROOT/test/lib/statcompat.sh" # BOTH seams: regression.sh and every differential run pass the binary POSITIONALLY; RIPWIRE_BIN is the # env form. A gate reading only one of them comes back ALL PASS against whatever is in build/ during a diff --git a/test/sincecheck.sh b/test/sincecheck.sh index 38fe61ba1..d254e7154 100755 --- a/test/sincecheck.sh +++ b/test/sincecheck.sh @@ -54,6 +54,7 @@ # Usage: test/sincecheck.sh | RIPWIRE_BIN=asan/ripwire test/sincecheck.sh # Exits non-zero on any failure. Does NOT edit test/regression.sh. Needs git. set -u +. "$( cd "$( dirname "$0" )" && pwd )/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-./build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$PWD/$BIN" fail=0 diff --git a/test/sincecochangecheck.sh b/test/sincecochangecheck.sh index 7ede588ea..035608bc3 100755 --- a/test/sincecochangecheck.sh +++ b/test/sincecochangecheck.sh @@ -39,6 +39,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/sincewindowcheck.sh b/test/sincewindowcheck.sh index 113323d86..76f20595a 100755 --- a/test/sincewindowcheck.sh +++ b/test/sincewindowcheck.sh @@ -10,6 +10,7 @@ # Usage: test/sincewindowcheck.sh | RIPWIRE_BIN=asan/ripwire test/sincewindowcheck.sh # Exits non-zero on any failure. Self-contained (own temp dirs). Does NOT edit test/regression.sh. Needs git. set -u +. "$( cd "$( dirname "$0" )" && pwd )/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-./build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$PWD/$BIN" fail=0 diff --git a/test/singledefcheck.sh b/test/singledefcheck.sh index 02f88a2b3..ff0489806 100755 --- a/test/singledefcheck.sh +++ b/test/singledefcheck.sh @@ -32,6 +32,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/situdiffcheck.sh b/test/situdiffcheck.sh index 05f6732f6..0dfda057b 100755 --- a/test/situdiffcheck.sh +++ b/test/situdiffcheck.sh @@ -16,6 +16,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow a repo-relative RIPWIRE_BIN CORPUS="$ROOT/test/zoomfix" diff --git a/test/situshapecheck.sh b/test/situshapecheck.sh index 25d5c5cb3..99c10d689 100755 --- a/test/situshapecheck.sh +++ b/test/situshapecheck.sh @@ -39,6 +39,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/slicediffcheck.sh b/test/slicediffcheck.sh index 77b1358bc..e98500c0d 100755 --- a/test/slicediffcheck.sh +++ b/test/slicediffcheck.sh @@ -36,6 +36,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/sliceflowsenscheck.sh b/test/sliceflowsenscheck.sh index cbd9b96bd..bc9b00bbd 100755 --- a/test/sliceflowsenscheck.sh +++ b/test/sliceflowsenscheck.sh @@ -30,6 +30,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="$ROOT/test/sliceflowsensfix" diff --git a/test/staleackcheck.sh b/test/staleackcheck.sh index 193a9d601..a42491369 100755 --- a/test/staleackcheck.sh +++ b/test/staleackcheck.sh @@ -28,6 +28,7 @@ # Usage: test/staleackcheck.sh | test/staleackcheck.sh asan/ripwire | RIPWIRE_BIN=asan/ripwire test/staleackcheck.sh set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/substrfiltercheck.sh b/test/substrfiltercheck.sh index 22879dc53..220b0a22c 100755 --- a/test/substrfiltercheck.sh +++ b/test/substrfiltercheck.sh @@ -36,6 +36,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/taskroutecheck.sh b/test/taskroutecheck.sh index 8cac7525a..1d39229c4 100755 --- a/test/taskroutecheck.sh +++ b/test/taskroutecheck.sh @@ -3,6 +3,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/tempfilesymlinkcheck.sh b/test/tempfilesymlinkcheck.sh index e1d8e8122..7670bd43f 100644 --- a/test/tempfilesymlinkcheck.sh +++ b/test/tempfilesymlinkcheck.sh @@ -42,6 +42,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" . "$ROOT/test/lib/statcompat.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" # allow repo-relative RIPWIRE_BIN diff --git a/test/testgatecheck.sh b/test/testgatecheck.sh index 62e10cd7e..54b176dec 100755 --- a/test/testgatecheck.sh +++ b/test/testgatecheck.sh @@ -31,6 +31,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" # BOTH seams: positional and RIPWIRE_BIN [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/testrowruncheck.sh b/test/testrowruncheck.sh index 260d1174e..c87277d05 100755 --- a/test/testrowruncheck.sh +++ b/test/testrowruncheck.sh @@ -34,6 +34,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" fail=0 diff --git a/test/tracehandoffcapcheck.sh b/test/tracehandoffcapcheck.sh index 37a06cb18..e4b32ab06 100755 --- a/test/tracehandoffcapcheck.sh +++ b/test/tracehandoffcapcheck.sh @@ -47,6 +47,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" TMP="$( mktemp -d )"; trap 'rm -rf "$TMP"' EXIT diff --git a/test/w2verbscheck.sh b/test/w2verbscheck.sh index 284a8f642..f2c98b06f 100755 --- a/test/w2verbscheck.sh +++ b/test/w2verbscheck.sh @@ -38,6 +38,7 @@ set -u ROOT="$( cd "$( dirname "$0" )/.." && pwd )" +. "$ROOT/test/lib/clean-env.sh" BIN="${1:-${RIPWIRE_BIN:-$ROOT/build/ripwire}}" [ "${BIN#/}" = "$BIN" ] && BIN="$ROOT/$BIN" FIX="test/w2verbsfix"