111 lines
3.4 KiB
Bash
Executable File
111 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SPEC: wp-snippets/README.md#verification
|
|
# Compliance date: 2026-05-20
|
|
# Launch type: manual post-deployment verification
|
|
# Registry: iqon Phase 1 hardening verification
|
|
|
|
set -u
|
|
|
|
BASE_URL="${1:-https://iqon.com}"
|
|
FAILED=0
|
|
|
|
note() {
|
|
printf '\n[%s] %s\n' "$1" "$2"
|
|
}
|
|
|
|
fail() {
|
|
FAILED=1
|
|
printf '[FAIL] %s\n' "$1"
|
|
}
|
|
|
|
pass() {
|
|
printf '[PASS] %s\n' "$1"
|
|
}
|
|
|
|
fetch_headers() {
|
|
curl -sS -I -L "$BASE_URL/"
|
|
}
|
|
|
|
fetch_home() {
|
|
curl -sS -L "$BASE_URL/"
|
|
}
|
|
|
|
note CHECK "Security headers"
|
|
if ! HEADERS="$(fetch_headers)"; then
|
|
HEADERS=""
|
|
fail 'could not fetch homepage headers'
|
|
fi
|
|
printf '%s\n' "$HEADERS" | rg -qi '^x-content-type-options:\s*nosniff' \
|
|
&& pass 'X-Content-Type-Options present' \
|
|
|| fail 'X-Content-Type-Options missing'
|
|
printf '%s\n' "$HEADERS" | rg -qi '^x-frame-options:\s*SAMEORIGIN' \
|
|
&& pass 'X-Frame-Options present' \
|
|
|| fail 'X-Frame-Options missing'
|
|
printf '%s\n' "$HEADERS" | rg -qi '^referrer-policy:' \
|
|
&& pass 'Referrer-Policy present' \
|
|
|| fail 'Referrer-Policy missing'
|
|
printf '%s\n' "$HEADERS" | rg -qi '^permissions-policy:' \
|
|
&& pass 'Permissions-Policy present' \
|
|
|| fail 'Permissions-Policy missing'
|
|
printf '%s\n' "$HEADERS" | rg -qi '^content-security-policy:' \
|
|
&& pass 'Content-Security-Policy present' \
|
|
|| fail 'Content-Security-Policy missing'
|
|
|
|
note CHECK "Homepage HTML"
|
|
if HOME="$(fetch_home)"; then
|
|
printf '%s\n' "$HOME" | rg -q 'name=["'\'']viewport["'\'']' \
|
|
&& pass 'viewport present' \
|
|
|| fail 'viewport missing'
|
|
printf '%s\n' "$HOME" | rg -q 'class=["'\''][^"'\'']*(iqon-skip-link|skip-link)' \
|
|
&& pass 'skip link present' \
|
|
|| fail 'skip link missing'
|
|
printf '%s\n' "$HOME" | rg -q 'http://www\.iqon\.com|http://iqon\.com|http://maps\.google\.com|http://maps\.googleapis\.com' \
|
|
&& fail 'known HTTP URLs still present' \
|
|
|| pass 'known HTTP URLs absent'
|
|
printf '%s\n' "$HOME" | rg -q 'property=["'\'']og:site_name["'\''][^>]*content=["'\'']- IQON["'\'']' \
|
|
&& fail 'og:site_name still has - IQON' \
|
|
|| pass 'og:site_name no longer has - IQON'
|
|
else
|
|
fail 'could not fetch homepage HTML'
|
|
fi
|
|
|
|
note CHECK "REST users endpoint"
|
|
if USERS_BODY="$(curl -sS -L "$BASE_URL/wp-json/wp/v2/users")"; then
|
|
printf '%s\n' "$USERS_BODY" | rg -q '"slug"\s*:\s*"(admin|iqnadm01)"' \
|
|
&& fail 'public REST users still exposed' \
|
|
|| pass 'public REST users not exposed'
|
|
else
|
|
fail 'could not fetch REST users endpoint'
|
|
fi
|
|
|
|
note CHECK "Install documents"
|
|
README_STATUS="$(curl -sS -o /dev/null -w '%{http_code}' -L "$BASE_URL/readme.html")"
|
|
case "$README_STATUS" in
|
|
403|404) pass "readme.html blocked with $README_STATUS" ;;
|
|
*) fail "readme.html returned $README_STATUS" ;;
|
|
esac
|
|
|
|
note CHECK "XML-RPC HEAD smoke"
|
|
XMLRPC_STATUS="$(curl -sS -o /dev/null -w '%{http_code}' -I --http1.1 "$BASE_URL/xmlrpc.php")"
|
|
XMLRPC_CURL_STATUS=$?
|
|
case "$XMLRPC_STATUS" in
|
|
403|404|405) pass "xmlrpc.php not plainly usable via HEAD: $XMLRPC_STATUS" ;;
|
|
000)
|
|
if [ "$XMLRPC_CURL_STATUS" -eq 52 ]; then
|
|
pass "xmlrpc.php returned empty reply via HEAD: $XMLRPC_STATUS"
|
|
else
|
|
fail "xmlrpc.php check failed with curl status $XMLRPC_CURL_STATUS"
|
|
fi
|
|
;;
|
|
*) fail "xmlrpc.php returned $XMLRPC_STATUS; run safe POST check" ;;
|
|
esac
|
|
|
|
printf '\n'
|
|
if [ "$FAILED" -eq 0 ]; then
|
|
printf '[OK] iqon Phase 1 verification passed for %s\n' "$BASE_URL"
|
|
else
|
|
printf '[FAIL] iqon Phase 1 verification failed for %s\n' "$BASE_URL"
|
|
fi
|
|
|
|
exit "$FAILED"
|