#!/usr/bin/env bash
# BW Lead Attribution Intelligence — handoff CORS regression check
#
#   bash tests/cors-check.sh <base-url> <allow-listed-origin> [host-header]
#
# e.g.
#   bash tests/cors-check.sh https://example.com https://portal.example.com
#   bash tests/cors-check.sh http://172.17.0.1:3078 https://good.example.com bw-plugins.demoing.info
#
# PREREQUISITE: handoff must be enabled on the target site, with <allow-listed-origin>
# in its allowed-origins list. The routes only exist when the feature is on.
#
# WHY THIS EXISTS
# ---------------
# WordPress core's rest_send_cors_headers() echoes ANY Origin back, with
# Access-Control-Allow-Credentials: true. It sits on the same rest_pre_serve_request
# hook the plugin uses. In 1.4.0 the plugin only ADDED headers for allow-listed
# origins and never removed core's for rejected ones — so the allow-list restricted
# nothing, while looking completely correct from an allow-listed origin.
#
# That is the trap: testing only with a good origin passes. You have to probe with a
# bad one. Hence this script. Run it after any change to the hooks in
# class-bw-lead-ai-handoff-rest.php.
#
# Exits non-zero on failure so it can gate a release.
set -uo pipefail

BASE="${1:-}"
GOOD="${2:-}"
HOSTH="${3:-}"
if [ -z "$BASE" ] || [ -z "$GOOD" ]; then
	echo "usage: bash tests/cors-check.sh <base-url> <allow-listed-origin> [host-header]" >&2
	exit 2
fi

BAD="https://definitely-not-allow-listed.example.net"
URL="$BASE/wp-json/bw-lead-ai/v1/handoff/00000000000000000000000000000000/confirm"
CURL=(curl -s -o /dev/null -D - --max-time 20)
[ -n "$HOSTH" ] && CURL+=(-H "Host: $HOSTH")

pass=0; fail=0
ck() { # ck <description> <expected: yes|no> <haystack> <needle>
	local desc="$1" want="$2" hay="$3" needle="$4" got
	if grep -qi "$needle" <<<"$hay"; then got=yes; else got=no; fi
	if [ "$got" = "$want" ]; then
		pass=$((pass+1)); echo "  PASS  $desc"
	else
		fail=$((fail+1)); echo "  FAIL  $desc (expected $want, got $got)"
	fi
}

echo "target: $URL"
echo "allow-listed origin: $GOOD"
echo

echo "== rejected origin must receive NO CORS grant =="
R=$("${CURL[@]}" -X POST -H "Origin: $BAD" "$URL" 2>&1)
ck "no Access-Control-Allow-Origin"      no "$R" "^access-control-allow-origin:"
ck "no Access-Control-Allow-Credentials" no "$R" "^access-control-allow-credentials:"
ck "no Access-Control-Allow-Methods"     no "$R" "^access-control-allow-methods:"
ck "origin not echoed anywhere"          no "$R" "definitely-not-allow-listed"

echo
echo "== allow-listed origin must receive a grant, without credentials =="
R=$("${CURL[@]}" -X POST -H "Origin: $GOOD" "$URL" 2>&1)
ck "Access-Control-Allow-Origin present"          yes "$R" "^access-control-allow-origin:"
ck "echoes exactly the allow-listed origin"       yes "$R" "^access-control-allow-origin: *${GOOD}[[:space:]]*$"
ck "never a wildcard"                             no  "$R" "^access-control-allow-origin: *\*"
ck "Allow-Credentials NOT advertised"             no  "$R" "^access-control-allow-credentials:"
ck "Vary: Origin present (cache safety)"          yes "$R" "^vary:.*origin"
ck "no-store present"                             yes "$R" "^cache-control:.*no-store"

echo
echo "== OPTIONS preflight from a rejected origin =="
R=$("${CURL[@]}" -X OPTIONS -H "Origin: $BAD" -H "Access-Control-Request-Method: POST" "$URL" 2>&1)
ck "preflight gets no Allow-Origin"      no "$R" "^access-control-allow-origin:"
ck "preflight gets no Allow-Credentials" no "$R" "^access-control-allow-credentials:"

echo
echo "== request with no Origin header at all =="
R=$("${CURL[@]}" -X POST "$URL" 2>&1)
ck "no Allow-Origin when no Origin sent" no "$R" "^access-control-allow-origin:"

echo
echo "===== $pass passed, $fail failed ====="
[ "$fail" -eq 0 ] || exit 1
