97a9379f79
improvise-cota, found in the delta review of #244. The tdfd fix skipped an
absent tracked path whenever `ls-files -d` listed it. `ls-files -d` also
lists an absent --assume-unchanged path. `status` hides that path, and
`commit -a` never records the deletion, so its citations stayed in HEAD
unread and the audit exited 0.
The deletion oracle is now `diff --name-only --diff-filter=D`. It honours
both index flags and still lists a plain unstaged delete.
The new case in bd-audit-ids-test.sh was red at 33d563a9. A rival that
treats every absent path as unread fails only the deliberate
deleted-file control.
Stacked on #244 (tooling/lqs0-audit-exits).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
166 lines
7.0 KiB
Bash
Executable File
166 lines
7.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# check_the_checker for scripts/bd-audit-ids. A throwaway git repo and a fake
|
|
# bd; no network, no real tracker. See context/test-evidence/tooling.md.
|
|
set -uo pipefail
|
|
|
|
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
AUDIT="$here/bd-audit-ids"
|
|
work="$(mktemp -d)"
|
|
trap 'rm -rf "$work"' EXIT
|
|
|
|
pass=0; fail=0
|
|
ok() { printf ' ok %s\n' "$1"; pass=$((pass+1)); }
|
|
bad() { printf ' FAIL %s (%s)\n' "$1" "$2"; fail=$((fail+1)); }
|
|
|
|
# The fake bd answers `list` from $FAKE_BD_OUT and exits $FAKE_BD_RC; any
|
|
# other subcommand is an error, so the audit cannot pass by calling `show`.
|
|
mkdir -p "$work/bin"
|
|
cat > "$work/bin/bd" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
[ "${1:-}" = list ] || { echo "fake bd: unexpected '$*'" >&2; exit 2; }
|
|
[ -f "${FAKE_BD_OUT:-}" ] && cat "$FAKE_BD_OUT"
|
|
exit "${FAKE_BD_RC:-0}"
|
|
EOF
|
|
chmod +x "$work/bin/bd"
|
|
|
|
repo="$work/repo"
|
|
mkdir -p "$repo/context" "$repo/harness/serve"
|
|
git -C "$repo" init -q
|
|
printf 'serve/\n' > "$repo/harness/.gitignore"
|
|
# A live id, and a crate name the exclusion list must drop: without the
|
|
# exclusion, improvise-core would be reported dead and the first case fails.
|
|
printf 'See improvise-ab12 in improvise-core.\n' > "$repo/context/notes.md"
|
|
# Ignored build output with a dead id. The audit reads git's file list, so
|
|
# this must never be reported (improvise-8haj).
|
|
printf 'improvise-gone9\n' > "$repo/harness/serve/copy.md"
|
|
|
|
printf '[{"id":"improvise-ab12"},{"id":"improvise-cd34"}]\n' > "$work/known.json"
|
|
printf '' > "$work/empty"
|
|
printf '[]\n' > "$work/none.json"
|
|
|
|
# $1 name, $2 expected exit, $3 grep -E pattern the output must contain;
|
|
# the caller sets FAKE_BD_* and BD_AUDIT_BD in the environment.
|
|
run_case() {
|
|
local name="$1" want="$2" pat="$3"
|
|
(cd "$repo" && "$AUDIT") > "$work/out" 2>&1
|
|
local got=$?
|
|
if [ "$got" != "$want" ]; then bad "$name" "exit $got, wanted $want: $(head -c 200 "$work/out")"
|
|
elif ! grep -Eq "$pat" "$work/out"; then bad "$name" "no /$pat/ in: $(head -c 200 "$work/out")"
|
|
else ok "$name"; fi
|
|
}
|
|
|
|
export BD_AUDIT_BD="$work/bin/bd"
|
|
|
|
FAKE_BD_OUT="$work/known.json" FAKE_BD_RC=0 \
|
|
run_case "every cited id known is a pass" 0 'all 1 cited ids resolve'
|
|
|
|
printf 'Also improvise-zzzq.\n' > "$repo/context/dead.md"
|
|
FAKE_BD_OUT="$work/known.json" FAKE_BD_RC=0 \
|
|
run_case "a dead id is exit 1, and named" 1 '^ improvise-zzzq$'
|
|
rm -f "$repo/context/dead.md"
|
|
|
|
# The three shapes of "bd never answered". The recipe this replaced reported
|
|
# "all resolve" for every one of them (improvise-52eq).
|
|
FAKE_BD_OUT="$work/empty" FAKE_BD_RC=0 \
|
|
run_case "a bd that prints nothing is not a pass" 3 'did not print a JSON list|returned no issues'
|
|
FAKE_BD_OUT="$work/none.json" FAKE_BD_RC=0 \
|
|
run_case "a bd that lists no issues is not a pass" 3 'returned no issues'
|
|
FAKE_BD_OUT="$work/known.json" FAKE_BD_RC=1 \
|
|
run_case "a bd that fails is not a pass" 3 'list. failed'
|
|
BD_AUDIT_BD="$work/bin/no-such-bd" \
|
|
run_case "a missing bd is not a pass" 3 'is not on PATH'
|
|
|
|
# The live repo, with the fake bd listing nothing: if this passed, a real
|
|
# audit whose bd fell silent would pass too.
|
|
(cd "$here/.." && FAKE_BD_OUT="$work/none.json" "$AUDIT") > "$work/out" 2>&1
|
|
got=$?
|
|
[ "$got" = 3 ] && ok "the real tree does not pass against a silent bd" \
|
|
|| bad "the real tree does not pass against a silent bd" "exit $got"
|
|
|
|
# improvise-lqs0: a file the scan cannot read, and the two exit-code mismatches.
|
|
# A second repo, so the file list is exactly these cases' files.
|
|
r2="$work/repo2"
|
|
mkdir -p "$r2/context"
|
|
git -C "$r2" init -q
|
|
printf 'improvise-ab12\n' > "$r2/context/a.md"
|
|
printf 'improvise-dead9\n' > "$r2/context/b.md"
|
|
git -C "$r2" add -A
|
|
git -C "$r2" -c user.name=t -c user.email=t@t commit -qm fixture
|
|
export FAKE_BD_OUT="$work/known.json" FAKE_BD_RC=0
|
|
|
|
(cd "$r2" && "$AUDIT") > "$work/out" 2>&1
|
|
got=$?
|
|
[ "$got" = 1 ] && grep -q 'improvise-dead9' "$work/out" \
|
|
&& ok "control: both files readable, the dead id is found" \
|
|
|| bad "control: both files readable, the dead id is found" "exit $got"
|
|
|
|
# A symlink whose target is gone reads as an error for any user, root included.
|
|
ln -s missing-target "$r2/context/c.md"
|
|
(cd "$r2" && "$AUDIT") > "$work/out" 2>&1
|
|
got=$?
|
|
[ "$got" = 4 ] && ok "a cited file grep cannot read is exit 4, not a pass" \
|
|
|| bad "a cited file grep cannot read is exit 4, not a pass" "exit $got: $(head -c 200 "$work/out")"
|
|
rm -f "$r2/context/c.md"
|
|
|
|
if [ "$(id -u)" != 0 ]; then
|
|
chmod 000 "$r2/context/b.md"
|
|
(cd "$r2" && "$AUDIT") > "$work/out" 2>&1
|
|
got=$?
|
|
chmod 644 "$r2/context/b.md"
|
|
[ "$got" = 4 ] && ok "an unreadable cited file is exit 4, not a pass" \
|
|
|| bad "an unreadable cited file is exit 4, not a pass" "exit $got: $(head -c 200 "$work/out")"
|
|
fi
|
|
|
|
# Decided, not accidental: a tracked file deleted from the working tree is not
|
|
# scanned. Its ids are leaving the tree, so its dead id is not reported.
|
|
mv "$r2/context/b.md" "$work/b.md.away"
|
|
(cd "$r2" && "$AUDIT") > "$work/out" 2>&1
|
|
got=$?
|
|
mv "$work/b.md.away" "$r2/context/b.md"
|
|
[ "$got" = 0 ] && ok "a tracked file deleted from the working tree is not scanned" \
|
|
|| bad "a tracked file deleted from the working tree is not scanned" "exit $got: $(head -c 200 "$work/out")"
|
|
|
|
# Absent is not deleted: a skip-worktree path is missing too, but ls-files -d
|
|
# does not list it, so its ids were never read (improvise-tdfd).
|
|
git -C "$r2" update-index --skip-worktree context/b.md
|
|
mv "$r2/context/b.md" "$work/b.md.away"
|
|
(cd "$r2" && "$AUDIT") > "$work/out" 2>&1
|
|
got=$?
|
|
mv "$work/b.md.away" "$r2/context/b.md"
|
|
git -C "$r2" update-index --no-skip-worktree context/b.md
|
|
[ "$got" = 4 ] && grep -q 'context/b.md' "$work/out" \
|
|
&& ok "a skip-worktree file missing from the tree is exit 4, and named" \
|
|
|| bad "a skip-worktree file missing from the tree is exit 4, and named" "exit $got: $(head -c 200 "$work/out")"
|
|
|
|
# ls-files -d DOES list an absent assume-unchanged path, yet status hides it and
|
|
# commit -a never records the deletion (improvise-cota).
|
|
git -C "$r2" update-index --assume-unchanged context/b.md
|
|
mv "$r2/context/b.md" "$work/b.md.away"
|
|
(cd "$r2" && "$AUDIT") > "$work/out" 2>&1
|
|
got=$?
|
|
mv "$work/b.md.away" "$r2/context/b.md"
|
|
git -C "$r2" update-index --no-assume-unchanged context/b.md
|
|
[ "$got" = 4 ] && grep -q 'context/b.md' "$work/out" \
|
|
&& ok "an assume-unchanged file missing from the tree is exit 4, and named" \
|
|
|| bad "an assume-unchanged file missing from the tree is exit 4, and named" "exit $got: $(head -c 200 "$work/out")"
|
|
|
|
mkdir -p "$work/not-a-repo"
|
|
(cd "$work/not-a-repo" && GIT_CEILING_DIRECTORIES="$work" "$AUDIT") > "$work/out" 2>&1
|
|
got=$?
|
|
[ "$got" = 4 ] && ok "run outside a git repository is exit 4" \
|
|
|| bad "run outside a git repository is exit 4" "exit $got"
|
|
|
|
printf '[{"title":"no id here"}]\n' > "$work/noid.json"
|
|
FAKE_BD_OUT="$work/noid.json" \
|
|
run_case "a bd listing issues with no id is exit 3, not every id dead" 3 'did not print'
|
|
unset FAKE_BD_OUT FAKE_BD_RC
|
|
|
|
"$AUDIT" --help > "$work/out" 2>&1
|
|
got=$?
|
|
[ "$got" = 4 ] && grep -q 'POSITIVE' "$work/out" \
|
|
&& ok "--help is exit 4 and states the positive comparison" \
|
|
|| bad "--help is exit 4 and states the positive comparison" "exit $got"
|
|
|
|
printf '\nbd-audit-ids-test: %d passed, %d failed\n' "$pass" "$fail"
|
|
[ "$fail" -eq 0 ]
|