← back to George Gmail

test-keeplist-failclosed.sh

46 lines

#!/usr/bin/env bash
# test-keeplist-failclosed.sh — prove delete-old-drafts-info.js FAILS CLOSED when
# its keep-list cannot be loaded (TK-11552).
#
# Why this test exists: the loader used to be `catch (_) { return {} }`, i.e. it
# failed OPEN — a corrupted or deleted keep-list silently meant "nothing is
# exempt" and the next run PERMANENTLY deleted (no Trash) every draft the
# keep-list existed to protect. A positive-only test would never catch that.
#
# SAFETY: the script under test is copied into a throwaway dir (so it reads that
# dir's empty//broken data/, never the real keep-list) AND pointed at a dead
# GEORGE_BASE port. So even if the abort FAILED, there is no reachable mailbox
# to delete from. Nothing here can touch real drafts.
set -u
SRC="$(cd "$(dirname "$0")" && pwd)/delete-old-drafts-info.js"
DEAD_GEORGE="http://127.0.0.1:9"   # discard port: never serves
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
mkdir -p "$TMP/data"; cp "$SRC" "$TMP/"
fails=0
check() { # name expect_abort expect_exit
  local name="$1" want_abort="$2"
  local out rc
  # `env` so the conditional CONFIRM=1 is a real assignment, not a command word.
  out="$(cd "$TMP" && env GEORGE_BASE="$DEAD_GEORGE" ${CONFIRM_ENV:+CONFIRM=1} timeout 25 node delete-old-drafts-info.js 2>&1)"; rc=$?
  local aborted=no; grep -q "ABORT:" <<<"$out" && aborted=yes
  # Guard the HARNESS: rc=127 means the command never ran, which would otherwise
  # read as a clean "did not abort" pass. A test that cannot run is not a pass.
  if [ "$rc" -eq 127 ]; then echo "  FAIL  $name (HARNESS BROKEN: rc=127, command never ran)"; echo "$out" | head -3 | sed 's/^/        /'; fails=$((fails+1)); return; fi
  if [ "$aborted" = "$want_abort" ]; then echo "  PASS  $name (aborted=$aborted rc=$rc)"
  else echo "  FAIL  $name (aborted=$aborted want=$want_abort rc=$rc)"; echo "$out" | head -4 | sed 's/^/        /'; fails=$((fails+1)); fi
}
echo "NEGATIVE TEST — keep-list fail-closed (isolated copy, dead George):"
# A: keep-list MISSING, real run -> must ABORT
rm -f "$TMP/data/drain-keep-list.json"; CONFIRM_ENV=1 check "A missing keep-list + CONFIRM=1 -> ABORT" yes
# B: keep-list CORRUPT, real run -> must ABORT
echo '{ this is not json' > "$TMP/data/drain-keep-list.json"; CONFIRM_ENV=1 check "B corrupt keep-list + CONFIRM=1 -> ABORT" yes
# C: keep-list is a JSON ARRAY (wrong shape) -> must ABORT
echo '["1a002b133c517293"]' > "$TMP/data/drain-keep-list.json"; CONFIRM_ENV=1 check "C wrong-shape keep-list + CONFIRM=1 -> ABORT" yes
# D: explicit empty object = deliberate "nothing exempt" -> must NOT abort
echo '{}' > "$TMP/data/drain-keep-list.json"; CONFIRM_ENV=1 check "D explicit {} + CONFIRM=1 -> proceeds (no abort)" no
# E: missing keep-list but DRY RUN -> warn only, no abort
rm -f "$TMP/data/drain-keep-list.json"; CONFIRM_ENV= check "E missing keep-list + dry run -> warn, no abort" no
echo ""
[ "$fails" -eq 0 ] && { echo "FAIL-CLOSED TEST PASSED — an unloadable keep-list can no longer silently permit deletion."; exit 0; }
echo "FAIL-CLOSED TEST FAILED ($fails)"; exit 1