← back to Nas Setup

scripts/test-backup-identity-guard.sh

76 lines

#!/usr/bin/env bash
# TK-11648 NEGATIVE TEST for backup-repos-to-henry.sh's identity guard.
# CLAUDE.md TK-11431 amendment 3: a positive-only test on a detector proves nothing —
# break it on purpose, watch it go red, put it back.
#
# The fault: a child dir with a present-but-INVALID .git makes `git bundle create --all`
# walk UP to the nearest valid parent repo and bundle THAT under the child's name — a
# VALID bundle (so `git bundle verify` passes) of the WRONG repo. This test injects that
# exact shape and asserts the guard FAILs it, and that a valid repo PASSes.
set -uo pipefail
T="$(mktemp -d /tmp/tk11648-XXXX)"
trap 'rm -rf "$T"' EXIT
fails=0

# --- fixture -----------------------------------------------------------------
# meta = a valid parent repo (mimics ~/Projects); child = hollow .git under it.
git init -q "$T/meta"; ( cd "$T/meta" && git -c user.email=t@t -c user.name=t commit -q --allow-empty -m meta )
mkdir -p "$T/meta/child/.git/refs" "$T/meta/child/.git/objects"   # hollow: no HEAD/config
# good = a valid standalone repo.
git init -q "$T/good"; ( cd "$T/good" && git -c user.email=t@t -c user.name=t commit -q --allow-empty -m good )

# the guard snippet, verbatim from backup-repos-to-henry.sh
guard() {  # $1 = repodir -> prints PASS|FAIL
  local repodir="$1" want top
  want="$(cd "$repodir" 2>/dev/null && pwd -P)"
  top="$(git -C "$repodir" rev-parse --show-toplevel 2>/dev/null)"
  if [ -z "$want" ] || [ -z "$top" ] || [ "$top" != "$want" ]; then echo "FAIL"; else echo "PASS"; fi
}

# --- prove the FAULT exists (what the guard defends against) ------------------
# Without the guard, `bundle create --all` on the hollow child succeeds by walking up:
if git -C "$T/meta/child" bundle create "$T/child.bundle" --all >/dev/null 2>&1 \
   && git bundle verify "$T/child.bundle" >/dev/null 2>&1; then
  bh="$(git bundle list-heads "$T/child.bundle" 2>/dev/null | head -1 | awk '{print $1}')"
  if git -C "$T/meta" cat-file -t "$bh" 2>/dev/null | grep -q commit; then
    echo "ok  : FAULT reproduced — hollow child bundled the PARENT repo (verify passed on the wrong repo)"
  else
    echo "FAIL: expected the hollow child to bundle the parent, but it did not"; fails=$((fails+1))
  fi
else
  echo "ok  : (this git refused to bundle the hollow child outright — also acceptable)"
fi

# --- the guard's verdicts -----------------------------------------------------
r_child="$(guard "$T/meta/child")"
r_good="$(guard "$T/good")"
[ "$r_child" = "FAIL" ] && echo "ok  : guard FAILs the hollow child (walk-up caught)" || { echo "FAIL: guard did NOT catch the hollow child (got $r_child)"; fails=$((fails+1)); }
[ "$r_good"  = "PASS" ] && echo "ok  : guard PASSes the valid standalone repo" || { echo "FAIL: guard wrongly rejected a valid repo (got $r_good)"; fails=$((fails+1)); }

# --- END-TO-END: drive the REAL script, not a copy of its guard ---------------
# TK-11431 amdt 3 ("applies to the test harness too"): the guard() checks above copy the
# snippet, so they stay green if the SHIPPED script's guard is reverted. This section runs
# backup-repos-to-henry.sh itself against a throwaway fixture via its BACKUP_TEST_MODE seam
# and proves the shipped code goes RED (writes no bundle) for the hollow child while still
# bundling the valid sibling.
SCRIPT="$(cd "$(dirname "$0")" && pwd)/backup-repos-to-henry.sh"
E="$(mktemp -d /tmp/tk11648-e2e-XXXX)"; trap 'rm -rf "$T" "$E"' EXIT
# fixture SRC is itself a valid repo (mimics ~/Projects meta-repo) so a hollow child walks up to it
git init -q "$E/src"; ( cd "$E/src" && git -c user.email=t@t -c user.name=t commit -q --allow-empty -m meta )
git init -q "$E/src/good"; ( cd "$E/src/good" && git -c user.email=t@t -c user.name=t commit -q --allow-empty -m good )
mkdir -p "$E/src/hollow/.git/refs" "$E/src/hollow/.git/objects"   # hollow: no HEAD/config
BACKUP_TEST_MODE=1 BACKUP_SRC="$E/src" BACKUP_DEST="$E/dest" BACKUP_HENRY="$E/henry" BACKUP_DATA="$E/dest" \
  bash "$SCRIPT" >"$E/out.txt" 2>&1
e2e_verdict="$(grep -o '"verdict":"[A-Z]*"' "$E/dest/repo-backup-latest.json" 2>/dev/null | head -1)"
[ -f "$E/dest/good.bundle" ]   && echo "ok  : real script bundled the valid sibling (good.bundle written)" || { echo "FAIL: real script did NOT bundle the valid sibling"; fails=$((fails+1)); }
[ ! -f "$E/dest/hollow.bundle" ] && echo "ok  : real script wrote NO hollow.bundle (walk-up mislabel prevented)" || { echo "FAIL: real script wrote hollow.bundle — the WRONG-repo mislabel"; fails=$((fails+1)); }
echo "$e2e_verdict" | grep -q 'WARN' && echo "ok  : real script reported WARN (a repo failed the guard)" || { echo "FAIL: real script verdict was not WARN (got ${e2e_verdict:-<none>})"; fails=$((fails+1)); }
# prove the seam did NOT touch the live heartbeat
if [ -f "$SCRIPT" ]; then
  live="$(cd "$(dirname "$SCRIPT")/.." && pwd)/data/repo-backup-latest.json"
  [ ! -e "$live" ] || ! grep -q "$E" "$live" 2>/dev/null && echo "ok  : live heartbeat untouched by the test seam" || { echo "FAIL: test seam wrote the fixture path into the live heartbeat"; fails=$((fails+1)); }
fi

echo "-------------------------------------------"
[ "$fails" -eq 0 ] && { echo "TK-11648 guard test: PASS"; exit 0; } || { echo "TK-11648 guard test: FAIL ($fails)"; exit 1; }