#!/usr/bin/env bash
# Regression test for quote-render-gate.sh.
#
# The gate is a PreToolUse hook on browser-pdf-save. It refuses a client-facing
# quote PDF (memory/users/<phone>/documents/quote-<jobId>.pdf or
# ...-breakdown.pdf) unless a render receipt exists for that jobId — proof the
# deterministic quote-render path produced it. Everything else passes.
#
# Covers:
#   A. client quote PDF, no receipt              → BLOCKED (exit 2)
#   B. client quote PDF, receipt present         → ALLOWED (exit 0)
#   C. client breakdown PDF, no receipt          → BLOCKED
#   D. client breakdown PDF, receipt present     → ALLOWED
#   E. non-quote PDF in the documents scope      → ALLOWED (not a quote artefact)
#   F. internal quote PDF (admin scope)          → ALLOWED (not client-facing)
#   G. quote-named PDF outside the client scope  → ALLOWED (only the documents scope is gated)
#   H. empty stdin                               → ALLOWED (general-purpose tool, fail-open)
#   I. a non-browser tool                        → ALLOWED (matcher defence-in-depth)
#   J. jobId carrying a path traversal           → BLOCKED (never resolves a stray receipt)
#   K. a block emits the op=bypass fault line

set -u

HOOK="$(cd "$(dirname "$0")/.." && pwd)/quote-render-gate.sh"
if [[ ! -x "$HOOK" ]]; then
  echo "FAIL: $HOOK not executable" >&2
  exit 1
fi

ACCT=$(mktemp -d)
cleanup() { rm -rf "$ACCT"; }
trap cleanup EXIT

# A receipt for job-1 (present) — jobs job-2 / job-3 have none.
mkdir -p "$ACCT/quoting/jobs/job-1"
printf '{"jobId":"job-1"}' > "$ACCT/quoting/jobs/job-1/render-receipt.json"

DOCS="$ACCT/memory/users/44700900000/documents"
ADMIN="$ACCT/memory/admin/customers/44700900000"

PASS=0
FAIL=0

# Run the hook with cwd = the account dir (as the PTY does), capturing exit + stderr.
run_case() {
  local name="$1" stdin="$2" expected_exit="$3"
  local actual_exit
  ( cd "$ACCT" && printf '%s' "$stdin" | bash "$HOOK" >/dev/null 2>/dev/null )
  actual_exit=$?
  if [[ "$actual_exit" -eq "$expected_exit" ]]; then
    echo "PASS: $name (exit=$actual_exit)"
    PASS=$((PASS + 1))
  else
    echo "FAIL: $name (expected exit=$expected_exit, got=$actual_exit)" >&2
    FAIL=$((FAIL + 1))
  fi
}

envelope() { # tool_name, path
  printf '{"hook_event_name":"PreToolUse","tool_name":"%s","tool_input":{"path":"%s"}}' "$1" "$2"
}

BROWSER="mcp__plugin_browser_browser__browser-pdf-save"

run_case "A: client quote PDF, no receipt → BLOCKED" \
  "$(envelope "$BROWSER" "$DOCS/quote-job-2.pdf")" 2

run_case "B: client quote PDF, receipt present → ALLOWED" \
  "$(envelope "$BROWSER" "$DOCS/quote-job-1.pdf")" 0

run_case "C: client breakdown PDF, no receipt → BLOCKED" \
  "$(envelope "$BROWSER" "$DOCS/quote-job-3-breakdown.pdf")" 2

run_case "D: client breakdown PDF, receipt present → ALLOWED" \
  "$(envelope "$BROWSER" "$DOCS/quote-job-1-breakdown.pdf")" 0

run_case "E: non-quote PDF in documents scope → ALLOWED" \
  "$(envelope "$BROWSER" "$DOCS/brochure.pdf")" 0

run_case "F: internal quote PDF (admin scope) → ALLOWED" \
  "$(envelope "$BROWSER" "$ADMIN/quote-job-2-internal.pdf")" 0

run_case "G: quote-named PDF outside client scope → ALLOWED" \
  "$(envelope "$BROWSER" "$ACCT/quote-job-2.pdf")" 0

run_case "H: empty stdin → ALLOWED (fail-open)" \
  "" 0

run_case "I: non-browser tool → ALLOWED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Write","tool_input":{"file_path":"/x/memory/users/44700900000/documents/quote-job-2.pdf"}}' 0

run_case "J: jobId path traversal → BLOCKED" \
  "$(envelope "$BROWSER" "$DOCS/quote-...pdf")" 2

# K: a block emits the op=bypass fault line on stderr.
STDERR=$( cd "$ACCT" && printf '%s' "$(envelope "$BROWSER" "$DOCS/quote-job-2.pdf")" | bash "$HOOK" 2>&1 >/dev/null )
if printf '%s' "$STDERR" | grep -q '\[quote-render\] op=bypass jobId=job-2'; then
  echo "PASS: K: block emits op=bypass jobId=job-2"
  PASS=$((PASS + 1))
else
  echo "FAIL: K: op=bypass line absent (got: $STDERR)" >&2
  FAIL=$((FAIL + 1))
fi

echo "──────── quote-render-gate test summary ────────"
echo "PASS=$PASS FAIL=$FAIL"
[[ "$FAIL" -eq 0 ]]
