#!/usr/bin/env bash
# Regression cases for .claude/hooks/env-file-guard.sh
# Run from the repo root: sh <this file>
# The hook runs under bash, as settings.json runs it: a Linux sh (dash) has no
# pipefail, so under sh every case would fail closed.
HOOK=.claude/hooks/env-file-guard.sh
pass=0
fail=0

probe() { # command [home] [cwd, as Claude Code passes it]
  out=$(jq -n --arg c "$1" --arg d "${3:-}" '{tool_input:{command:$c}} + if $d == "" then {} else {cwd:$d} end' |
    HOME=${2:-$HOME} bash "$HOOK" 2>&1)
  if [ -z "$out" ]; then echo "allow"; else
    printf '%s' "$out" | jq -r '.hookSpecificOutput.permissionDecision' 2>/dev/null || echo "ERROR"
  fi
}

check() { # name expected command [home] [cwd]
  got=$(probe "$3" "$4" "$5")
  if [ "$got" = "$2" ]; then
    pass=$((pass + 1)); printf '  ok    %-52s %s\n' "$1" "$got"
  else
    fail=$((fail + 1)); printf '  FAIL  %-52s got=%s want=%s\n' "$1" "$got" "$2"
  fi
}

printf 'The leak this hook exists for (2026-07-31):\n'
check "recursive grep from the root" deny "grep -rn 'HYGRAPH_TOKEN' . --exclude-dir=node_modules --exclude-dir=.git"

printf '\nReaders the old deny list never named:\n'
check "sed" deny "sed -n '1,5p' .env.local"
check "awk" deny "awk -F= '{print \$1}' .env.local"
check "cut" deny "cut -d= -f1 .env.local"
check "head" deny "head -3 .env.local"
check "tail" deny "tail -n 1 .env.local"
check "strings" deny "strings .env.local"
check "xxd" deny "xxd .env.local"
check "sort" deny "sort .env.local"
check "a script of one's own" deny "./scripts/dump.sh .env.local"
check "python" deny "python3 -c 'print(open(\".env.local\").read())'"
check "still catches cat" deny "cat .env.local"

printf '\nOther protected targets and paths:\n'
check ".env" deny "grep TOKEN .env"
check ".env.production" deny "less .env.production"
check ".env.development" deny "wc -l .env.development"
check "a nested worktree path" deny "cat ../esther-perel/.env.local"
check "an absolute path" deny "cat /Users/x/repo/.env.local"
check "a prefixed name" deny "cat app.env.local"
check "Wrangler's local secrets file" deny "cat apps/edge/.dev.vars"
check "a quoted path" deny "cat '.env.local'"
check "append (a write is an Edit)" deny "printf 'X=1' >> .env.local"

printf '\nSweeps that would reach the root:\n'
check "grep -r with no path" deny "grep -rl SECRET"
check "grep -R ." deny "grep -R TOKEN ."
check "grep -r with a glob path" deny "grep -r TOKEN *"
check "rg --no-ignore" deny "rg --no-ignore TOKEN"
check "rg --hidden" deny "rg --hidden -n TOKEN ."
check "rg -uu" deny "rg -uu TOKEN"
check "git grep --untracked" deny "git grep --untracked TOKEN"
check "find -exec" deny "find . -type f -exec grep -l TOKEN {} +"

printf '\nSearches that are already safe:\n'
check "scoped path" allow "grep -rn TOKEN app/"
check "scoped path, two dirs" allow "grep -rn TOKEN app/ scripts/"
check "explicit exclusion" allow "grep -rn TOKEN . --exclude=.env* --exclude=.dev.vars"
check "exclusion, separate token" allow "grep -rn TOKEN . --exclude '.env*' --exclude .dev.vars"
check "plain rg (skips gitignored)" allow "rg TOKEN"
check "rg with a path" allow "rg -n TOKEN app/lib"
check "rg glob exclusion" allow "rg --no-ignore -g '!.env*' -g '!.dev.vars' TOKEN"
check "git grep (tracked only)" allow "git grep TOKEN"
check "find printing paths" allow "find . -name '*.ts'"
check "find naming an env file" allow "find . -name '.env*'"
check "non-recursive grep on a file" allow "grep -n TOKEN app/lib/cms.ts"

printf '\n.env.example is checked in and carries no values:\n'
check "cat" allow "cat .env.example"
check "grep" allow "grep -n '^[A-Z_]*=' .env.example"
check "a sweep excluding only it still reads .dev.vars" deny "grep -rn TOKEN . --exclude=.env.example"

printf '\n--env-file loads, it does not print:\n'
check "package.json form" allow "node --env-file-if-exists=.env.local db/migrate.ts"
check "separate token form" allow "node --env-file .env.local scripts/cms-seed/index.mts"
check "documented one-liner" allow "node --env-file-if-exists=.env.local scripts/cms-edit/index.mts"
check "but not with -e" deny "node --env-file=.env.local -e 'console.log(process.env.HYGRAPH_TOKEN)'"
check "but not with --print" deny "node --env-file=.env.local --print process.env.STRIPE_SECRET_KEY"

printf '\nA mention is not a read:\n'
check "commit message" allow "git commit -m 'docs: explain .env.local'"
check "commit message, double quotes" allow "git commit -m \"fix: read DATABASE_URL from .env.local\""
check "echoed instruction" allow "echo 'add HYGRAPH_TOKEN to .env.local'"
check "gh pr body" allow "gh pr create --body 'Part of EST-151. Touches .env.local handling.'"

printf '\nEveryday commands must not be touched:\n'
check "git status" allow "git status"
check "ls" allow "ls -la"
check "pnpm script (loads env internally)" allow "pnpm db:migrate"
check "dev stack (writes env internally)" allow "node scripts/dev-stack/index.mts provision"
check "pnpm check" allow "pnpm check"
check "vitest" allow "pnpm test app/lib/cms.test.ts"

printf '\nWriting the file is not printing it:\n'
check "vercel env pull (documented step)" allow "vercel env pull .env.local"
check "vercel env ls" allow "vercel env ls"
check "but the cat after it still counts" deny "vercel env pull .env.local && cat .env.local"

printf '\nEach command in a chain is judged on its own:\n'
check "cd then sweep the root" deny "cd app && grep -rn TOKEN ."
check "cd then a scoped search" allow "cd app && grep -rn TOKEN lib/"
check "load, then read" deny "node --env-file=.env.local db/migrate.ts && cat .env.local"
check "pipe into a sweep" deny "echo x | grep -rn TOKEN ."
check "pipe out of a scoped search" allow "grep -rn TOKEN app/ | head -5"
check "an unrelated first command" deny "pnpm check && grep -rn TOKEN ."

printf '\nA leading rtk or rtk proxy runs the command after it:\n'
check "rtk grep sweeping the root" deny "rtk grep -rn TOKEN ."
check "rtk proxy grep sweeping the root" deny "rtk proxy grep -rn TOKEN ."
check "rtk rg --hidden" deny "rtk rg --hidden TOKEN"
check "rtk find -exec" deny "rtk find . -type f -exec grep -l TOKEN {} +"
check "rtk git grep --untracked" deny "rtk git grep --untracked TOKEN"
check "rtk proxy python inline code" deny "rtk proxy python3 -c 'print(open(\".env.local\").read())'"
check "rtk read names the file" deny "rtk read .env.local"
check "cd then rtk grep the root" deny "cd app && rtk grep -rn TOKEN ."
check "rtk grep, scoped path" allow "rtk grep -rn TOKEN app/"
check "rtk proxy grep, scoped path" allow "rtk proxy grep -rn TOKEN app/"
check "rtk git status" allow "rtk git status"
check "rtk proxy with nothing after" allow "rtk proxy"

printf '\nA package-manager launcher runs the program after it:\n'
check "npx node -e" deny "npx node -e \"require('fs').readFileSync('.env.local')\""
check "npx with a flag" deny "npx -y node -p \"require('fs').readFileSync('.env')+''\""
check "npx tsx --eval" deny "npx tsx --eval \"require('fs').readFileSync('.env.local')\""
check "pnpm exec node -e" deny "pnpm exec node -e \"console.log(require('fs').readFileSync('.env.local', 'utf8'))\""
check "pnpm exec tsx -e, a nested file" deny "pnpm exec tsx -e \"readFileSync('apps/x/.env.development.local')\""
check "pnpm exec node -e, a credential store" deny "pnpm exec node -e \"readFileSync('$HOME/.ssh/id_rsa')\""
check "pnpm dlx tsx -e" deny "pnpm dlx tsx -e \"import('node:fs').then((fs) => fs.readFileSync('.env.local'))\""
check "a bare pnpm tsx -e" deny "pnpm tsx -e \"readFileSync('.env.local')\""
check "bunx tsx -e" deny "bunx tsx -e \"readFileSync('.env.local')\""
check "pnpm --filter <app> exec node -e" deny "pnpm --filter web exec node -e \"readFileSync('.env.local')\""
check "an env assignment first" deny "NODE_ENV=test node -e \"require('fs').readFileSync('.env.test')\""
check "pnpm exec grep sweeping the root" deny "pnpm exec grep -rn TOKEN ."
check "npx vitest" allow "npx vitest run app/lib"
check "pnpm exec tsc" allow "pnpm exec tsc --noEmit"
check "pnpm exec node -e without a file" allow "pnpm exec node -e \"console.log(process.env.NODE_ENV)\""
check "pnpm exec grep, scoped path" allow "pnpm exec grep -rn TOKEN app/"

printf '\nA glob or name that picks env files reads them, however narrow the path:\n'
check "rg -g .env*" deny "rg -g '.env*' TOKEN"
check "rg -g attached" deny "rg -g.env* TOKEN"
check "rg --glob=.env*" deny "rg --glob='.env*' TOKEN"
check "rg -g .env* with the ignores off, scoped" deny "rg --hidden --no-ignore -g '.env*' TOKEN apps/"
check "grep --include=.env*, scoped" deny "grep -rn TOKEN apps/ --include='.env*'"
check "find -name .env* -exec, scoped" deny "find apps -name '.env*' -exec cat {} +"
check "find -iname .env* -exec" deny "find apps -iname '.env*' -exec cat {} +"
check "find | xargs grep" deny "find . -name '.env*' | xargs grep DATABASE_URL"
check "find -print0 | xargs -0 head" deny "find apps -name '.env*' -print0 | xargs -0 head"
check "find into a read loop" deny "find . -name '.env*' | while read f; do cat \"\$f\"; done"
check "cat \$(find)" deny "cat \$(find . -name '.env*')"
check "cat \`find\`" deny "cat \`find . -name '.env*'\`"
check "a loop over \$(find)" deny "for f in \$(find . -name '.env*'); do head \$f; done"
check "a read loop from <(find)" deny "while IFS= read -r f; do cat \"\$f\"; done < <(find . -name '.env*')"
check "a shell glob" deny "head .env*"
check "a nested shell glob" deny "grep TOKEN apps/web/.env*"
check "rg -g on .ts files" allow "rg -g '*.ts' TOKEN"
check "find excluding env files -exec" allow "find . ! -name '.env*' ! -name .dev.vars -type f -exec grep -l TOKEN {} +"
check "find of env files | wc" allow "find . -name '.env*' | wc -l"
check "find of .ts files | xargs grep" allow "find app -name '*.ts' | xargs grep -l TOKEN"
check "\$(find) of .ts files" allow "wc -l \$(find app -name '*.ts')"
check "a shell glob of .ts files" allow "head app/*.ts"
check "a quoted pattern is not a glob" allow "rg -n '.env.*' app/"
check "find -name, an exact .env.<x>.local -exec" deny "find apps -name .env.staging.local -exec cat {} +"
check "find -iname, an exact name in capitals -exec" deny "find apps -iname .ENV.PREVIEW.LOCAL -exec cat {} +"
check "find -path ending in an exact name -exec" deny "find apps -path '*/web/.env.ci.local' -exec cat {} +"
check "find -name, an exact name | xargs cat" deny "find apps -name .env.staging.local | xargs cat"
check "rg -g, an exact name" deny "rg -g .env.staging.local TOKEN apps"
check "rg --glob=, an exact prefixed name" deny "rg --glob=app.env.local TOKEN apps"
check "find -name, an exact name, printing paths" allow "find apps -name .env.staging.local"
check "rg -g .env.example" allow "rg -g .env.example TOKEN apps"

printf '\nCredential stores, read from the Read(~/...) rules in settings.json:\n'
check "cat an ssh key" deny "cat ~/.ssh/id_rsa"
check "head aws credentials" deny "head -1 ~/.aws/credentials"
check "\$HOME spelling" deny 'cat $HOME/.npmrc'
check "\${HOME} spelling" deny 'cat ${HOME}/.config/gh/hosts.yml'
check "absolute home path" deny "cat $HOME/.npmrc"
check "path with a space, quoted" deny "cat \"$HOME/Library/Application Support/com.vercel.cli/auth.json\""
check "path with a space, escaped" deny 'cat ~/Library/Application\ Support/com.vercel.cli/auth.json'
check "a key outside ~/.ssh" deny "cat ~/backup/id_ed25519"
check "copying it out" deny "cp ~/.claude/.credentials.json /tmp/x"
check "listing the store" deny "ls ~/.ssh"
check "rtk read" deny "rtk read ~/.ssh/id_ed25519"
check "rtk proxy cat" deny "rtk proxy cat ~/.config/op/config"
check "bash -c" deny "bash -c 'cat ~/.ssh/id_rsa'"
check "sh -c with \$HOME" deny "sh -c 'head -3 \$HOME/.aws/credentials'"
check "python3 -c open()" deny "python3 -c \"print(open('$HOME/.npmrc').read())\""
check "node -e readFileSync" deny "node -e \"require('fs').readFileSync('$HOME/.docker/config.json')\""
check "grep -r over \$HOME" deny 'grep -rn TOKEN $HOME'

check "a relative key name" deny "cat backup/id_rsa"

# One heredoc as a command string: the line that takes it, the body, EOF.
heredoc() { printf "%s <<'EOF'\n%s\nEOF" "$1" "$2"; }

printf '\nA heredoc into an interpreter or a launcher of one is code:\n'
check "node" deny "$(heredoc node "console.log(require('fs').readFileSync('.env.local', 'utf8'))")"
check "node --input-type module" deny "$(heredoc "node --input-type module" "import { readFileSync } from 'node:fs'; console.log(readFileSync('.env.local', 'utf8'))")"
check "python" deny "$(heredoc "python -" "print(open('.env.local').read())")"
check "python3" deny "$(heredoc "python3 -" "print(open('.env').read())")"
check "python3.12" deny "$(heredoc "python3.12 -" "print(open('apps/auth/.env.local').read())")"
check "deno run -" deny "$(heredoc "deno run -" "console.log(Deno.readTextFileSync('.env.local'))")"
check "bun run -" deny "$(heredoc "bun run -" "console.log(await Bun.file('.env.local').text())")"
check "pnpm tsx" deny "$(heredoc "pnpm tsx" "console.log(readFileSync('.env.production', 'utf8'))")"
check "uv run python -" deny "$(heredoc "uv run python -" "print(open('.env.local').read())")"
check "a credential store" deny "$(heredoc "python3 -" "print(open('$HOME/.npmrc').read())")"
check "after cd, inside \$(...)" deny "$(heredoc "cd app && out=\$(node" "console.log(readFileSync('.env.local', 'utf8'))")"
check "piped in from cat" deny "$(printf "cat <<'EOF' | python3 -\nprint(open('.env.local').read())\nEOF")"
check "node -e \"\$(cat <<EOF)\"" deny "$(printf "node -e \"\$(cat <<'EOF'\nconsole.log(readFileSync('.env.local', 'utf8'))\nEOF\n)\"")"
check "<<- with tab-indented lines" deny "$(printf "python3 - <<-EOF\n\tprint(open('.env.local').read())\n\tEOF")"
check "a line continuation before it" deny "$(printf "uv run \\\\\n  python - <<'EOF'\nprint(open('.env.local').read())\nEOF")"
check "after a shift on an earlier line" deny "$(printf "echo \$((1 << 2))\npython3 - <<'EOF'\nprint(open('.env.local').read())\nEOF")"
check "after a shift on the same line" deny "$(printf "n=\$((1<<3)); python3 - <<'EOF'\nprint(open('.env.local').read())\nEOF")"
check "after a quoted << on an earlier line" deny "$(printf "git commit -m \"use << x\"\npython3 - <<'EOF'\nprint(open('.env.local').read())\nEOF")"

printf '\nThe same heredocs with no env file named:\n'
check "node" allow "$(heredoc node "console.log(process.env.NODE_ENV)")"
check "node --input-type module" allow "$(heredoc "node --input-type module" "import { readFileSync } from 'node:fs'; console.log(readFileSync('package.json', 'utf8'))")"
check "python" allow "$(heredoc "python -" "import os; print(os.environ.get('HOME'))")"
check "python3" allow "$(heredoc "python3 -" "print(open('package.json').read())")"
check "python3.12" allow "$(heredoc "python3.12 -" "print(1 + 1)")"
check "deno run -" allow "$(heredoc "deno run -" "console.log(Deno.readTextFileSync('deno.json'))")"
check "bun run -" allow "$(heredoc "bun run -" "console.log(await Bun.file('package.json').text())")"
check "pnpm tsx" allow "$(heredoc "pnpm tsx" "console.log(import.meta.env)")"
check "uv run python -" allow "$(heredoc "uv run python -" "print(open('.env.example').read())")"
check "a shift is not a heredoc" allow "$(printf "echo \$((1 << 2))\npython3 - <<'EOF'\nprint(open('package.json').read())\nEOF")"
check "a heredoc into cat is prose" allow "$(heredoc "cat > notes.md" "read it with readFileSync('.env.local')")"
check "a PR body whose title names node" allow "$(printf "gh pr create --title \"fix: heredoc into node\" --body \"\$(cat <<'EOF'\nnode now denies readFileSync('.env.local') here\nEOF\n)\"")"

printf '\nHeredocs the hook already read as commands or names:\n'
check "xargs" deny "$(heredoc "xargs cat" ".env.local")"
check "a while-read loop" deny "$(heredoc "while read f; do head \"\$f\"; done" ".env.local")"
check "bash -s" deny "$(heredoc "bash -s" "cat .env.local")"
check "sh -s" deny "$(heredoc "sh -s" "head -3 .env.local")"
check "\$(cat <<EOF)" deny "$(printf "head \$(cat <<'EOF'\n.env.local\nEOF\n)")"

printf '\nThe list is the built-in defaults plus settings.json; a malformed file fails closed:\n'
tmp=$(mktemp -d)
mkdir -p "$tmp/hooks" "$tmp/bin"
cp "$HOOK" "$tmp/hooks/env-file-guard.sh"
real_hook=$HOOK
HOOK="$tmp/hooks/env-file-guard.sh"
check "missing file: built-in list guards stores" deny "cat ~/.ssh/id_rsa"
check "missing file: env files still guarded" deny "cat .env.local"
check "missing file: ordinary commands run" allow "git status"
printf '{}\n' > "$tmp/settings.json"
check "no permissions key: built-in list" deny "cat ~/.aws/credentials"
printf '{"permissions":{"deny":["Read(~/.bp87-probe/**)"]}}\n' > "$tmp/settings.json"
check "a rule added to settings.json" deny "cat ~/.bp87-probe/token"
check "settings cannot remove a default" deny "cat ~/.ssh/id_rsa"
printf '{"permissions":{"deny":[]}}\n' > "$tmp/settings.json"
check "empty deny list: defaults still hold" deny "cat ~/.ssh/id_rsa"
printf '{"permissions":{"deny":["Bash(git push --force*)"]}}\n' > "$tmp/settings.json"
check "deny list with no Read rule: defaults hold" deny "cat ~/.npmrc"
rm "$tmp/settings.json"
printf '{"permissions":{"deny":null}}\n' > "$tmp/settings.json"
check "deny is null: fail closed" deny "git status"
printf '{"permissions":{"deny":42}}\n' > "$tmp/settings.json"
check "deny is a number: fail closed" deny "git status"
printf '{"permissions":{"deny":true}}\n' > "$tmp/settings.json"
check "deny is a boolean: fail closed" deny "git status"
printf '{"permissions":{"deny":"Read(~/.ssh/**)"}}\n' > "$tmp/settings.json"
check "deny is a string: fail closed" deny "git status"
printf '{"permissions":{"deny":[42]}}\n' > "$tmp/settings.json"
check "a rule that is not a string: fail closed" deny "git status"
printf '{"permissions":[]}\n' > "$tmp/settings.json"
check "permissions is not an object: fail closed" deny "git status"
printf '{"permissions":{"deny":[' > "$tmp/settings.json"
check "invalid JSON: fail closed" deny "git status"
rm "$tmp/settings.json" && mkdir "$tmp/settings.json"
check "unreadable file: fail closed" deny "git status"
rmdir "$tmp/settings.json"
# A guard that crashes must not wave the command through.
printf '#!/bin/sh\nexit 1\n' > "$tmp/bin/python3" && chmod +x "$tmp/bin/python3"
got=$(PATH="$tmp/bin:$PATH"; export PATH; probe "git status")
if [ "$got" = deny ]; then
  pass=$((pass + 1)); printf '  ok    %-52s %s\n' "the guard itself fails: fail closed" "$got"
else
  fail=$((fail + 1)); printf '  FAIL  %-52s got=%s want=deny\n' "the guard itself fails: fail closed" "$got"
fi
rm "$tmp/bin/python3"

# The hook timeout kills a slow guard, and Claude Code then lets the call
# through, so the scan has its own deadline, well under the timeout. The test
# stubs the timer down to 50ms and hands it a command that takes about 2s to
# scan; an ordinary command still finishes inside a 1s stub.
big="echo $(printf 'a %.0s' $(seq 1 200000))"
reason_of() { # command deadline -> the deny reason, or allow
  # On stdin, not as an argument: Linux caps one argument at 128KB.
  out=$(printf '%s' "$1" | jq -Rs '{tool_input:{command:.}}' | ENV_FILE_GUARD_DEADLINE=$2 bash "$HOOK" 2>/dev/null)
  if [ -z "$out" ]; then echo allow; else
    printf '%s' "$out" | jq -r '.hookSpecificOutput.permissionDecisionReason' 2>/dev/null || echo ERROR
  fi
}
got=$(reason_of "$big" 0.05)
case "$got" in
  *"timed out"*) pass=$((pass + 1)); printf '  ok    %-52s %s\n' "slow scan past the deadline: deny" "timed out" ;;
  *) fail=$((fail + 1)); printf '  FAIL  %-52s reason=%s\n' "slow scan past the deadline: deny" "$got" ;;
esac
got=$(reason_of "git status" 1)
if [ "$got" = allow ]; then
  pass=$((pass + 1)); printf '  ok    %-52s %s\n' "a quick scan beats the deadline" "$got"
else
  fail=$((fail + 1)); printf '  FAIL  %-52s reason=%s\n' "a quick scan beats the deadline" "$got"
fi

# SIGTERM to the wrapper (a hook timeout) exits 2, the blocking exit.
printf '#!/bin/sh\nsleep 1\n' > "$tmp/bin/python3" && chmod +x "$tmp/bin/python3"
jq -n '{tool_input:{command:"git status"}}' > "$tmp/input.json"
(PATH="$tmp/bin:$PATH"; export PATH; exec bash "$HOOK" < "$tmp/input.json" >/dev/null 2>&1) &
pid=$!
sleep 0.3
kill -TERM "$pid"
wait "$pid" && code=0 || code=$?
if [ "$code" -eq 2 ]; then
  pass=$((pass + 1)); printf '  ok    %-52s %s\n' "SIGTERM mid-scan: exit 2 (block)" "exit $code"
else
  fail=$((fail + 1)); printf '  FAIL  %-52s exit %s, want 2\n' "SIGTERM mid-scan: exit 2 (block)" "$code"
fi
HOOK=$real_hook
rm -rf "$tmp"
# Exit 2 is the only failure Claude Code treats as a block.
printf 'not json' | bash "$HOOK" >/dev/null 2>&1 && code=0 || code=$?
if [ "$code" -eq 2 ]; then
  pass=$((pass + 1)); printf '  ok    %-52s %s\n' "unreadable hook input: exit 2 (block)" "exit $code"
else
  fail=$((fail + 1)); printf '  FAIL  %-52s exit %s, want 2\n' "unreadable hook input: exit 2 (block)" "$code"
fi

# The built-in list is the fallback for a missing settings.json, so it must be
# the same list as settings.json, rule for rule.
printf '\nThe built-in list matches settings.json:\n'
from_settings=$(jq -r '.permissions.deny[] | select(startswith("Read(~/"))' .claude/settings.json | sort)
from_hook=$(grep -o '"Read(~/[^"]*)"' "$HOOK" | tr -d '"' | sort)
if [ -n "$from_settings" ] && [ "$from_settings" = "$from_hook" ]; then
  pass=$((pass + 1)); printf '  ok    %-52s %s\n' "same Read(~/...) rules" "$(printf '%s\n' "$from_hook" | wc -l | tr -d ' ') rules"
else
  fail=$((fail + 1)); printf '  FAIL  %-52s\n' "same Read(~/...) rules"
  a=$(mktemp) && b=$(mktemp)
  printf '%s\n' "$from_settings" > "$a"; printf '%s\n' "$from_hook" > "$b"
  diff "$a" "$b" | sed 's/^/        /'; rm -f "$a" "$b"
fi

printf '\nA mention of a credential store is not a read:\n'
check "commit message" allow "git commit -m 'docs: never cat ~/.ssh/id_rsa'"
check "echo" allow "echo 'keys live in ~/.ssh'"
check "the parent directory" allow "ls ~/.config"
check "an unlisted file" allow "cat ~/.config/other/settings.json"
check "a longer name" allow "cat ~/.npmrc.example"
check "the gh CLI itself" allow "gh auth status"

printf '\nInline code with escaped quotes, a flag cluster or an attached value is still code:\n'
check "node -e, escaped quotes" deny 'node -e "console.log(require(\"fs\").readFileSync(\".env.local\", \"utf8\"))"'
check "node -p, escaped quotes" deny 'node -p "require(\"fs\").readFileSync(\".env.local\", \"utf8\")"'
check "npx tsx -e, escaped quotes" deny 'npx tsx -e "console.log(require(\"fs\").readFileSync(\".env.local\", \"utf8\"))"'
check "pnpm exec node -e, escaped quotes" deny 'pnpm exec node -e "console.log(require(\"fs\").readFileSync(\".env.local\", \"utf8\"))"'
check "python3 -c, escaped quotes" deny 'python3 -c "print(open(\".env.local\").read())"'
check "bash -c, escaped quotes" deny 'bash -c "cat \".env.local\""'
check "node -pe" deny "node -pe \"require('fs').readFileSync('.env.local', 'utf8')\""
check "bash -lc" deny "bash -lc 'cat .env.local'"
check "python3 -c with the code attached" deny "python3 -c\"print(open('.env.local').read())\""
check "pnpm exec -c (shell mode)" deny "pnpm exec -c 'cat .env.local'"
check "npx -c" deny "npx -c 'cat .env.local'"
check "escaped quotes, no env file" allow 'node -e "console.log(require(\"fs\").readFileSync(\"package.json\", \"utf8\"))"'
check "node -pe, no env file" allow "node -pe 'process.env.NODE_ENV'"

printf '\nAn eval flag in any spelling turns an --env-file load into a read:\n'
check "-pe" deny "node --env-file=.env.local -pe process.env.HYGRAPH_TOKEN"
check "-pe, quoted code" deny "node --env-file=.env.local -pe 'process.env'"
check "--eval=" deny "node --env-file=.env.local --eval='console.log(process.env)'"
check "separate token form, -pe" deny "node --env-file .env.local -pe process.env"

printf '\nA reader past any launcher, flag value or assignment is still that reader:\n'
check "pnpm --filter <app> exec grep" deny "pnpm --filter web exec grep -rn TOKEN ."
check "pnpm -F <app> exec grep" deny "pnpm -F web exec grep -rn TOKEN ."
check "pnpm --dir <dir> exec grep" deny "pnpm --dir apps/web exec grep -rn TOKEN ."
check "pnpm --filter <app> grep, no verb" deny "pnpm --filter web grep -rn TOKEN ."
check "npm -w <app> exec grep" deny "npm -w web exec grep -rn TOKEN ."
check "an env assignment first" deny "LC_ALL=C grep -rn TOKEN ."
check "the second line of a command" deny "$(printf 'cd app\ngrep -rn TOKEN .')"
check "pnpm --filter <app> exec grep, scoped" allow "pnpm --filter web exec grep -rn TOKEN app/"

printf '\nThe root spelled another way is still the root:\n'
check "the absolute path of the root" deny "grep -rn HYGRAPH_TOKEN $PWD"
check "the root through ~" deny "$(printf 'grep -rn TOKEN ~/%s' "$(basename "$PWD")")" "$(dirname "$PWD")"
check "\"\$PWD\"" deny 'grep -rn TOKEN "$PWD"'
check "\$(pwd)" deny 'grep -rn TOKEN $(pwd)'
check "\$(git rev-parse --show-toplevel)" deny 'grep -rn TOKEN $(git rev-parse --show-toplevel)'
check "rg --hidden \"\$CLAUDE_PROJECT_DIR\"" deny 'rg --hidden TOKEN "$CLAUDE_PROJECT_DIR"'
check "a path that climbs back to the root" deny "grep -rn TOKEN app/.."
check "find from the absolute root -exec" deny "find $PWD -type f -exec grep -l TOKEN {} +"
check "grep --dereference-recursive" deny "grep --dereference-recursive TOKEN ."
check "grep -d recurse" deny "grep -d recurse TOKEN ."
check "grep --directories=recurse" deny "grep --directories=recurse TOKEN ."
check "an absolute path below the root" allow "grep -rn TOKEN $PWD/app"
check "the directory the command runs in" deny "grep -rn TOKEN $PWD/app" "" "$PWD/app"
check "find -exec with a variable pattern, scoped" allow "find app -name '*.ts' -exec grep -l \"\$PATTERN\" {} +"

printf '\nA redirect or operator glued to the path still names it:\n'
check "sort <.env.local" deny "sort <.env.local"
check "cat<.env.local" deny "cat<.env.local"
check "node reading stdin <.env.local" deny "node -pe \"require('fs').readFileSync(0,'utf8')\" <.env.local"
check "a read loop <.env.local" deny "while read l; do echo \$l; done <.env.local"
check "a write >.env.local" deny "printf 'X=1' >.env.local"
check "\$(cat .env.local)" deny "echo \$(cat .env.local)"
check "a trailing ;" deny "cat .env.local;echo"
check "a credential store <~/.aws/credentials" deny "sort <~/.aws/credentials"
check "a sweep with a trailing ;" deny "grep -rn TOKEN .;echo"
check "stdin from a plain file" allow "sort <app/list.txt"
check "stderr to /dev/null" allow "node scripts/x.mts 2>/dev/null"

printf '\nThe shell splits words, not the separators and # inside quoted code:\n'
check "node -e, escaped quotes then ;" deny 'node -e "const a=\"x\" ; console.log(require(\"fs\").readFileSync(\".env.local\",\"utf8\"))"'
check "npx tsx -e, escaped quotes then ;" deny 'npx tsx -e "const a=\"x\" ; console.log(require(\"fs\").readFileSync(\".env.local\",\"utf8\"))"'
check "pnpm exec node -e, escaped quotes then ;" deny 'pnpm exec node -e "const a=\"x\" ; console.log(require(\"fs\").readFileSync(\".env.local\",\"utf8\"))"'
check "python3 -c, escaped quotes then ;" deny 'python3 -c "x=\"a\" ; print(open(\".env.local\").read())"'
check "python3 -c attached, escaped quotes then ;" deny 'python3 -c"x=\"a\" ; print(open(\".env.local\").read())"'
check "bash -c, escaped quotes then ;" deny 'bash -c "echo \"hi\" ; cat .env.local"'
check "node -e, a # in the code" deny 'node -e "const a=\"#\"; console.log(require(\"fs\").readFileSync(\".env.local\",\"utf8\"))"'
check "a # inside a word is not a comment" deny "grep -rn TOKEN a#b ."
check "a # starting a word is a comment" allow "echo hi # cat .env.local"
check "escaped quotes in a commit message" allow 'git commit -m "fix: a \"quoted\" word; then .env.local"'

printf '\nA double-quoted substitution is a command of its own:\n'
check "echo \"\$(cat .env.local)\"" deny 'echo "$(cat .env.local)"'
check "echo \"\`cat .env.local\`\"" deny 'echo "`cat .env.local`"'
check "jq --arg \"\$(grep .env.local)\"" deny "jq -n --arg t \"\$(grep HYGRAPH_TOKEN .env.local)\" '\$t'"
check "curl -H \"Bearer \$(grep .env.local | cut)\"" deny 'curl http://localhost:3000/api -H "Authorization: Bearer $(grep HYGRAPH_TOKEN .env.local | cut -d= -f2)"'
check "a root sweep in \"\$(...)\"" deny 'echo "$(grep -rn HYGRAPH_TOKEN .)"'
check "a credential store in \"\$(...)\"" deny 'echo "$(cat ~/.npmrc)"'
check "a scoped search in \"\$(...)\"" allow 'echo "$(grep -rn TOKEN app/)"'
check "\$(...) in single quotes is text" allow "echo '\$(cat .env.local)'"
check "escaped backticks in a commit message" allow 'git commit -m "docs: never run \`cat .env.local\`"'
check "a PR body naming the file in a heredoc" allow "$(printf "gh pr create --title \"fix: env guard\" --body \"\$(cat <<'EOF'\nDeny \`cat .env.local\` and\n.env.local itself.\nEOF\n)\"")"

printf '\nShell code given to a shell or a launcher gets every rule:\n'
check "npx -c, a root sweep" deny "npx -c 'grep -rn HYGRAPH_TOKEN .'"
check "pnpm exec -c, a root sweep" deny "pnpm exec -c 'grep -rn HYGRAPH_TOKEN .'"
check "npm exec --call=, a root sweep" deny "npm exec --call='grep -rn HYGRAPH_TOKEN .'"
check "pnpm --filter <app> exec sh -c, a root sweep" deny "pnpm --filter web exec sh -c 'grep -rn HYGRAPH_TOKEN .'"
check "bash -c, a root sweep" deny "bash -c 'grep -rn HYGRAPH_TOKEN .'"
check "bash -lc, a find into xargs" deny "bash -lc \"find . -name '.env*' | xargs cat\""
check "npx -c, a scoped search" allow "npx -c 'grep -rn TOKEN app/'"
check "bash -c, a scoped search" allow "bash -c 'grep -rn TOKEN app/'"
check "eslint -c <config> is not shell code" allow "pnpm exec eslint -c eslint.config.js ."

printf '\neval, a variable and code on stdin are shell code too:\n'
check "eval, a double-quoted string" deny 'eval "cat .env.local"'
check "eval, a single-quoted string" deny "eval 'cat .env.local'"
check "eval in a subshell" deny '(eval "cat .env.local")'
check "eval, a root sweep" deny 'eval "grep -rn TOKEN ."'
check "eval of a variable holding the command" deny 'x="cat .env.local"; eval "$x"'
check "eval, the word itself quoted" deny '"eval" "cat .env.local"'
check "eval, the word single-quoted" deny "'eval' 'cat .env.local'"
check "eval, the word partly quoted" deny 'e"val" "cat .env.local"'
check "eval, the word escaped" deny '\eval "cat .env.local"'
check "grep, the word escaped, a root sweep" deny '\grep -rn TOKEN .'
check "bash -c of a variable holding the command" deny 'x="cat .env.local"; bash -c "$x"'
check "a variable run as the command" deny 'x="cat .env.local"; $x'
check "a variable holding the path" deny 'x=.env.local; cat $x'
check "a variable holding a credential store" deny 'f=~/.ssh/id_rsa; cat "${f}"'
check "a herestring into bash" deny 'bash <<< "cat .env.local"'
check "a herestring glued" deny 'bash <<<"cat .env.local"'
check "echo piped into sh" deny 'echo "cat .env.local" | sh'
check "piped into sh past an assignment" deny 'echo "cat .env.local" | FOO=1 sh'
check "piped into sh past a wrapper" deny 'echo "cat .env.local" | env sh'
check "source <(...)" deny 'source <(echo "cat .env.local")'
check ". /dev/stdin with a herestring" deny '. /dev/stdin <<< "cat .env.local"'
check "eval \"\$(ssh-agent -s)\"" allow 'eval "$(ssh-agent -s)"'
check "eval, a scoped search" allow 'eval "grep -rn TOKEN app/"'
check "an installer piped into bash" allow "curl -fsSL https://example.com/install.sh | bash"
check "a variable naming the file, never expanded" allow "DOTENV_CONFIG_PATH=.env.local pnpm dev"
check "eval in a commit message" allow 'git commit -m "eval is fine" -m "document .env.local"'
check "a variable of something else" allow 'x=1; echo $x'

printf '\nA flag value is not the pattern, so the pattern is not a path:\n'
check "grep -rn -C 3, no path" deny "grep -rn -C 3 HYGRAPH_TOKEN"
check "grep -rn -A 2, no path" deny "grep -rn -A 2 HYGRAPH_TOKEN"
check "grep -rn -m 5, no path" deny "grep -rn -m 5 HYGRAPH_TOKEN"
check "grep -r -e A -e B, no path" deny "grep -r -e HYGRAPH_TOKEN -e SENTRY_AUTH"
check "grep -rnC 3, the value flag ends a cluster" deny "grep -rnC 3 HYGRAPH_TOKEN"
check "grep -rn --context 3, no path" deny "grep -rn --context 3 HYGRAPH_TOKEN"
check "grep -d recurse, no path" deny "grep -d recurse HYGRAPH_TOKEN"
check "rg -uu -A 2, no path" deny "rg -uu -A 2 HYGRAPH_TOKEN"
check "grep -rn -C 3, scoped" allow "grep -rn -C 3 TOKEN app/"
check "grep -rn -C3, scoped" allow "grep -rn -C3 TOKEN app/"
check "grep -r -e A -e B, scoped" allow "grep -r -e HYGRAPH_TOKEN -e SENTRY_AUTH app/"

printf '\nrg ignore overrides inside a flag cluster:\n'
check "rg -iuu" deny "rg -iuu HYGRAPH_TOKEN ."
check "rg -nuu" deny "rg -nuu HYGRAPH_TOKEN ."
check "rg -uuS, no path" deny "rg -uuS HYGRAPH_TOKEN"
check "rg -n. (hidden)" deny "rg -n. HYGRAPH_TOKEN"
check "rg -in, no override" allow "rg -in TOKEN"
check "rg -trust, a type value holding u" allow "rg -trust TOKEN"

printf '\nAn operator glued to the next command still ends the one before:\n'
check "cd app;grep, a root sweep" deny "cd app;grep -rn TOKEN ."
check "cd app&&grep, a root sweep" deny "cd app&&grep -rn TOKEN ."
check "cd app||grep, a root sweep" deny "cd app||grep -rn TOKEN ."
check "echo x|grep, a root sweep" deny "echo x|grep -rn TOKEN ."
check "sleep 1&grep, a root sweep" deny "sleep 1&grep -rn TOKEN ."
check "cd app;rg --hidden" deny "cd app;rg --hidden TOKEN"
check "cd app;find -exec" deny "cd app;find . -type f -exec grep -l TOKEN {} +"
check "cd app;node -e" deny "cd app;node -e \"require('fs').readFileSync('.env.local')\""
check "cd app;bash -c, a root sweep" deny "cd app;bash -c 'grep -rn TOKEN .'"
check "cd app;npx -c" deny "cd app;npx -c 'cat .env.local'"
check "(cd app;grep), a root sweep" deny "(cd app;grep -rn TOKEN .)"
check "a quoted \$(cd app;grep)" deny 'echo "$(cd app;grep -rn TOKEN .)"'
check "cd app;grep, scoped" allow "cd app;grep -rn TOKEN lib/"
check "cd app&&git status" allow "cd app&&git status"
check "a scoped search 2>&1|head" allow "grep -rn TOKEN app/ 2>&1|head -5"
check "pnpm check &>/dev/null" allow "pnpm check &>/dev/null"
check "find -exec with an escaped ;" allow "find app -name '*.ts' -exec grep -l TOKEN {} \\;"
check "a ; in a commit message" allow "git commit -m 'fix: a;grep -rn TOKEN . in prose'"

printf '\nA redirect is not a path to search:\n'
check "grep -rn 2>/dev/null, no path" deny "grep -rn TOKEN 2>/dev/null"
check "grep -rn 2>&1|head, no path" deny "grep -rn TOKEN 2>&1|head -5"
check "grep -rn > out.txt, no path" deny "grep -rn TOKEN > out.txt"
check "grep -rn >>out.txt, no path" deny "grep -rn TOKEN >>out.txt"
check "rg --hidden 2>/dev/null, no path" deny "rg --hidden TOKEN 2>/dev/null"
check "grep -rn 2>/dev/null, scoped" allow "grep -rn TOKEN app/ 2>/dev/null"
check "a pattern that looks like a redirect" allow "grep -rn '<div>' app/"
check "a read loop from <(grep), scoped" allow "while read -r l; do echo \"\$l\"; done < <(grep -rn TOKEN app/)"

printf '\nThe glob and name rules cover Wrangler'"'"'s .dev.vars too:\n'
check "rg -g .dev.vars" deny "rg -g '.dev.vars' TOKEN"
check "a shell glob of .dev.vars" deny "head apps/edge/.dev.vars*"
check "find -name .dev.vars -exec" deny "find apps -name '.dev.vars' -exec cat {} +"

printf '\nA substitution runs in every part of a word outside single quotes:\n'
check "curl -d, a JSON splice" deny "$(cat <<'CMD'
curl http://localhost:3000/api -d '{"t":"'"$(grep HYGRAPH_TOKEN .env.local | cut -d= -f2)"'"}'
CMD
)"
check "jq --argjson, a JSON splice" deny "$(cat <<'CMD'
jq -n --argjson t '{"a":"'"$(cat .env.local)"'"}' '$t'
CMD
)"
check "an empty single quote first" deny "echo ''\"\$(cat .env.local)\""
check "backticks after a single-quoted part" deny "echo 'x'\"\`cat .env.local\`\""
check "an unquoted \$(...) after a single-quoted part" deny "echo 'x'\$(cat .env.local)"
check "a single-quoted \$(...) after a double-quoted part" allow "echo \"a\"'\$(cat .env.local)'"
check "a JSON splice of a harmless command" allow "$(cat <<'CMD'
curl http://localhost:3000/api -d '{"t":"'"$(date +%s)"'"}'
CMD
)"

printf '\nA heredoc body is data, never shell code:\n'
check "a note with an apostrophe, then a root sweep" deny "$(printf "cat > notes.md <<'EOF'\nIt's the plan\nEOF\ngrep -rn HYGRAPH_TOKEN .")"
check "a note with an apostrophe, then rg -uu" deny "$(printf "cat > notes.md <<'EOF'\nIt's the plan\nEOF\nrg -uu HYGRAPH_TOKEN")"
check "a note with an apostrophe, then cat, then a quote" deny "$(printf "cat > notes.md <<'EOF'\nIt's the plan\nEOF\ncat .env.local\necho \"x'\" # \"")"
check "a note that mentions a root sweep" allow "$(printf "cat > notes.md <<'EOF'\nIt's done: grep -rn TOKEN . now denies\nEOF\ngit status")"
check "a body naming the file, handed to xargs" deny "$(printf "xargs cat <<'EOF'\nIt's here:\n.env.local\nEOF")"
check "a shift is not a heredoc opener" deny "$(printf "echo \$((1 << 2))\ncat .env.local")"
check "a quoted << opens no heredoc" deny "$(printf "git commit -m \"a <<EOF b\"\ncat .env.local\nEOF")"
check "an unparseable line after a root sweep" deny "$(printf "grep -rn HYGRAPH_TOKEN .\necho \"it's")"
check "an unparseable line after a sweep with no path" deny "$(printf "grep -rn HYGRAPH_TOKEN\necho \"it's")"
check "an unparseable line after rg -uu with no path" deny "$(printf "rg -uu HYGRAPH_TOKEN\necho \"it's")"

printf '\nA line break ends a command as ; does:\n'
check "a sweep with no path, then another line" deny "$(printf 'grep -rn HYGRAPH_TOKEN\necho done')"
check "rg --hidden with no path, then another line" deny "$(printf 'rg --hidden HYGRAPH_TOKEN\ngit status')"
check "a subshell sweep with no path, then another line" deny "$(printf '(\ngrep -rn HYGRAPH_TOKEN\n)')"
check "a subshell sweep with no path, spaced" deny "( grep -rn HYGRAPH_TOKEN )"
check "a pipe continued on the next line is still fed" deny "$(printf 'echo "cat .env.local" |\nsh')"
check "cd, then a scoped search on the next line" allow "$(printf 'cd app\ngrep -rn TOKEN lib/')"
check "a scoped search piped to head on the next line" allow "$(printf 'grep -rn TOKEN app/ |\nhead -5')"

printf '\nA word that only spells eval or an interpreter runs nothing:\n'
check "eval as a commit message" allow 'git commit -m "eval" -m "see .env.local"'
check "a pipe into grep for an interpreter's name" allow 'git log --oneline --grep "document .env.local" | grep node'
check "command -p eval" deny 'command -p eval "cat .env.local"'
check "time -p eval" deny 'time -p eval "cat .env.local"'
check "exec -c eval (zsh runs it)" deny 'exec -c eval "cat .env.local"'
check "exec -l eval, a root sweep" deny 'exec -l eval "grep -rn TOKEN ."'
check "watch -t eval" deny 'watch -t eval "cat .env.local"'
check "eval after a flag, a substitution" deny 'exec -c eval "echo \$(cat .env.local)"'
check "eval of a flag, then a command after ;" deny 'git commit -m "eval" -m "x; cat .env.local"'
check "eval of a flag, a substitution in it" deny 'git commit -m "eval" -m "\$(cat .env.local)"'
check "eval of -- still runs the rest" deny 'eval -- "cat .env.local"'
check "eval of a flag runs nothing" allow 'eval -m "see .env.local"'
check "piped into bash -s" deny 'echo "cat .env.local" | bash -s'
check "piped into grep, then sh" deny 'echo "cat .env.local" | grep cat | sh'

printf '\nA partly quoted path is the path the shell hands over:\n'
check "cat \".env\".local" deny "cat \".env\".local"
check "cat '.env.local'\"\"" deny "cat '.env.local'\"\""
check "cat .env\".local\"" deny "cat .env\".local\""
check "head -5 .en\"v.local\"" deny "head -5 .en\"v.local\""
check "cat ~/\".npmrc\"" deny "cat ~/\".npmrc\""
check "a glob whose * is unquoted" deny "head \".env\"*"
check "a glob whose * is quoted" allow "head .env\".*\""

printf '\nA root sweep must leave out .dev.vars as well as .env*:\n'
check "grep excluding only .env*" deny "grep -rn TOKEN . --exclude='.env*'"
check "rg excluding only .env*" deny "rg --no-ignore -g '!.env*' TOKEN"
check "find excluding only .env* -exec" deny "find . ! -name '.env*' -type f -exec grep -l TOKEN {} +"
check "grep excluding both" allow "grep -rn TOKEN . --exclude='.env*' --exclude=.dev.vars"
context=$(jq -n '{tool_input:{command:"grep -rn TOKEN ."}}' | bash "$HOOK" | jq -r '.hookSpecificOutput.additionalContext')
case "$context" in
  *"--exclude='.env*' --exclude=.dev.vars"*) pass=$((pass + 1)); printf '  ok    %-52s %s\n' "the deny message shows the full exclusion" "shown" ;;
  *) fail=$((fail + 1)); printf '  FAIL  %-52s\n' "the deny message shows the full exclusion" ;;
esac

printf '\nAn exclusion counts only when its glob leaves out every env file:\n'
check "--exclude=.env, no star" deny "grep -rn TOKEN . --exclude=.env --exclude=.dev.vars"
check "--exclude-dir of a name holding env" deny "grep -rn TOKEN . --exclude-dir=.venv --exclude=.dev.vars"
check "--exclude-dir skips directories, not files" deny "grep -rn TOKEN . --exclude-dir='.env*' --exclude-dir=.dev.vars"
check "--exclude=.env.*, which keeps .env" deny "grep -rn TOKEN . --exclude='.env.*' --exclude=.dev.vars"
check "--exclude of a path, not a name" deny "grep -rn TOKEN . --exclude='*/.env*' --exclude=.dev.vars"
check "rg -g !.env, no star" deny "rg --no-ignore -g '!.env' -g '!.dev.vars' TOKEN"
check "a glob that covers .dev.vars" allow "grep -rn TOKEN . --exclude='.env*' --exclude='.dev.*'"
check "exclusions after a bare --" deny "grep -rn -- TOKEN . --exclude='.env*' --exclude=.dev.vars"
check "exclusions after a bare --, a dash pattern" deny "grep -rn -- -TOKEN . --exclude='.env*' --exclude=.dev.vars"
check "exclusions before a bare --" allow "grep -rn --exclude='.env*' --exclude=.dev.vars -- -TOKEN ."
check "a scoped search after a bare --" allow "grep -rn -- -TOKEN app/"
check "a flag after a bare -- is the pattern" allow "grep -n -- -r app/lib/cms.ts"
check "find ! -path at any depth" allow "find . ! -path '*/.env*' ! -path '*/.dev.vars' -type f -exec grep -l TOKEN {} +"
check "find ! -path at the top only" deny "find . ! -path './.env*' ! -path './.dev.vars' -type f -exec grep -l TOKEN {} +"

printf '\nA dotfile glob expands to env files whatever letters it spells:\n'
check "grep .*" deny "grep -n TOKEN .*"
check "head .*" deny "head .*"
check "cat .*" deny "cat .*"
check "tail .[!.]*" deny "tail -n 5 .[!.]*"
check "sort .e*" deny "sort .e*"
check "head .[e]nv.local" deny "head .[e]nv.local"
check "a jq path is not a dotfile glob" allow "jq .[0] data.json"

printf '\nCase does not matter on macOS and Windows filesystems:\n'
check "cat .ENV.LOCAL" deny "cat .ENV.LOCAL"
check "head .Env" deny "head .Env"
check "a nested .DEV.VARS" deny "cat apps/edge/.DEV.VARS"
check "a credential store, capitalised" deny "cat ~/.AWS/credentials"
check "an ssh key, capitalised" deny "cat ~/.SSH/id_rsa"
check ".ENV.EXAMPLE is still the example" allow "cat .ENV.EXAMPLE"

printf '\nMore credential stores:\n'
check "git's plaintext store" deny "head ~/.git-credentials"
check "git's XDG store" deny "cat ~/.config/git/credentials"
check "netrc" deny "cat ~/.netrc"
check "pgpass" deny "cat ~/.pgpass"
check "kubeconfig" deny "cat ~/.kube/config"
check "gcloud" deny "cat ~/.config/gcloud/credentials.db"
check "pypirc" deny "cat ~/.pypirc"
check "cargo" deny "cat ~/.cargo/credentials.toml"

printf '\nA CLI that prints a credential is denied past any launcher:\n'
check "security find-generic-password" deny "security find-generic-password -s x -w"
check "pnpm exec security find-generic-password" deny "pnpm exec security find-generic-password -s x -w"
check "pnpm exec security find-internet-password" deny "pnpm exec security find-internet-password -s github.com -w"
check "npx security dump-keychain" deny "npx security dump-keychain"
check "pnpm exec gh auth token" deny "pnpm exec gh auth token"
check "gh auth status --show-token" deny "gh auth status --show-token"
check "pnpm exec op read" deny "pnpm exec op read op://v/i/f"
check "op with a flag before item get" deny "op --account me item get x"
check "pnpm exec printenv" deny "pnpm exec printenv"
check "printenv of one variable" deny "printenv DATABASE_URL"
check "pnpm exec env" deny "pnpm exec env"
check "env into grep" deny "env | grep TOKEN"
check "printenv in a substitution" deny "echo \$(printenv)"
check "git credential fill" deny "printf 'protocol=https\\nhost=github.com\\n\\n' | git credential fill"
check "pnpm exec git credential fill" deny "echo host=github.com | pnpm exec git credential fill"
check "git -C <dir> credential fill" deny "git -C app credential fill"
check "git credential-osxkeychain get" deny "echo host=github.com | git credential-osxkeychain get"
check "git credential-store get" deny "git credential-store get"
check "a helper run by its own name" deny "git-credential-manager get"
check "gh auth git-credential get" deny "echo host=github.com | gh auth git-credential get"
check "npx gh auth git-credential get" deny "npx gh auth git-credential get"
check "git credential fill in a split \$(...)" deny 'creds=$(printf "protocol=https\nhost=github.com\n\n" | git credential fill); echo "$creds"'
check "gh auth git-credential get in a split \$(...)" deny 'out=$(echo host=github.com | gh auth git-credential get); echo "$out"'
check "git credential fill ending a subshell" deny '(echo host=github.com | git credential fill)'
check "a subshell of git credential fill, fed" deny 'printf "host=github.com\n" | (git credential fill)'
check "echo \$(git credential fill)" deny 'echo $(git credential fill)'
check "echo \`git credential fill\`" deny 'echo `git credential fill`'
check "echo \$(gh auth token)" deny 'echo $(gh auth token)'
check "a subshell of printenv" deny '(printenv)'
check "a subshell of git credential approve" allow '(echo host=github.com | git credential approve)'
check "git credential approve stores, never prints" allow "git credential approve"
check "git config get credential.helper" allow "git config get credential.helper"
check "gh auth setup-git" allow "gh auth setup-git"
check "gh auth status" allow "gh auth status"
check "gh pr create -t" allow "gh pr create -t 'fix: token refresh'"
check "security list-keychains" allow "security list-keychains"
check "env running a command" allow "pnpm exec env NODE_ENV=test vitest run"
check "a directory named env" allow "python3 -m venv env"

printf '\nA file list handed to a reader is a sweep of what it lists:\n'
check "find | xargs grep" deny "find . -type f | xargs grep TOKEN"
check "find -print0 | xargs -0 grep" deny "find . -type f -print0 | xargs -0 grep -l TOKEN"
check "grep \$(find)" deny "grep TOKEN \$(find . -type f)"
check "cat \"\$(find)\" of env files, quoted" deny "cat \"\$(find . -name '.env*')\""
check "find into a read loop" deny "find . -type f | while read f; do grep TOKEN \"\$f\"; done"
check "find -o, one side lists anything" deny "find . -name '*.ts' -o -type f | xargs grep TOKEN"
check "find ! ( -name ), a negated group" deny "find . ! \\( -name '*.ts' \\) | xargs cat"
check "find \\! -name, an escaped negation" deny "find . \\! -name '*.ts' | xargs cat"
check "find ( ... ) with no path starts at ." deny "find \\( -type f \\) -exec cat {} +"
check "find -o, both sides other names" allow "find . -name '*.ts' -o -name '*.md' | xargs grep -l TOKEN"
check "ls -A | xargs grep" deny "ls -A | xargs grep TOKEN"
check "grep \$(ls -A)" deny "grep TOKEN \$(ls -A)"
check "a loop over \$(ls -a)" deny "for f in \$(ls -a); do head \$f; done"
check "git ls-files -o | xargs grep" deny "git ls-files -o | xargs grep TOKEN"
check "git ls-files --others --ignored | xargs" deny "git ls-files --others --ignored | xargs cat"
check "grep -r on the directories find names" deny "find apps -name src -exec grep -rn TOKEN {} +"
check "find of .ts files from the root | xargs grep" allow "find . -name '*.ts' | xargs grep -l TOKEN"
check "find | wc" allow "find . -type f | wc -l"
check "ls | xargs, no dotfiles" allow "ls | xargs wc -l"
check "git ls-files | xargs grep (tracked only)" allow "git ls-files | xargs grep -l TOKEN"

printf '\nA sweep below or beside the root is checked on disk:\n'
# Empty files with env-file and credential-store names in a scratch tree: the
# guard looks at names, never at contents.
fx=$(mktemp -d)
mkdir -p "$fx/app/apps/x" "$fx/app/lib" "$fx/sibling" "$fx/home/.config/gh" "$fx/big"
: > "$fx/app/apps/x/.env.development.local"
: > "$fx/sibling/.env.local"
: > "$fx/home/.config/gh/hosts.yml"
: > "$fx/big/a" && : > "$fx/big/b" && : > "$fx/big/c"
check "a nested env file" deny "grep -rn TOKEN apps/" "" "$fx/app"
check "rg --hidden over a nested env file" deny "rg --hidden TOKEN apps/" "" "$fx/app"
check "git grep --untracked over one" deny "git grep --untracked TOKEN apps/" "" "$fx/app"
check "find -exec over one" deny "find apps -type f -exec cat {} +" "" "$fx/app"
check "find | xargs over one" deny "find apps -type f | xargs cat" "" "$fx/app"
check "a glob of directories holding one" deny "grep -rn TOKEN apps/*" "" "$fx/app"
check "a sibling checkout's env file" deny "grep -rn DATABASE_URL ../sibling" "" "$fx/app"
check "cd beside the root, then a relative sweep" deny "cd .. && grep -rn TOKEN sibling/" "" "$fx/app"
check "cd to a place only run time knows" deny "cd \$DIR && grep -rn TOKEN lib/" "" "$fx/app"
check "a directory holding a credential store" deny "grep -rn TOKEN ~/.config" "$fx/home"
check "the home directory, env files excluded" deny "grep -rn TOKEN ~ --exclude='.env*' --exclude=.dev.vars" "$fx/home"
check "a store beside the root, env files excluded" deny "grep -rn TOKEN ~/.config --exclude='.env*' --exclude=.dev.vars" "$fx/home"
check "a directory with no secret file" allow "grep -rn TOKEN lib/" "" "$fx/app"
check "a nested env file, excluded" allow "grep -rn TOKEN apps/ --exclude='.env*' --exclude=.dev.vars" "" "$fx/app"
check "plain rg over a nested env file" allow "rg TOKEN apps/" "" "$fx/app"
got=$(ENV_FILE_GUARD_WALK_LIMIT=2; export ENV_FILE_GUARD_WALK_LIMIT; probe "grep -rn TOKEN $fx/big")
if [ "$got" = deny ]; then
  pass=$((pass + 1)); printf '  ok    %-52s %s\n' "a walk past its limit: deny" "$got"
else
  fail=$((fail + 1)); printf '  FAIL  %-52s got=%s want=deny\n' "a walk past its limit: deny" "$got"
fi

printf '\nA credential store relative to where the command runs is that store:\n'
check "cd ~, then git's store by its bare name" deny "cd ~ && cat .git-credentials" "$fx/home" "$fx/app"
check "cd with no path, then the npm config" deny "cd && cat .npmrc" "$fx/home" "$fx/app"
check "the npm config, run in the home directory" deny "cat .npmrc" "$fx/home" "$fx/home"
check "cd above a store, then a path into it" deny "cd ~/.config && cat gh/hosts.yml" "$fx/home" "$fx/app"
check "cd ~, then python3 -c opens the npm config" deny "cd ~ && python3 -c \"print(open('.npmrc').read())\"" "$fx/home" "$fx/app"
check "cd ~, then node -e reads git's store" deny "cd ~ && node -e \"console.log(require('fs').readFileSync('.git-credentials','utf8'))\"" "$fx/home" "$fx/app"
check "cd ~, then a heredoc into python3" deny "$(printf "cd ~ && python3 - <<PY\nprint(open('.git-credentials').read())\nPY")" "$fx/home" "$fx/app"
check "cd ~, then code piped into python3" deny "cd ~ && echo \"print(open('.npmrc').read())\" | python3" "$fx/home" "$fx/app"
check "node -p, run in the home directory" deny "node -p \"require('fs').readFileSync('.docker/config.json','utf8')\"" "$fx/home" "$fx/home"
check "a project's own .npmrc" allow "cat .npmrc" "$fx/home" "$fx/app"
check "node -p of a project's own .npmrc" allow "node -p \"require('fs').readFileSync('.npmrc','utf8')\"" "$fx/home" "$fx/app"
check "a heredoc into python3, a project's own .npmrc" allow "$(printf "python3 - <<PY\nprint(open('.npmrc').read())\nPY")" "$fx/home" "$fx/app"
check "cd ~, then a file that is no store" allow "cd ~ && cat notes.txt" "$fx/home" "$fx/app"

printf '\nA cd in a subshell, a group or a substitution moves the paths after it:\n'
check "( cd ~/.config && cat gh/hosts.yml )" deny "( cd ~/.config && cat gh/hosts.yml )" "$fx/home" "$fx/app"
check "( cd ~ && cat .npmrc )" deny "( cd ~ && cat .npmrc )" "$fx/home" "$fx/app"
check "x=\$(cd ~/.config && cat gh/hosts.yml)" deny "x=\$(cd ~/.config && cat gh/hosts.yml); echo \"\$x\"" "$fx/home" "$fx/app"
check "echo \$(cd ~ && cat .npmrc)" deny "echo \$(cd ~ && cat .npmrc)" "$fx/home" "$fx/app"
check "echo \$( cd ~ && cat .npmrc )" deny "echo \$( cd ~ && cat .npmrc )" "$fx/home" "$fx/app"
check "echo \`cd ~ && cat .npmrc\`" deny "echo \`cd ~ && cat .npmrc\`" "$fx/home" "$fx/app"
check "{ cd ~ && cat .npmrc; }" deny "{ cd ~ && cat .npmrc; }" "$fx/home" "$fx/app"
check "{ cd ~; } lasts past the group" deny "{ cd ~; } && cat .npmrc" "$fx/home" "$fx/app"
check "( cd ~ && python3 -c ... )" deny "( cd ~ && python3 -c \"print(open('.npmrc').read())\" )" "$fx/home" "$fx/app"
check "( cd ~ && a heredoc into python3 )" deny "$(printf "( cd ~ && python3 - <<PY\nprint(open('.npmrc').read())\nPY\n)")" "$fx/home" "$fx/app"
check "a subshell's cd ends with it" allow "( cd ~ && ls ) && cat .npmrc" "$fx/home" "$fx/app"
check "a glued subshell's cd ends with it" deny "(cd app && ls) && cat .npmrc" "$fx/home" "$fx/home"
check "a spaced subshell's cd ends with it" deny "( cd app && ls ) && cat .npmrc" "$fx/home" "$fx/home"
check "( cd ~ && cat notes.txt )" allow "( cd ~ && cat notes.txt )" "$fx/home" "$fx/app"
check "( printenv )" deny "( printenv )"
check "{ printenv; }" deny "{ printenv; }"
check "echo \$( printenv )" deny "echo \$( printenv )"
check "( FOO=1 printenv )" deny "( FOO=1 printenv )"
check "echo FOO=1 printenv is prose" allow "echo FOO=1 printenv"

printf '\nA cd or a program behind a shell reserved word runs:\n'
check "if ...; else cd ~ && cat .npmrc; fi" deny "if [ -f .npmrc ]; then cat .npmrc; else cd ~ && cat .npmrc; fi" "$fx/home" "$fx/app"
check "if true; then cd ~/.config && cat gh/hosts.yml" deny "if true; then cd ~/.config && cat gh/hosts.yml; fi" "$fx/home" "$fx/app"
check "if cd ~/.config; then cat gh/hosts.yml" deny "if cd ~/.config; then cat gh/hosts.yml; fi" "$fx/home" "$fx/app"
check "while true; do cd ~ && cat .npmrc" deny "while true; do cd ~ && cat .npmrc; break; done" "$fx/home" "$fx/app"
check "while true; do cd ~ && python3 -c ..." deny "while true; do cd ~ && python3 -c \"print(open('.npmrc').read())\"; break; done" "$fx/home" "$fx/app"
check "if true; then cd ~ && a heredoc into python3" deny "$(printf "if true; then cd ~ && python3 - <<PY\nprint(open('.npmrc').read())\nPY\nfi")" "$fx/home" "$fx/app"
check "if true; then printenv; fi" deny "if true; then printenv; fi"
check "for i in 1; do env; done" deny "for i in 1; do env; done"
check "echo if cd ~ is prose" allow "echo if cd ~ && cat .npmrc" "$fx/home" "$fx/app"
check "a commit message \"then cd\" is prose" allow "git commit -m \"then cd\" && cat .npmrc" "$fx/home" "$fx/app"

printf '\nA cd or a program in a case arm runs:\n'
check "case ... in Darwin) cd ~ && cat .npmrc" deny "case \"\$(uname)\" in Darwin) cd ~ && cat .npmrc ;; esac" "$fx/home" "$fx/app"
check "case ... in Darwin) cd ~/.config && cat gh/hosts.yml" deny "case \"\$(uname)\" in Darwin) cd ~/.config && cat gh/hosts.yml ;; esac" "$fx/home" "$fx/app"
check "case \$(uname -s) in Darwin) cd ~ && cat .npmrc" deny "case \$(uname -s) in Darwin) cd ~ && cat .npmrc ;; esac" "$fx/home" "$fx/app"
check "case x in x) pushd ~ && cat .git-credentials" deny "case x in x) pushd ~ && cat .git-credentials;; esac" "$fx/home" "$fx/app"
check "case x in x|y) cd ~;; esac; cat .npmrc" deny "case x in x|y) cd ~;; esac; cat .npmrc" "$fx/home" "$fx/app"
check "case x in (x) cd ~ && cat .npmrc" deny "case x in (x) cd ~ && cat .npmrc;; esac" "$fx/home" "$fx/app"
check "case x in x)cd ~ && cat .npmrc, glued" deny "case x in x)cd ~ && cat .npmrc;; esac" "$fx/home" "$fx/app"
check "case x in \$(echo x)) cd ~ && cat .npmrc" deny "case x in \$(echo x)) cd ~ && cat .npmrc;; esac" "$fx/home" "$fx/app"
check "a later arm: y) cd ~ && cat .npmrc" deny "case y in x) true;; y) cd ~ && cat .npmrc;; esac" "$fx/home" "$fx/app"
check "an arm on its own line" deny "$(printf 'case x in\n  x) cd ~ && cat .npmrc ;;\nesac')" "$fx/home" "$fx/app"
check "a pattern's ) closes no subshell" deny "( cd ~ && case x in x) true;; esac; cat .npmrc )" "$fx/home" "$fx/app"
check "case a in a) printenv;; esac" deny "case a in a) printenv;; esac"
check "case a in a) env;; esac" deny "case a in a) env;; esac"
check "a case pattern is no program" allow "case \"\$1\" in printenv|env) echo usage;; esac"
check "words that never close a pattern are commands" deny "case x in x; printenv"

printf '\nA case arm inside a quoted substitution runs:\n'
check "os=\"\$(case ... Darwin) cd ~/.config && cat gh/hosts.yml)\"" deny "os=\"\$(case \"\$(uname)\" in Darwin) cd ~/.config && cat gh/hosts.yml;; esac)\"" "$fx/home" "$fx/app"
check "echo \"\$(case a in a) cd ~ && cat .npmrc;; esac)\"" deny "echo \"\$(case a in a) cd ~ && cat .npmrc;; esac)\"" "$fx/home" "$fx/app"
check "echo \"\$(case a in a) printenv;; esac)\"" deny "echo \"\$(case a in a) printenv;; esac)\""
check "echo \"\$(case a in a) env;; esac)\"" deny "echo \"\$(case a in a) env;; esac)\""
check "echo \"\$(case a in a) git credential fill;; esac)\"" deny "echo \"\$(case a in a) git credential fill;; esac)\""
check "echo \"\$(case a in a) gh auth git-credential get;; esac)\"" deny "echo \"\$(case a in a) gh auth git-credential get;; esac)\""
check "a later arm: \"\$(case b in a) true;; b) printenv;; esac)\"" deny "echo \"\$(case b in a) true;; b) printenv;; esac)\""
check "an arm after a nested case" deny "echo \"\$(case a in a) case b in b) true;; esac;; c) printenv;; esac)\""
check "a quoted case pattern is no program" allow "echo \"\$(case \"\$1\" in printenv|env) echo usage;; esac)\""
check "prose after a quoted case stays prose" allow "git commit -m \"\$(case a in a) echo x;; esac) mentions .env.local\""

printf '\nA case arm nested deeper in a quoted substitution runs:\n'
check "\"\$(os=\$(case ...); cd ~/.config && cat gh/hosts.yml)\"" deny "v=\"\$(os=\$(case \"\$(uname)\" in Darwin) echo mac;; esac); cd ~/.config && cat gh/hosts.yml)\"" "$fx/home" "$fx/app"
check "\"\$(echo \"\$(case ...)\" && cd ~ && cat .npmrc)\"" deny "echo \"\$(echo \"\$(case a in a) true;; esac)\" && cd ~ && cat .npmrc)\"" "$fx/home" "$fx/app"
check "\"\$( (case ...); cd ~ && cat .npmrc )\"" deny "echo \"\$( (case a in a) true;; esac); cd ~ && cat .npmrc )\"" "$fx/home" "$fx/app"
check "\"\$(echo \$(case ...); cat ~/.npmrc)\"" deny "echo \"\$(echo \$(case a in a) true;; esac); cat ~/.npmrc)\"" "$fx/home" "$fx/app"
for cli in printenv env "git credential fill" "gh auth git-credential get"; do
  check "\"\$(os=\$(case ...); $cli)\"" deny "v=\"\$(os=\$(case \"\$(uname)\" in Darwin) echo mac;; esac); $cli)\""
  check "\"\$(echo \"\$(case ...)\" && $cli)\"" deny "echo \"\$(echo \"\$(case a in a) true;; esac)\" && $cli)\""
  check "\"\$( (case ...); $cli )\"" deny "echo \"\$( (case a in a) true;; esac); $cli )\""
  check "\"\$(echo \$(case ...); $cli)\"" deny "echo \"\$(echo \$(case a in a) true;; esac); $cli)\""
done
check "a nested substitution's quotes end nothing" deny "echo \"\$(echo \"\$(cd ~ && cat .npmrc)\")\"" "$fx/home" "$fx/app"
check "\"\$(os=\$(case ...); echo \"\$os\")\"" allow "v=\"\$(os=\$(case \"\$(uname)\" in Darwin) echo mac;; esac); echo \"\$os\")\""
check "\"\$(echo \"\$(case ...)\" && echo done)\"" allow "echo \"\$(echo \"\$(case a in a) true;; esac)\" && echo done)\""
check "\"\$( (case ...); ls )\"" allow "echo \"\$( (case a in a) true;; esac); ls )\""
check "\"\$(echo \$(case ...); date)\"" allow "echo \"\$(echo \$(case a in a) true;; esac); date)\""
check "a cd in a nested subshell's arm ends with it" allow "echo \"\$( (case a in a) cd ~;; esac); cat .npmrc )\"" "$fx/home" "$fx/app"
check "prose after a nested quoted case stays prose" allow "git commit -m \"\$(echo \"\$(case a in a) echo x;; esac)\") mentions .env.local\""
check "a PR body with a) and a quote stays prose" allow "$(printf "gh pr create --body \"\$(cat <<'EOF'\nIt's a fix: a) one (see \"docs.\nMentions .env.local and cd ~ && cat .npmrc.\nEOF\n)\"")" "$fx/home" "$fx/app"

printf '\nA nested quoted case after a cd closes no subshell:\n'
nested="x=\"\$(echo \"\$(case a in a) :;; esac)\")\""
check "( cd ~ && x=\"\$(...case...)\" && cat .npmrc )" deny "( cd ~ && $nested && cat .npmrc )" "$fx/home" "$fx/app"
check "( cd ~/.config && os=\"\$(...case...)\" && cat gh/hosts.yml )" deny "( cd ~/.config && os=\"\$(echo \"\$(case \"\$(uname)\" in Darwin) echo mac;; esac)\")\" && cat gh/hosts.yml )" "$fx/home" "$fx/app"
check "( cd && x=\"\$(...case...)\" && cat .git-credentials )" deny "( cd && $nested && cat .git-credentials )" "$fx/home" "$fx/app"
check "echo \$(cd ~ && x=\"\$(...case...)\" && cat .npmrc)" deny "echo \$(cd ~ && $nested && cat .npmrc)" "$fx/home" "$fx/app"
check "( cd ~ && x=\"\$(...case...)\" && python3 -c open )" deny "( cd ~ && $nested && python3 -c 'print(open(\".npmrc\").read())' )" "$fx/home" "$fx/app"
check "( cd ~ && x=\"\$(...case...)\" && grep -rn TOKEN .config )" deny "( cd ~ && $nested && grep -rn TOKEN .config )" "$fx/home" "$fx/app"
check "( cd ~ && x=\"\$(...case...)\" && grep -rn TOKEN . --exclude )" deny "( cd ~ && $nested && grep -rn TOKEN . --exclude='.env*' --exclude=.dev.vars )" "$fx/home" "$fx/app"
check "( cd ~ && x=\"\$(...case...)\" ) && cat .npmrc" allow "( cd ~ && $nested ) && cat .npmrc" "$fx/home" "$fx/app"

printf '\nA comment or a $'"'"'...'"'"' string in a quoted substitution hides nothing:\n'
for cli in "printf 'protocol=https\\nhost=github.com\\n\\n' | git credential fill" "gh auth git-credential get" "git credential-osxkeychain get" printenv env "gh auth token"; do
  check "\"\$(# what's stored; $cli)\"" deny "$(printf 'echo "$(\n  # what'"'"'s stored for github.com\n  %s)"' "$cli")"
done
for cli in "git credential fill" printenv env "gh auth token"; do
  check "\"\$(printf \$'it\\'s\\n'; $cli)\"" deny "echo \"\$(printf \$'it\\'s\\n'; $cli)\""
  check "\"\$(os=\$(case ... ;; # isn't ...); $cli)\"" deny "$(printf 'v="$(os=$(case "$(uname)" in\n  Darwin) echo mac ;; # macOS isn'"'"'t linux\nesac); %s)"' "$cli")"
done
check "\"\$(# it's home; cd ~ && cat .npmrc)\"" deny "$(printf 'echo "$(\n  # it'"'"'s in home\n  cd ~ && cat .npmrc)"')" "$fx/home" "$fx/app"
check "\"\$(# what's the date; date)\"" allow "$(printf 'echo "$(\n  # what'"'"'s the date\n  date)"')"
check "\"\$(printf \$'it\\'s\\n'; date)\"" allow "echo \"\$(printf \$'it\\'s\\n'; date)\""
check "\"\$(os=\$(case ... ;; # isn't ...); echo \$os)\"" allow "$(printf 'v="$(os=$(case "$(uname)" in\n  Darwin) echo mac ;; # macOS isn'"'"'t linux\nesac); echo "$os")"')"
check "a # inside a word starts no comment" deny "echo \"\$(echo a#'b'; printenv)\""
for cli in "git credential fill" "gh auth git-credential get" "git credential-osxkeychain get" "gh auth token" printenv env; do
  check "\"\$(echo \$(git rev-parse ...)#L10; $cli)\"" deny "echo \"\$(echo \$(git rev-parse --short HEAD)#L10; $cli)\""
  check "\"\$(echo .../pull/\$(gh pr view ...)#discussion; $cli)\"" deny "echo \"\$(echo https://github.com/o/r/pull/\$(gh pr view --json number -q .number)#discussion; $cli)\""
  check "\"\$(echo \$(date)#x; $cli)\"" deny "echo \"\$(echo \$(date)#x; $cli)\""
  check "\"\$(echo a\\ #b; $cli)\"" deny "echo \"\$(echo a\\ #b; $cli)\""
done
check "\"\$(cat <(echo a)#b; printenv)\"" deny "echo \"\$(cat <(echo a)#b; printenv)\""
check "\"\$(echo \$((1+2))#b; printenv)\"" deny "echo \"\$(echo \$((1+2))#b; printenv)\""
check "a subshell's ) does start a comment" deny "$(printf 'echo "$(\n  (true)# it'"'"'s done\n  printenv)"')"
for cli in "git credential fill" "gh auth git-credential get" printenv "gh auth token"; do
  check "\"\$(echo \$(case ... esac)#L10; $cli)\"" deny "echo \"\$(echo \$(case a in (a) echo hi;; esac)#L10; $cli)\""
  check "\"\$(echo \$(case ... esac)-arm64; $cli)\"" deny "echo \"\$(echo \$(case \"\$(uname)\" in (Darwin) echo mac;; esac)-arm64; $cli)\""
done
check "\"\$(echo \$(case ... esac)#L10; date)\"" allow "echo \"\$(echo \$(case a in (a) echo hi;; esac)#L10; date)\""
# zsh ends `esac` at a glued redirect or `}` as it does at a glued `)`.
for cli in "git credential fill" "gh auth git-credential get" printenv "gh auth token"; do
  check "\"\$(echo \$(case ... esac>/dev/null)#L10; $cli)\"" deny "echo \"\$(echo \$(case a in (a) echo hi;; esac>/dev/null)#L10; $cli)\""
  check "\"\$(echo \$(case ... esac>&2)-arm64; $cli)\"" deny "out=\"\$(echo \$(case \"\$(uname)\" in (Darwin) echo mac;; esac>&2)-arm64; $cli)\""
  check "\"\$(echo \$(case ... esac<&-)-arm64; $cli)\"" deny "out=\"\$(echo \$(case \"\$(uname)\" in (Darwin) echo mac;; esac<&-)-arm64; $cli)\""
  check "\"\$(echo \$(case ... esac&>/dev/null)#L10; $cli)\"" deny "echo \"\$(echo \$(case a in (a) echo hi;; esac&>/dev/null)#L10; $cli)\""
  check "\"\$(echo \$({ case ... esac})#L10; $cli)\"" deny "echo \"\$(echo \$({ case a in (a) echo hi;; esac})#L10; $cli)\""
  check "\"\$(case ... esac>/dev/null\\n$cli)\"" deny "$(printf 'out="$(case "$(uname)" in Darwin) echo mac;; esac>/dev/null\n%s)"' "$cli")"
done
check "\"\$(case ... esac>/dev/null)\"; date" allow "x=\"\$(case a in (a) echo hi;; esac>/dev/null)\"; date"
check "\"\$(echo \$(case ... esac>/dev/null)#L10; date)\"" allow "echo \"\$(echo \$(case a in (a) echo hi;; esac>/dev/null)#L10; date)\""
for cli in printenv "gh auth git-credential get"; do
  check "\"\$(stores=(...)# a) npm, b) git; $cli)\"" deny "$(printf 'out="$(\n  stores=(.npmrc .git-credentials)# a) npm, b) git\n  %s\n)"' "$cli")"
done
check "\"\$(stores=(...)# a) npm, b) git; cd ~ && cat .npmrc)\"" deny "$(printf 'out="$(\n  stores=(.npmrc .git-credentials)# a) npm, b) git\n  cd ~ && cat .npmrc\n)"')" "$fx/home" "$fx/app"
check "\"\$(cfg=(~/.config)# a) gh; cd ~/.config && cat gh/hosts.yml)\"" deny "$(printf 'out="$(\n  cfg=(~/.config)# a) gh\n  cd ~/.config && cat gh/hosts.yml\n)"')" "$fx/home" "$fx/app"
check "\"\$(creds()# 1) ask git, 2) print it; git credential fill)\"" deny "$(printf 'out="$(\n  creds()# 1) ask git, 2) print it\n  { git credential fill; }\n  creds\n)"')"
check "\"\$(f()#)\\n{ :; }; git credential fill)\"" deny "$(printf 'echo "$(f()#)\n{ :; }; git credential fill)"')"
check "\"\$(a=(1)#)\\nprintenv)\"" deny "$(printf 'echo "$(a=(1)#)\nprintenv)"')"
check "\"\$({(true)#)\\n}; printenv)\"" deny "$(printf 'echo "$({(true)#)\n}; printenv)"')"
# zsh reads a glob group (`x(a)`, `f( )`) as part of its word, `#` and all.
check "\"\$(echo x(a)#)\"; printenv; echo \"\\n)\"" deny "$(printf 'echo "$(echo x(a)#)" ; printenv ; echo "\n)"')"
check "\"\$(echo f( )#)\"; git credential fill; echo \"\\n)\"" deny "$(printf 'echo "$(echo f( )#)" ; git credential fill ; echo "\n)"')"
check "\"\$(stores=(...)# a) npm, b) git; date)\"" allow "$(printf 'out="$(\n  stores=(.npmrc .git-credentials)# a) npm, b) git\n  date\n)"')"
check "\"\$(echo \$(date)#x; date)\"" allow "echo \"\$(echo \$(date)#x; date)\""
check "\"\$(echo a\\ #b; date)\"" allow "echo \"\$(echo a\\ #b; date)\""
check "\$'it\\'s'; printenv; \$'don\\'t'" deny "printf \$'it\\'s'; printenv; printf \$'don\\'t'"
check "\"\$(\$'it\\'s'; printenv; \$'don\\'t')\"" deny "echo \"\$(printf \$'it\\'s'; printenv; printf \$'don\\'t')\""
check "x=\$'it\\'s'\"\$(printenv)\"" deny "x=\$'it\\'s'\"\$(printenv)\""
check "a \$'...' commit message is prose" allow "git commit -m \$'it\\'s about .env.local'"

printf '\nA store path in escaped double quotes inside inline code:\n'
check "cd ~, python3 -c open(\\\".npmrc\\\")" deny "cd ~ && python3 -c \"print(open(\\\".npmrc\\\").read())\"" "$fx/home" "$fx/app"
check "cd ~, python3 -c open(\\\".git-credentials\\\")" deny "cd ~ && python3 -c \"print(open(\\\".git-credentials\\\").read())\"" "$fx/home" "$fx/app"
check "cd ~, node -e readFileSync(\\\".git-credentials\\\")" deny "cd ~ && node -e \"console.log(require(\\\"fs\\\").readFileSync(\\\".git-credentials\\\", \\\"utf8\\\"))\"" "$fx/home" "$fx/app"
check "cd ~, ruby -e File.read(\\\".npmrc\\\")" deny "cd ~ && ruby -e \"puts File.read(\\\".npmrc\\\")\"" "$fx/home" "$fx/app"
check "node -p (\\\".docker/config.json\\\"), in home" deny "node -p \"require(\\\"fs\\\").readFileSync(\\\".docker/config.json\\\",\\\"utf8\\\")\"" "$fx/home" "$fx/home"
check "python3 json.load(\\\".docker/config.json\\\"), in home" deny "python3 -c \"import json; print(json.load(open(\\\".docker/config.json\\\")))\"" "$fx/home" "$fx/home"
check "python3 -c open(\\\".npmrc\\\"), a project's own" allow "python3 -c \"print(open(\\\".npmrc\\\").read())\"" "$fx/home" "$fx/app"

printf '\nA store behind a symlinked directory is still that store:\n'
# ~/.config links into a dotfiles repo, as a stow or dotfiles setup does.
mkdir -p "$fx/linked/dotfiles/config/gh" && : > "$fx/linked/dotfiles/config/gh/hosts.yml"
ln -s dotfiles/config "$fx/linked/.config"
check "cd into a linked ~/.config, then gh's hosts" deny "cd ~/.config && cat gh/hosts.yml" "$fx/linked" "$fx/app"
check "cd ~, cd into the link, then gh's hosts" deny "cd ~ && cd .config && cat gh/hosts.yml" "$fx/linked" "$fx/app"
check "cd into the link and back out, then .npmrc" deny "cd ~/.config && cd .. && cat .npmrc" "$fx/linked" "$fx/app"
check "a sweep of a linked ~/.config" deny "grep -rn TOKEN ~/.config" "$fx/linked"
check "the store where the link resolves" deny "cat ~/dotfiles/config/gh/hosts.yml" "$fx/linked"
check "cd into the link, then a file that is no store" allow "cd ~/.config && cat other/settings.json" "$fx/linked" "$fx/app"
rm -r "$fx"

printf '\nEdge cases:\n'
check "empty command" allow ""
check "unbalanced quotes, no env mention" allow "grep -rn 'unterminated app/"
check "unbalanced quotes naming an env file" deny "cat '.env.local"

printf '\n%d passed, %d failed\n' "$pass" "$fail"
[ "$fail" -eq 0 ]
