Files
stack/scripts/test-git-guard.sh
T

356 lines
19 KiB
Bash
Executable File

#!/usr/bin/env bash
# Sandboxed selftests for the push guard, its installer and the busy check
# (row 211, #426): scripts/git-hooks/pre-push, scripts/install-git-hooks.sh
# and scripts/slot-busy.sh.
#
# Pushes go from a scratch clone and its worktree to a scratch bare remote,
# never to origin. Git sees no user or system config. The busy check runs
# against a fake /proc (pids above pid_max) for the exit codes and rules, and
# against the real /proc with a sleeping stand-in whose argv is `node --test`.
set -uo pipefail
cd "$(dirname "$0")/.."
REPO="$(pwd)"
unset GIT_DIR GIT_WORK_TREE GIT_COMMON_DIR GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES
SANDBOX="$(cd "$(mktemp -d)" && pwd -P)"
STANDIN=""
cleanup() {
if [ -n "$STANDIN" ]; then kill "$STANDIN" 2>/dev/null; wait "$STANDIN" 2>/dev/null; fi
rm -rf "$SANDBOX"
}
trap cleanup EXIT
PASS=0
FAIL=0
# Status colors: terminal-only, NO_COLOR-respecting; plain when piped.
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
C_OK=$'\033[0;32m'; C_FAIL=$'\033[0;31m'; C_RESET=$'\033[0m'
else
C_OK=""; C_FAIL=""; C_RESET=""
fi
check() {
if [ "$2" = "0" ]; then PASS=$((PASS+1)); echo "${C_OK}OK${C_RESET} $1"; else FAIL=$((FAIL+1)); echo "${C_FAIL}FAIL${C_RESET} $1"; fi
}
has() { [[ "$1" == *"$2"* ]]; }
# Git sees no user or system config: no hooks path, no signing, a fixed identity.
: > "$SANDBOX/gitconfig"
export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL="$SANDBOX/gitconfig"
export GIT_AUTHOR_NAME=suite GIT_AUTHOR_EMAIL=suite@local GIT_COMMITTER_NAME=suite GIT_COMMITTER_EMAIL=suite@local
HOOK_SRC="$REPO/scripts/git-hooks/pre-push"
INSTALL="$REPO/scripts/install-git-hooks.sh"
BUSY="$REPO/scripts/slot-busy.sh"
B="$SANDBOX/remote.git"
C="$SANDBOX/clone"
W="$SANDBOX/wt"
O="$SANDBOX/other"
commit() { # $1: repo, $2: file and message
echo "$2" > "$1/$2" && git -C "$1" add "$2" && git -C "$1" commit -q -m "$2"
}
rtip() { git -C "$B" rev-parse -q --verify "refs/heads/$1"; }
# ---- the remote, a clone with the guard, a worktree ----
git init -q --bare -b main "$B"
git init -q -b main "$SANDBOX/seed"
commit "$SANDBOX/seed" base
git -C "$SANDBOX/seed" push -q "$B" main
git clone -q "$B" "$C"
echo "== install =="
out=$(bash "$INSTALL" --repo "$C" 2>&1); rc=$?
check "the install into a clean clone exits 0" "$rc"
check "it reports the install and a passed canary" "$(has "$out" "ok installed the push guard" && has "$out" "canary passed"; echo $?)"
check "the hook is in the common .git/hooks, with the repository's bytes, executable" \
"$(cmp -s "$HOOK_SRC" "$C/.git/hooks/pre-push" && [ -x "$C/.git/hooks/pre-push" ]; echo $?)"
check "no temporary file is left in .git/hooks" \
"$(ls -A "$C/.git/hooks" | grep -q '^\.pre-push\.install'; [ $? = 1 ]; echo $?)"
git -C "$C" worktree add -q -b seat/w "$W" origin/main
check "the worktree's git runs the common hook" \
"$([ "$(git -C "$W" rev-parse --path-format=absolute --git-path hooks/pre-push)" = "$C/.git/hooks/pre-push" ]; echo $?)"
echo "== pushes from the worktree =="
commit "$W" one
out=$(git -C "$W" push origin seat/w 2>&1); rc=$?
check "a new branch passes" "$rc"
check "the remote branch is at the pushed commit" "$([ "$(rtip seat/w)" = "$(git -C "$W" rev-parse HEAD)" ]; echo $?)"
commit "$W" two
out=$(git -C "$W" push origin seat/w 2>&1); rc=$?
check "a fast-forward passes" "$rc"
check "the remote branch moved forward" "$([ "$(rtip seat/w)" = "$(git -C "$W" rev-parse HEAD)" ]; echo $?)"
before=$(rtip seat/w)
git -C "$W" reset -q --hard HEAD~1
commit "$W" two-rewritten
after=$(git -C "$W" rev-parse HEAD)
out=$(git -C "$W" push --force origin seat/w 2>&1); rc=$?
check "push --force of a rewritten branch is refused" "$([ "$rc" -ne 0 ]; echo $?)"
check "the refusal is the guard's, and names the ref and both shas" \
"$(has "$out" "mosaic push guard: refused: refs/heads/seat/w: not a fast-forward" && has "$out" "$before" && has "$out" "$after"; echo $?)"
check "the remote ref is unchanged after the refused --force" "$([ "$(rtip seat/w)" = "$before" ]; echo $?)"
out=$(git -C "$W" push origin +seat/w:seat/w 2>&1); rc=$?
check "a +refspec push is refused" "$([ "$rc" -ne 0 ] && has "$out" "not a fast-forward"; echo $?)"
check "the remote ref is unchanged after the refused +refspec" "$([ "$(rtip seat/w)" = "$before" ]; echo $?)"
out=$(git -C "$W" push --force-with-lease origin seat/w 2>&1); rc=$?
check "push --force-with-lease is refused too" "$([ "$rc" -ne 0 ] && has "$out" "not a fast-forward"; echo $?)"
out=$(git -C "$W" push origin :seat/w 2>&1); rc=$?
check "a delete (:ref) is refused" "$([ "$rc" -ne 0 ] && has "$out" "mosaic push guard: refused: refs/heads/seat/w: a delete"; echo $?)"
out=$(git -C "$W" push --delete origin seat/w 2>&1); rc=$?
check "a delete (--delete) is refused" "$([ "$rc" -ne 0 ] && has "$out" "a delete"; echo $?)"
check "the remote branch still exists after the refused deletes" "$([ "$(rtip seat/w)" = "$before" ]; echo $?)"
# Another clone moves the remote; this clone never fetches it.
git clone -q -b seat/w "$B" "$O"
commit "$O" from-other
git -C "$O" push -q origin seat/w
moved=$(rtip seat/w)
check "the other clone moved the remote, and this clone lacks that commit" \
"$([ "$moved" != "$before" ] && ! git -C "$C" cat-file -e "$moved^{commit}" 2>/dev/null; echo $?)"
out=$(git -C "$W" push --force origin seat/w 2>&1); rc=$?
check "a push over a remote tip missing locally is refused, saying fetch first" \
"$([ "$rc" -ne 0 ] && has "$out" "isn't in this repository; fetch first"; echo $?)"
check "the remote ref is unchanged after that refusal" "$([ "$(rtip seat/w)" = "$moved" ]; echo $?)"
check "the guard fetched nothing" "$(! git -C "$C" cat-file -e "$moved^{commit}" 2>/dev/null; echo $?)"
echo "== tags =="
# An existing tag never changes. Both cases below pass the ancestor check: a
# new tag object on the same commit peels to that commit, and a moved
# lightweight tag's old commit is an ancestor of its new one.
tagtip() { git -C "$B" rev-parse -q --verify "refs/tags/$1"; }
git -C "$W" tag -a -m first t-ann HEAD
out=$(git -C "$W" push origin t-ann 2>&1); rc=$?
check "a new annotated tag passes" "$([ "$rc" = 0 ] && [ "$(tagtip t-ann)" = "$(git -C "$W" rev-parse t-ann)" ]; echo $?)"
first=$(tagtip t-ann)
git -C "$W" tag -f -a -m second t-ann HEAD >/dev/null
out=$(git -C "$W" push --force origin t-ann 2>&1); rc=$?
check "push --force of a new tag object on the same commit is refused" \
"$([ "$rc" -ne 0 ] && has "$out" "mosaic push guard: refused: refs/tags/t-ann: an existing tag" && has "$out" "$first"; echo $?)"
check "the remote tag is still the first tag object" "$([ "$(tagtip t-ann)" = "$first" ]; echo $?)"
git -C "$W" tag t-light HEAD~1
out=$(git -C "$W" push origin t-light 2>&1); rc=$?
check "a new lightweight tag passes" "$rc"
git -C "$W" tag -f t-light HEAD >/dev/null
out=$(git -C "$W" push --force origin t-light 2>&1); rc=$?
check "push --force of a lightweight tag moved to a descendant is refused" \
"$([ "$rc" -ne 0 ] && has "$out" "mosaic push guard: refused: refs/tags/t-light: an existing tag"; echo $?)"
check "the remote lightweight tag hasn't moved" "$([ "$(tagtip t-light)" = "$(git -C "$W" rev-parse HEAD~1)" ]; echo $?)"
out=$(git -C "$W" push origin :refs/tags/t-light 2>&1); rc=$?
check "a tag delete is refused, and the tag stays" \
"$([ "$rc" -ne 0 ] && has "$out" "refs/tags/t-light: a delete" && [ -n "$(tagtip t-light)" ]; echo $?)"
echo "== the hook, fed by hand =="
z=0000000000000000000000000000000000000000
hookrun() { (cd "$C" && printf '%s\n' "$1" | sh "$C/.git/hooks/pre-push" origin "$B" 2>&1); }
out=$(hookrun "refs/heads/x $(git -C "$C" rev-parse HEAD) refs/heads/x"); rc=$?
check "a short ref line is refused" "$([ "$rc" -ne 0 ] && has "$out" "unreadable ref line"; echo $?)"
out=$(hookrun "refs/heads/x HEAD refs/heads/x $z"); rc=$?
check "a non-hex object name is refused" "$([ "$rc" -ne 0 ] && has "$out" "non-hex"; echo $?)"
out=$(hookrun "refs/heads/x $(git -C "$C" rev-parse HEAD) refs/heads/x 0"); rc=$?
check "a remote object name of 0 is refused, not read as a new ref" \
"$([ "$rc" -ne 0 ] && has "$out" "isn't 40 or 64 hex characters"; echo $?)"
out=$(hookrun "refs/heads/x $(git -C "$C" rev-parse HEAD | cut -c1-39) refs/heads/x $z"); rc=$?
check "a 39-character local object name is refused" "$([ "$rc" -ne 0 ] && has "$out" "isn't 40 or 64 hex characters"; echo $?)"
out=$(hookrun "refs/heads/x ${z}${z:0:24} refs/heads/x $(git -C "$C" rev-parse HEAD)"); rc=$?
check "a 64-character object name passes the length check (64 zeros refuse as a delete)" \
"$([ "$rc" -ne 0 ] && has "$out" "refs/heads/x: a delete" && ! has "$out" "isn't 40 or 64"; echo $?)"
out=$(hookrun "refs/heads/x 1234567890123456789012345678901234567890 refs/heads/x $(git -C "$C" rev-parse HEAD)"); rc=$?
check "a failed ancestor check (an unknown local object) is refused" \
"$([ "$rc" -ne 0 ] && has "$out" "the ancestor check failed"; echo $?)"
out=$(printf '' | (cd "$C" && sh "$C/.git/hooks/pre-push" origin "$B" 2>&1)); rc=$?
check "an empty push passes" "$rc"
echo "== installer refusals =="
fresh() { rm -rf "$1"; git clone -q "$B" "$1"; }
fresh "$SANDBOX/hp"
git -C "$SANDBOX/hp" config core.hooksPath .husky
out=$(bash "$INSTALL" --repo "$SANDBOX/hp" 2>&1); rc=$?
check "the install refuses with core.hooksPath set (exit 2)" "$([ "$rc" = 2 ]; echo $?)"
check "it says core.hooksPath is set" "$(has "$out" "core.hooksPath is set"; echo $?)"
check "no hook was written under the hooksPath refusal" \
"$([ ! -e "$SANDBOX/hp/.git/hooks/pre-push" ] && [ ! -e "$SANDBOX/hp/.husky/pre-push" ]; echo $?)"
fresh "$SANDBOX/df"
printf '#!/bin/sh\nexit 0\n' > "$SANDBOX/df/.git/hooks/pre-push"
chmod 0755 "$SANDBOX/df/.git/hooks/pre-push"
ln "$SANDBOX/df/.git/hooks/pre-push" "$SANDBOX/df-old"
out=$(bash "$INSTALL" --repo "$SANDBOX/df" 2>&1); rc=$?
check "the install refuses a different installed pre-push (exit 2)" \
"$([ "$rc" = 2 ] && has "$out" "a different pre-push hook is installed"; echo $?)"
check "the different hook is untouched" \
"$([ "$(cat "$SANDBOX/df/.git/hooks/pre-push")" = "$(printf '#!/bin/sh\nexit 0')" ]; echo $?)"
out=$(bash "$INSTALL" --repo "$SANDBOX/df" --force-install 2>&1); rc=$?
check "--force-install replaces it" \
"$([ "$rc" = 0 ] && has "$out" "replaced a different hook" && cmp -s "$HOOK_SRC" "$SANDBOX/df/.git/hooks/pre-push"; echo $?)"
check "the replacement was a rename: the old file keeps its bytes" \
"$([ "$(cat "$SANDBOX/df-old")" = "$(printf '#!/bin/sh\nexit 0')" ]; echo $?)"
out=$(bash "$INSTALL" --repo "$SANDBOX/df" 2>&1); rc=$?
check "a second install over the same bytes exits 0" "$([ "$rc" = 0 ] && has "$out" "the same bytes"; echo $?)"
fresh "$SANDBOX/ln"
ln -s /dev/null "$SANDBOX/ln/.git/hooks/pre-push"
out=$(bash "$INSTALL" --repo "$SANDBOX/ln" --force-install 2>&1); rc=$?
check "the install refuses a symlinked pre-push, even with --force-install" "$([ "$rc" = 2 ] && has "$out" "is a symlink"; echo $?)"
# A hooks directory that links to a shared one would put the hook outside
# the repository, in every repository that shares it.
fresh "$SANDBOX/sl"
mkdir -p "$SANDBOX/shared-hooks"
rm -rf "$SANDBOX/sl/.git/hooks"
ln -s "$SANDBOX/shared-hooks" "$SANDBOX/sl/.git/hooks"
out=$(bash "$INSTALL" --repo "$SANDBOX/sl" 2>&1); rc=$?
check "the install refuses a symlinked hooks directory (exit 2)" "$([ "$rc" = 2 ] && has "$out" "/.git/hooks is a symlink"; echo $?)"
out=$(bash "$INSTALL" --repo "$SANDBOX/sl" --force-install 2>&1); rc=$?
check "it refuses it with --force-install too" "$([ "$rc" = 2 ] && has "$out" "/.git/hooks is a symlink"; echo $?)"
check "nothing was written in the directory the symlink names" "$([ -z "$(ls -A "$SANDBOX/shared-hooks")" ]; echo $?)"
fresh "$SANDBOX/wd"
git -C "$SANDBOX/wd" worktree add -q -b seat/x "$SANDBOX/wd-wt" origin/main
out=$(bash "$INSTALL" --repo "$SANDBOX/wd-wt" 2>&1); rc=$?
check "an install named by a worktree path lands in the common .git/hooks" \
"$([ "$rc" = 0 ] && cmp -s "$HOOK_SRC" "$SANDBOX/wd/.git/hooks/pre-push"; echo $?)"
out=$(GIT_DIR="$SANDBOX/wd/.git" bash "$INSTALL" --repo "$SANDBOX/wd" 2>&1); rc=$?
check "the install refuses with GIT_DIR set" "$([ "$rc" = 2 ] && has "$out" "GIT_DIR is set"; echo $?)"
mkdir -p "$SANDBOX/plain"
out=$(bash "$INSTALL" --repo "$SANDBOX/plain" 2>&1); rc=$?
check "the install refuses a directory that isn't a checkout" "$([ "$rc" = 2 ]; echo $?)"
out=$(bash "$INSTALL" --nope 2>&1); rc=$?
check "an unknown argument exits 4" "$([ "$rc" = 4 ]; echo $?)"
echo "== slot-busy, fake /proc =="
P="$SANDBOX/proc"
fakeproc() { # $1: pid, $2: cwd, rest: argv
local pid=$1 cwd=$2; shift 2
mkdir -p "$P/$pid"
printf '%s\0' "$@" > "$P/$pid/cmdline"
ln -sfn "$cwd" "$P/$pid/cwd"
}
busyrun() { bash "$BUSY" --proc-root "$P" 2>&1; }
fakeproc 4194401 /srv node server.mjs
fakeproc 4194402 /srv grep -r gate .
# Both wrappers' text would match a rule without the snapshot exclusion.
fakeproc 4194403 /srv /bin/bash -c "source /home/u/.claude/shell-snapshots/snapshot-bash-1.sh && node --test x.test.mjs"
fakeproc 4194405 /srv /usr/bin/bash -c "source /home/u/.claude/shell-snapshots/snapshot-bash-2-ab.sh 2>/dev/null || true && eval 'bash scripts/test-x.sh > x.log' && pwd -P >| /home/u/cwd"
mkdir -p "$P/4194404"; : > "$P/4194404/cmdline"
out=$(busyrun); rc=$?
check "no matching process: exit 0 and CLEAR" "$([ "$rc" = 0 ] && [ "$out" = CLEAR ]; echo $?)"
check "an agent's shell-snapshot wrapper isn't a match" "$(! has "$out" "4194403" && ! has "$out" "4194405"; echo $?)"
fakeproc 4194410 /seat/a node --test packages/x/tests/a.test.mjs
out=$(busyrun); rc=$?
check "a node --test process: exit 1" "$([ "$rc" = 1 ]; echo $?)"
check "its BUSY line names pid, rule and cwd" "$(has "$out" "BUSY 4194410 node --test cwd=/seat/a node --test"; echo $?)"
check "BUSY output never says CLEAR" "$(! has "$out" "CLEAR"; echo $?)"
ran=$(bash "$BUSY" --proc-root "$P" >/dev/null && echo ran)
check "\`slot-busy > LOG && step\` doesn't run the step while BUSY" "$([ -z "$ran" ]; echo $?)"
rm -rf "${P:?}/4194410"
rule() { # $1: expected rule, rest: argv
local want=$1; shift
rm -rf "${P:?}/4194420"; fakeproc 4194420 /seat/b "$@"
out=$(busyrun); rc=$?
check "busy on: $* ($want)" "$([ "$rc" = 1 ] && has "$out" "BUSY 4194420 $want "; echo $?)"
}
rule "node --test" /usr/bin/node --experimental-strip-types --test a.test.ts
rule "gate" bash /mnt/scratch/sage-gate.sh 253
rule "gate" bash ./gate.sh
rule "mutant" bash agents/x/work/queue-1/mutants.sh M3
rule "test script" bash scripts/test-land-work.sh
rule "docker compose" docker compose -p x up -d
rule "docker compose" /usr/bin/docker-compose up
# The snapshot exclusion is for the wrapper's shape only: the same command
# without the snapshot source, and real runs whose arguments hold the path.
rule "node --test" /bin/bash -c "node --test x.test.mjs"
rule "node --test" node --test /seat/tests/shell-snapshots/snapshot-guard.test.mjs
rule "gate" bash /seat/shell-snapshots/snapshot-gate.sh
rm -rf "${P:?}/4194420"
echo "== slot-busy, read errors =="
# A pid directory that stays while its cmdline can't be read is an error,
# never a vanished process: exit 2 and no CLEAR.
mkdir -p "$P/4194430"
out=$(busyrun); rc=$?
check "a pid directory with no cmdline: exit 2" "$([ "$rc" = 2 ]; echo $?)"
check "it names that cmdline and never says CLEAR" "$(has "$out" "cannot read $P/4194430/cmdline" && ! has "$out" CLEAR; echo $?)"
rm -rf "${P:?}/4194430"
mkdir -p "$P/4194431/cmdline"
out=$(busyrun); rc=$?
check "a cmdline that can't be read (a directory): exit 2, no CLEAR" "$([ "$rc" = 2 ] && ! has "$out" CLEAR; echo $?)"
fakeproc 4194410 /seat/a node --test a.test.mjs
out=$(busyrun); rc=$?
check "a read error beside a BUSY process: exit 2, the BUSY line kept, no CLEAR" \
"$([ "$rc" = 2 ] && has "$out" "BUSY 4194410 node --test" && ! has "$out" CLEAR; echo $?)"
rm -rf "${P:?}/4194431"
chmod 000 "$P/4194410/cmdline"
out=$(busyrun); rc=$?
check "a node --test process whose cmdline is unreadable (mode 000) is never CLEAR" "$([ "$rc" != 0 ] && ! has "$out" CLEAR; echo $?)"
rm -rf "${P:?}/4194410"
mkdir -p "$SANDBOX/failtr" "$SANDBOX/vanishtr" "$SANDBOX/failawk"
printf '#!/bin/sh\nexit 1\n' > "$SANDBOX/failtr/tr"
printf '#!/bin/sh\nexit 1\n' > "$SANDBOX/failawk/awk"
# This tr stands in for a process that exits during the read: for pid
# 4194440 it removes the pid directory and fails; otherwise it is tr.
cat > "$SANDBOX/vanishtr/tr" <<EOF
#!/bin/sh
f=\$(readlink "/proc/\$\$/fd/0")
case "\$f" in */4194440/cmdline) rm -rf "\${f%/cmdline}"; exit 1 ;; esac
exec $(command -v tr) "\$@"
EOF
chmod +x "$SANDBOX/failtr/tr" "$SANDBOX/failawk/awk" "$SANDBOX/vanishtr/tr"
out=$(PATH="$SANDBOX/failtr:$PATH" bash "$BUSY" --proc-root "$P" 2>&1); rc=$?
check "a failing read (tr exits 1) with every pid directory still there: exit 2, no CLEAR" \
"$([ "$rc" = 2 ] && has "$out" "cannot read" && ! has "$out" CLEAR; echo $?)"
fakeproc 4194440 /seat/v node --test v.test.mjs
out=$(PATH="$SANDBOX/vanishtr:$PATH" bash "$BUSY" --proc-root "$P" 2>&1); rc=$?
check "a process that vanishes during its read isn't an error: exit 0 and CLEAR" \
"$([ "$rc" = 0 ] && [ "$out" = CLEAR ] && [ ! -e "$P/4194440" ]; echo $?)"
rm -rf "${P:?}/4194440"
out=$(PATH="$SANDBOX/failawk:$PATH" bash "$BUSY" --proc-root "$P" 2>&1); rc=$?
check "its own process unreadable (awk exits 1): exit 2, no CLEAR" \
"$([ "$rc" = 2 ] && has "$out" "cannot read its own process" && ! has "$out" CLEAR; echo $?)"
out=$(bash "$BUSY" --proc-root "$SANDBOX/no-such-proc" 2>&1); rc=$?
check "a missing proc root: exit 2" "$([ "$rc" = 2 ]; echo $?)"
mkdir -p "$SANDBOX/empty-proc"
out=$(bash "$BUSY" --proc-root "$SANDBOX/empty-proc" 2>&1); rc=$?
check "a proc root with no processes: exit 2" "$([ "$rc" = 2 ]; echo $?)"
out=$(bash "$BUSY" --nope 2>&1); rc=$?
check "an unknown argument: exit 2" "$([ "$rc" = 2 ]; echo $?)"
echo "== slot-busy, real /proc =="
mkdir -p "$SANDBOX/bin" "$SANDBOX/standin"
cat > "$SANDBOX/bin/node" <<'EOF'
#!/bin/sh
trap 'exit 0' TERM
while :; do sleep 0.2; done
EOF
chmod +x "$SANDBOX/bin/node"
(cd "$SANDBOX/standin" && exec "$SANDBOX/bin/node" --test standin.test.mjs) &
STANDIN=$!
for _ in $(seq 50); do
has "$(tr '\0' ' ' < "/proc/$STANDIN/cmdline" 2>/dev/null)" "--test standin" && break
sleep 0.1
done
out=$(bash "$BUSY" 2>&1); rc=$?
check "with a stand-in node --test running: exit 1" "$([ "$rc" = 1 ]; echo $?)"
check "the stand-in has a BUSY line with its cwd" \
"$(printf '%s\n' "$out" | grep -q "^BUSY $STANDIN node --test cwd=$SANDBOX/standin "; echo $?)"
check "this suite, an ancestor, has no BUSY line" "$(! printf '%s\n' "$out" | grep -q "^BUSY $$ "; echo $?)"
ran=$(bash "$BUSY" >/dev/null && echo ran)
check "\`slot-busy > LOG && step\` doesn't run the step with the stand-in up" "$([ -z "$ran" ]; echo $?)"
kill "$STANDIN" 2>/dev/null; wait "$STANDIN" 2>/dev/null
gone=$STANDIN; STANDIN=""
out=$(bash "$BUSY" 2>&1); rc=$?
check "after the stand-in exits, it has no BUSY line" "$(! printf '%s\n' "$out" | grep -q "^BUSY $gone "; echo $?)"
check "the real-/proc run exits 0 or 1, never 2" "$([ "$rc" = 0 ] || [ "$rc" = 1 ]; echo $?)"
echo "---"
echo "git-guard selftests: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ]