#!/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 "== 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 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 $?)" 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 . fakeproc 4194403 /srv /bin/bash -c "source /home/u/.claude/shell-snapshots/snapshot-bash-1.sh && eval 'node --test x.test.mjs'" 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"; 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 rm -rf "${P:?}/4194420" 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 ]