Files
arisingmedia-web-sops/tools/verify-protection.sh
T
2026-06-09 18:31:59 +02:00

123 lines
3.0 KiB
Bash

#!/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 <base-url>
# ./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 <base-url>" >&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