#!/usr/bin/env bash # verify-protection.sh — confirm a deployed Arising Media site is not leaking # build artifacts, server config, or dotfiles to the public web. # # Usage: # ./verify-protection.sh # ./verify-protection.sh http://localhost:8010 # ./verify-protection.sh https://cobhamtech.com # # Exit 0 if every check passes, 1 otherwise. Designed to be run after every # deploy and in CI. set -euo pipefail BASE="${1:-}" if [[ -z "$BASE" ]]; then echo "usage: $0 " >&2 exit 2 fi BASE="${BASE%/}" # Required paths — site must serve these; missing = audit FAIL. REQUIRED=( "/" ) # Public paths — should be reachable; missing = WARN (content gap, not a leak). PUBLIC=( "/robots.txt" "/sitemap.xml" ) # Sensitive paths — must NOT return 200. 404 or 403 is acceptable. # This list mirrors the deny patterns in SOP 08 nginx.conf. SENSITIVE=( "/Dockerfile" "/dockerfile" "/docker-compose.yml" "/nginx.conf" "/.dockerignore" "/.gitignore" "/.git/config" "/.git/HEAD" "/.env" "/.env.example" "/api/.env" "/.planning/" "/.planning/build_locations.py" "/.planning/build_services.py" "/.planning/regen_images.py" "/.planning/playwright_audit.py" "/__pycache__/" "/build_locations.py" "/build_services.py" "/regen_images.py" "/playwright_audit.py" "/server.py" "/main.py" "/README.md" "/package.json" "/composer.json" ) fail=0 warn=0 probe() { local path="$1" local expect="$2" # public | required | sensitive local code code=$(curl -k -s -o /dev/null -w '%{http_code}' --max-time 5 "${BASE}${path}" || echo "000") case "$expect" in required) if [[ "$code" =~ ^(200|301|302|304)$ ]]; then printf ' OK %-3s %s\n' "$code" "$path" else printf ' FAIL %-3s %s (required public path unreachable)\n' "$code" "$path" fail=1 fi ;; public) if [[ "$code" =~ ^(200|301|302|304)$ ]]; then printf ' OK %-3s %s\n' "$code" "$path" else printf ' WARN %-3s %s (public path unreachable — content gap, not a leak)\n' "$code" "$path" warn=1 fi ;; sensitive) if [[ "$code" == "200" ]]; then printf ' LEAK %-3s %s (must not return 200)\n' "$code" "$path" fail=1 else printf ' OK %-3s %s\n' "$code" "$path" fi ;; esac } echo "Verifying ${BASE}" echo echo "Required paths (site must serve these):" for p in "${REQUIRED[@]}"; do probe "$p" required; done echo echo "Public paths (should be reachable):" for p in "${PUBLIC[@]}"; do probe "$p" public; done echo echo "Sensitive paths (must not be reachable):" for p in "${SENSITIVE[@]}"; do probe "$p" sensitive; done echo if [[ $fail -ne 0 ]]; then echo "FAIL — exposure or required-path failure at ${BASE}" >&2 exit 1 elif [[ $warn -ne 0 ]]; then echo "PASS (with warnings) — no exposure at ${BASE}, but missing public content" exit 0 else echo "PASS — no exposure detected at ${BASE}" exit 0 fi