#!/usr/bin/env bash set -euo pipefail # Verify every response class (/, /index.html, a hashed asset) carries the # full security-header set, using the REAL nginx image on a scratch port. # Requires a container runtime (podman or docker). ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" if command -v podman >/dev/null 2>&1; then RUNTIME=podman elif command -v docker >/dev/null 2>&1; then RUNTIME=docker else echo "ERROR: neither podman nor docker found" >&2; exit 2; fi IMAGE="homepage-headercheck-$$" PORT=18099 CID="" trap 'if [ -n "$CID" ]; then $RUNTIME rm -f "$CID" >/dev/null 2>&1 || true; fi' EXIT echo ">> building image ($RUNTIME)..." $RUNTIME build -q -t "$IMAGE" . echo ">> starting container on 127.0.0.1:$PORT..." CID="$($RUNTIME run -d --rm -p 127.0.0.1:$PORT:8080 "$IMAGE")" for i in $(seq 1 30); do curl -sf -o /dev/null "http://127.0.0.1:$PORT/" && break sleep 0.5 if [ "$i" -eq 30 ]; then echo "ERROR: container not ready" >&2; exit 1; fi done ASSET="$(curl -s "http://127.0.0.1:$PORT/" \ | grep -oE '(style|script|terminal)[a-z-]*\.[0-9a-f]{32}\.(css|js)' | head -n1 || true)" if [ -z "$ASSET" ]; then echo "ERROR: no hashed asset found in index.html" >&2; exit 1; fi fail=0 check_headers() { local path="$1" hdrs h hdrs="$(curl -sI "http://127.0.0.1:$PORT$path")" for h in "X-Frame-Options" "X-Content-Type-Options" "Referrer-Policy" "Content-Security-Policy"; do if ! printf '%s' "$hdrs" | grep -qi "^${h}:"; then echo "FAIL: ${h} missing on ${path}" >&2; fail=1 fi done [ "$fail" -eq 0 ] && echo "OK: all security headers present on ${path}" } echo ">> checking headers..." check_headers "/" check_headers "/index.html" check_headers "/${ASSET}" if [ "$fail" -ne 0 ]; then echo "HEADER CHECK FAILED" >&2; exit 1; fi echo "HEADER CHECK PASSED"