test: gate DWH authentication integration

This commit is contained in:
User
2026-08-21 03:12:01 +02:00
parent 62ec29ff92
commit 1b18a0fb25
3 changed files with 701 additions and 0 deletions
+25
View File
@@ -106,6 +106,31 @@ jobs:
- name: Run authentication and authenticated F1 browser smoke
run: bash scripts/authentication-smoke.sh
dwh-auth-linux:
name: DWH authentication Nginx gate
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Check out source
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "1.26.5"
cache-dependency-path: tools/dwh-auth/go.mod
- name: Install Nginx
run: |
sudo apt-get update
sudo apt-get install --yes --no-install-recommends nginx-light
- name: Run DWH authentication gates
run: |
(cd tools/dwh-auth && go test -race ./... -count=1 && go vet ./...)
bash scripts/test-dwh-auth-build-contract.sh
bash scripts/test-dwh-auth-nginx-contract.sh
bash scripts/test-dwh-auth-nginx-integration.sh
linux-docker:
name: Linux Docker deployment and rollback
runs-on: ubuntu-24.04
+219
View File
@@ -0,0 +1,219 @@
#!/usr/bin/env bash
set -euo pipefail
repo_root=$(cd "$(dirname "$0")/.." && pwd -P)
http_template=${DWH_AUTH_NGINX_HTTP:-"$repo_root/deploy/dwh-auth/nginx-http.conf.example"}
location_template=${DWH_AUTH_NGINX_LOCATION:-"$repo_root/deploy/dwh-auth/nginx-dwh-location.conf.example"}
temp_root=
report_pass() {
printf 'case=%s status=PASS\n' "$1"
}
report_fail() {
printf 'case=%s status=FAIL\n' "$1" >&2
exit 1
}
cleanup() {
if [[ "$temp_root" == /tmp/thothii-dwh-auth-nginx-contract.* && -d "$temp_root" ]]; then
rm -rf -- "$temp_root"
fi
}
trap cleanup EXIT
effective_lines() {
awk '
{
line = $0
sub(/[[:space:]]*#.*/, "", line)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
gsub(/[[:space:]]+/, " ", line)
if (line != "") print line
}
' "$1"
}
location_block() {
local file=$1
local location=$2
awk -v expected="location $location {" '
function normalize(line) {
sub(/[[:space:]]*#.*/, "", line)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
gsub(/[[:space:]]+/, " ", line)
return line
}
{
line = normalize($0)
if (!inside && line == expected) inside = 1
if (inside) {
if (line != "") print line
if (line == "}") exit
}
}
' "$file"
}
contains_exactly_once() {
local haystack=$1
local needle=$2
[[ $(grep -Fxc -- "$needle" <<<"$haystack" || true) -eq 1 ]]
}
contains_line() {
local haystack=$1
local needle=$2
grep -Fqx -- "$needle" <<<"$haystack"
}
check_templates() {
local http=$1
local location=$2
local http_lines auth_lines unavailable_lines dwh_lines
[[ -f "$http" && -f "$location" ]] || return 1
http_lines=$(effective_lines "$http")
auth_lines=$(location_block "$location" '= /_check_dwh_key')
unavailable_lines=$(location_block "$location" '@dwh_auth_unavailable')
dwh_lines=$(location_block "$location" '/dwh/')
contains_exactly_once "$auth_lines" 'internal;' || return 1
contains_exactly_once "$auth_lines" 'proxy_method GET;' || return 1
contains_exactly_once "$auth_lines" 'proxy_pass http://unix:/run/dwh-auth/verify.sock:/verify;' || return 1
contains_exactly_once "$auth_lines" 'proxy_pass_request_body off;' || return 1
contains_exactly_once "$auth_lines" 'proxy_pass_request_headers off;' || return 1
contains_exactly_once "$auth_lines" 'proxy_set_header Content-Length "";' || return 1
contains_exactly_once "$auth_lines" 'proxy_set_header X-API-Key $http_x_api_key;' || return 1
contains_exactly_once "$unavailable_lines" 'return 503;' || return 1
contains_line "$dwh_lines" 'location /dwh/ {' || return 1
contains_exactly_once "$dwh_lines" 'limit_req zone=dwh_auth burst=100 nodelay;' || return 1
contains_exactly_once "$dwh_lines" 'auth_request /_check_dwh_key;' || return 1
contains_exactly_once "$dwh_lines" 'auth_request_set $dwh_key_id $upstream_http_x_dwh_key_id;' || return 1
contains_exactly_once "$dwh_lines" 'error_page 500 =503 @dwh_auth_unavailable;' || return 1
contains_exactly_once "$dwh_lines" 'proxy_set_header X-API-Key "";' || return 1
contains_exactly_once "$dwh_lines" 'proxy_set_header X-DWH-Key-ID "";' || return 1
contains_exactly_once "$dwh_lines" 'proxy_set_header Host $host;' || return 1
contains_exactly_once "$dwh_lines" 'proxy_pass http://127.0.0.1:3001;' || return 1
contains_exactly_once "$http_lines" 'map $http_x_api_key $dwh_public_key_class {' || return 1
contains_line "$http_lines" 'default opaque;' || return 1
contains_line "$http_lines" '"~^thtdwh_v1\.([A-Za-z0-9_-]{16})\.[A-Za-z0-9_-]{43}$" v1:$1;' || return 1
contains_exactly_once "$http_lines" 'map "$remote_addr:$dwh_public_key_class" $dwh_auth_rate_key {' || return 1
contains_exactly_once "$http_lines" 'limit_req_zone $dwh_auth_rate_key zone=dwh_auth:10m rate=20r/s;' || return 1
! grep -Eq 'limit_req_zone.*\$(http_x_api_key|dwh_key_secret|request)' <<<"$http_lines" || return 1
! grep -Eq 'map .*\$http_x_api_key .*\$dwh_auth_rate_key' <<<"$http_lines" || return 1
}
replace_effective_line() {
local file=$1
local needle=$2
local replacement=$3
local output="$file.replaced"
awk -v needle="$needle" -v replacement="$replacement" '
function normalize(line) {
sub(/[[:space:]]*#.*/, "", line)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
gsub(/[[:space:]]+/, " ", line)
return line
}
{
if (normalize($0) == needle) {
print replacement
replaced++
next
}
print
}
END { if (replaced != 1) exit 1 }
' "$file" >"$output" || return 1
mv -- "$output" "$file"
}
expect_location_rejected() {
local name=$1
local needle=$2
local replacement=$3
local fixture="$temp_root/$name"
mkdir -- "$fixture"
cp -- "$http_template" "$fixture/http.conf"
cp -- "$location_template" "$fixture/location.conf"
replace_effective_line "$fixture/location.conf" "$needle" "$replacement" || return 1
! check_templates "$fixture/http.conf" "$fixture/location.conf"
}
expect_http_rejected() {
local name=$1
local needle=$2
local replacement=$3
local fixture="$temp_root/$name"
mkdir -- "$fixture"
cp -- "$http_template" "$fixture/http.conf"
cp -- "$location_template" "$fixture/location.conf"
replace_effective_line "$fixture/http.conf" "$needle" "$replacement" || return 1
! check_templates "$fixture/http.conf" "$fixture/location.conf"
}
[[ -f "$http_template" ]] || report_fail source_http_exists
[[ -f "$location_template" ]] || report_fail source_location_exists
check_templates "$http_template" "$location_template" || report_fail source_contract
report_pass source_contract
temp_root=$(mktemp -d /tmp/thothii-dwh-auth-nginx-contract.XXXXXXXX) || report_fail fixture_root
expect_location_rejected missing_auth_request 'auth_request /_check_dwh_key;' '# removed auth request' \
|| report_fail negative_missing_auth_request
report_pass negative_missing_auth_request
expect_location_rejected missing_proxy_method 'proxy_method GET;' '# removed proxy method' \
|| report_fail negative_missing_proxy_method
report_pass negative_missing_proxy_method
expect_location_rejected missing_proxy_body 'proxy_pass_request_body off;' '# removed proxy body suppression' \
|| report_fail negative_missing_proxy_body
report_pass negative_missing_proxy_body
expect_location_rejected missing_proxy_header_isolation 'proxy_pass_request_headers off;' '# removed proxy header isolation' \
|| report_fail negative_missing_proxy_header_isolation
report_pass negative_missing_proxy_header_isolation
expect_location_rejected missing_content_length_clear 'proxy_set_header Content-Length "";' '# removed content length clear' \
|| report_fail negative_missing_content_length_clear
report_pass negative_missing_content_length_clear
expect_location_rejected missing_verifier_key_forward 'proxy_set_header X-API-Key $http_x_api_key;' '# removed verifier key forwarding' \
|| report_fail negative_missing_verifier_key_forward
report_pass negative_missing_verifier_key_forward
expect_location_rejected missing_upstream_key_clear 'proxy_set_header X-API-Key "";' '# removed upstream key clear' \
|| report_fail negative_missing_upstream_key_clear
report_pass negative_missing_upstream_key_clear
expect_location_rejected missing_failure_mapping 'error_page 500 =503 @dwh_auth_unavailable;' '# removed failure mapping' \
|| report_fail negative_missing_failure_mapping
report_pass negative_missing_failure_mapping
expect_location_rejected public_verifier 'internal;' '# verifier became public' \
|| report_fail negative_public_verifier
report_pass negative_public_verifier
expect_location_rejected tcp_authenticator 'proxy_pass http://unix:/run/dwh-auth/verify.sock:/verify;' 'proxy_pass http://127.0.0.1:19091/verify;' \
|| report_fail negative_tcp_authenticator
report_pass negative_tcp_authenticator
expect_location_rejected postgrest_bypass 'auth_request /_check_dwh_key;' '# direct PostgREST bypass' \
|| report_fail negative_postgrest_bypass
report_pass negative_postgrest_bypass
expect_location_rejected failure_mapped_to_success 'error_page 500 =503 @dwh_auth_unavailable;' 'error_page 500 =200 @dwh_auth_unavailable;' \
|| report_fail negative_failure_mapped_to_success
report_pass negative_failure_mapped_to_success
expect_http_rejected full_secret_rate_key 'map "$remote_addr:$dwh_public_key_class" $dwh_auth_rate_key {' 'map "$remote_addr:$http_x_api_key" $dwh_auth_rate_key {' \
|| report_fail negative_full_secret_rate_key
report_pass negative_full_secret_rate_key
report_pass summary
+457
View File
@@ -0,0 +1,457 @@
#!/usr/bin/env bash
set -euo pipefail
repo_root=$(cd "$(dirname "$0")/.." && pwd -P)
go_image='golang:1.26.5-bookworm@sha256:1ecb7edf62a0408027bd5729dfd6b1b8766e578e8df93995b225dfd0944eb651'
temp_root=
current_case=setup
failure_reported=false
registered_pids=()
report_pass() {
printf 'case=%s status=PASS\n' "$1"
}
fail_case() {
current_case=$1
failure_reported=true
printf 'case=%s status=FAIL\n' "$current_case" >&2
exit 1
}
register_pid() {
registered_pids+=("$1")
}
cleanup() {
local pid
set +e
for pid in "${registered_pids[@]}"; do
if [[ "$pid" =~ ^[0-9]+$ ]] && kill -0 "$pid" 2>/dev/null; then
kill -TERM "$pid" 2>/dev/null
fi
done
for pid in "${registered_pids[@]}"; do
if [[ "$pid" =~ ^[0-9]+$ ]]; then
wait "$pid" 2>/dev/null
fi
done
if [[ "$temp_root" == /tmp/thothii-dwh-auth-nginx-integration.* && -d "$temp_root" ]]; then
rm -rf -- "$temp_root"
fi
}
on_exit() {
local exit_code=$?
cleanup
if ((exit_code != 0)) && [[ "$failure_reported" != true ]]; then
printf 'case=%s status=FAIL\n' "$current_case" >&2
fi
exit "$exit_code"
}
trap on_exit EXIT
trap 'exit 130' INT TERM
wait_for_socket() {
local socket=$1
local attempt
for attempt in $(seq 1 100); do
[[ -S "$socket" ]] && return 0
sleep 0.05
done
return 1
}
wait_for_file() {
local file=$1
local attempt
for attempt in $(seq 1 100); do
[[ -s "$file" ]] && return 0
sleep 0.05
done
return 1
}
build_dwh_auth() {
local output=$1
if command -v go >/dev/null 2>&1; then
(
cd "$repo_root/tools/dwh-auth"
go build -o "$output" ./cmd/dwh-auth
)
return
fi
command -v docker >/dev/null 2>&1 || return 1
docker run --rm --network none --user "$(id -u):$(id -g)" \
--volume "$repo_root:/work:ro" \
--volume "$temp_root:/out" \
--workdir /work/tools/dwh-auth \
"$go_image" \
/bin/sh -ec 'GOCACHE=/out/go-cache CGO_ENABLED=0 go build -o /out/dwh-auth ./cmd/dwh-auth'
}
v1_key_id() {
local value=$1
local remainder=${value#thtdwh_v1.}
printf '%s' "${remainder%%.*}"
}
request_status() {
local body=$1
shift
curl --silent --show-error --noproxy '*' \
--unix-socket "$nginx_socket" \
--output "$body" \
--write-out '%{http_code}' \
"$@" 2>"$temp_root/curl.stderr"
}
expect_status() {
local name=$1
local expected=$2
local body=$3
shift 3
local status
current_case=$name
if ! status=$(request_status "$body" "$@"); then
fail_case "$name"
fi
[[ "$status" == "$expected" ]] || fail_case "$name"
}
stop_registered_pid() {
local pid=$1
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
if kill -0 "$pid" 2>/dev/null; then
kill -TERM "$pid"
wait "$pid"
fi
}
for command in nginx curl python3 ss date; do
command -v "$command" >/dev/null 2>&1 || fail_case "missing_${command}"
done
nginx_version=$(nginx -v 2>&1)
[[ "$nginx_version" == *nginx/1.24.* ]] || fail_case nginx_version
report_pass nginx_1_24
temp_root=$(mktemp -d /tmp/thothii-dwh-auth-nginx-integration.XXXXXXXX) || fail_case fixture_root
chmod 0700 "$temp_root" || fail_case fixture_root
umask 077
dwh_auth="$temp_root/dwh-auth"
current_case=build_dwh_auth
build_dwh_auth "$dwh_auth" >"$temp_root/build.log" 2>&1 || fail_case build_dwh_auth
[[ -x "$dwh_auth" ]] || fail_case build_dwh_auth
report_pass build_dwh_auth
registry_root="$temp_root/registry"
socket_parent="$temp_root/socket"
service_socket="$socket_parent/verify.sock"
auth_proxy_socket="$socket_parent/nginx-auth.sock"
nginx_prefix="$temp_root/nginx"
nginx_socket="$nginx_prefix/listener.sock"
nginx_config="$nginx_prefix/nginx.conf"
runtime_http="$nginx_prefix/http.conf"
runtime_location="$nginx_prefix/location.conf"
marker_port_file="$temp_root/marker-port"
marker_observations="$temp_root/marker-observations.jsonl"
auth_observations="$temp_root/auth-observations.jsonl"
mkdir "$registry_root" "$socket_parent" "$nginx_prefix" || fail_case fixture_directories
chmod 0750 "$registry_root"
chmod 0700 "$socket_parent" "$nginx_prefix"
v1_file="$temp_root/v1.key"
legacy_file="$temp_root/legacy.key"
revoked_file="$temp_root/revoked.key"
expired_file="$temp_root/expired.key"
current_case=registry_setup
"$dwh_auth" --registry-root "$registry_root" key create --installation-id synthetic-primary --output "$v1_file" \
>"$temp_root/cli.log" 2>&1 || fail_case registry_setup
printf '%s' 'synthetic-legacy-ordinary' >"$legacy_file"
chmod 0600 "$legacy_file"
"$dwh_auth" --registry-root "$registry_root" key import --legacy-raw --installation-id legacy-shared --from-file "$legacy_file" \
>"$temp_root/cli.log" 2>&1 || fail_case registry_setup
"$dwh_auth" --registry-root "$registry_root" key create --installation-id synthetic-revoked --output "$revoked_file" \
>"$temp_root/cli.log" 2>&1 || fail_case registry_setup
revoked_key=$(<"$revoked_file")
revoked_id=$(v1_key_id "$revoked_key")
"$dwh_auth" --registry-root "$registry_root" key revoke --key-id "$revoked_id" --reason synthetic \
>"$temp_root/cli.log" 2>&1 || fail_case registry_setup
expires_at=$(date --utc --date='2 seconds' '+%Y-%m-%dT%H:%M:%SZ')
"$dwh_auth" --registry-root "$registry_root" key create --installation-id synthetic-expired --expires-at "$expires_at" --output "$expired_file" \
>"$temp_root/cli.log" 2>&1 || fail_case registry_setup
sleep 3
v1_key=$(<"$v1_file")
legacy_key=$(<"$legacy_file")
expired_key=$(<"$expired_file")
report_pass registry_setup
current_case=verifier_start
"$dwh_auth" serve --registry-root "$registry_root" --socket "$service_socket" \
>"$temp_root/verifier.log" 2>&1 &
verifier_pid=$!
register_pid "$verifier_pid"
wait_for_socket "$service_socket" || fail_case verifier_start
report_pass verifier_start
current_case=synthetic_upstreams
AUTH_PROXY_SOCKET="$auth_proxy_socket" \
VERIFIER_SOCKET="$service_socket" \
MARKER_PORT_FILE="$marker_port_file" \
MARKER_OBSERVATIONS="$marker_observations" \
AUTH_OBSERVATIONS="$auth_observations" \
python3 - >"$temp_root/upstreams.log" 2>&1 <<'PY' &
import http.client
import http.server
import json
import os
import signal
import socket
import socketserver
import sys
import threading
proxy_socket = os.environ["AUTH_PROXY_SOCKET"]
verifier_socket = os.environ["VERIFIER_SOCKET"]
marker_port_file = os.environ["MARKER_PORT_FILE"]
marker_observations = os.environ["MARKER_OBSERVATIONS"]
auth_observations = os.environ["AUTH_OBSERVATIONS"]
def append_json(path, value):
with open(path, "a", encoding="utf-8") as handle:
handle.write(json.dumps(value, sort_keys=True, separators=(",", ":")) + "\n")
class UnixHTTPConnection(http.client.HTTPConnection):
def __init__(self, path):
super().__init__("localhost")
self.path = path
def connect(self):
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.connect(self.path)
class AuthProxy(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def log_message(self, _format, *_args):
pass
def do_GET(self):
names = sorted(
name.lower()
for name in self.headers.keys()
if name.lower() not in {"host", "connection"}
)
append_json(
auth_observations,
{
"client_header_names": names,
"has_authorization": "authorization" in self.headers,
"has_cookie": "cookie" in self.headers,
"has_dwh_key_id": "x-dwh-key-id" in self.headers,
"method": self.command,
"path": self.path,
},
)
try:
connection = UnixHTTPConnection(verifier_socket)
connection.request(self.command, self.path, headers=dict(self.headers.items()))
response = connection.getresponse()
payload = response.read()
self.send_response(response.status)
for name, value in response.getheaders():
if name.lower() not in {"connection", "transfer-encoding", "content-length"}:
self.send_header(name, value)
self.send_header("Content-Length", str(len(payload)))
self.end_headers()
self.wfile.write(payload)
connection.close()
except OSError:
self.send_response(500)
self.send_header("Content-Length", "0")
self.end_headers()
class UnixHTTPServer(socketserver.ThreadingMixIn, socketserver.UnixStreamServer):
daemon_threads = True
class Marker(http.server.BaseHTTPRequestHandler):
def log_message(self, _format, *_args):
pass
def do_GET(self):
append_json(
marker_observations,
{
"has_api_key": "x-api-key" in self.headers,
"has_dwh_key_id": "x-dwh-key-id" in self.headers,
"path": self.path,
},
)
payload = b"postgrest-marker\n"
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(payload)))
self.end_headers()
self.wfile.write(payload)
for path in (proxy_socket,):
try:
os.unlink(path)
except FileNotFoundError:
pass
marker = http.server.ThreadingHTTPServer(("127.0.0.1", 0), Marker)
auth_proxy = UnixHTTPServer(proxy_socket, AuthProxy)
os.chmod(proxy_socket, 0o600)
with open(marker_port_file, "w", encoding="ascii") as handle:
handle.write(str(marker.server_address[1]))
for server in (marker, auth_proxy):
threading.Thread(target=server.serve_forever, daemon=True).start()
signal.pause()
PY
upstreams_pid=$!
register_pid "$upstreams_pid"
wait_for_socket "$auth_proxy_socket" || fail_case synthetic_upstreams
wait_for_file "$marker_port_file" || fail_case synthetic_upstreams
marker_port=$(<"$marker_port_file")
[[ "$marker_port" =~ ^[0-9]+$ ]] || fail_case synthetic_upstreams
report_pass synthetic_upstreams
current_case=render_nginx
cp -- "$repo_root/deploy/dwh-auth/nginx-http.conf.example" "$runtime_http"
sed \
-e "s|http://unix:/run/dwh-auth/verify.sock:/verify|http://unix:$auth_proxy_socket:/verify|" \
-e "s|http://127.0.0.1:3001|http://127.0.0.1:$marker_port|" \
"$repo_root/deploy/dwh-auth/nginx-dwh-location.conf.example" >"$runtime_location"
cat >"$nginx_config" <<EOF
worker_processes 1;
pid $nginx_prefix/nginx.pid;
error_log $nginx_prefix/error.log crit;
events {
worker_connections 16;
}
http {
access_log $nginx_prefix/access.log;
include $runtime_http;
server {
listen unix:$nginx_socket;
server_name synthetic;
include $runtime_location;
}
}
EOF
nginx -t -p "$nginx_prefix" -c "$nginx_config" >"$temp_root/nginx-test.log" 2>&1 || fail_case render_nginx
report_pass composite_nginx_config
current_case=nginx_start
nginx -p "$nginx_prefix" -c "$nginx_config" >"$temp_root/nginx-start.log" 2>&1 || fail_case nginx_start
wait_for_file "$nginx_prefix/nginx.pid" || fail_case nginx_start
nginx_pid=$(<"$nginx_prefix/nginx.pid")
[[ "$nginx_pid" =~ ^[0-9]+$ ]] || fail_case nginx_start
register_pid "$nginx_pid"
wait_for_socket "$nginx_socket" || fail_case nginx_start
report_pass nginx_start
current_case=auth_socket_unix_only
[[ -S "$service_socket" ]] || fail_case auth_socket_unix_only
ss -xl >"$temp_root/ss-unix.log" 2>&1 || fail_case auth_socket_unix_only
grep -Fq -- "$service_socket" "$temp_root/ss-unix.log" || fail_case auth_socket_unix_only
report_pass auth_socket_unix_only
probe_body="$temp_root/probe.body"
expect_status verifier_not_public 404 "$probe_body" 'http://synthetic/_check_dwh_key'
report_pass verifier_not_public
route_url='http://synthetic/dwh/?keep=exact&second=two'
expect_status valid_v1 200 "$probe_body" \
-H "X-API-Key: $v1_key" \
-H 'Cookie: synthetic-session=one' \
-H 'Authorization: Bearer synthetic' \
-H 'X-DWH-Key-ID: client-spoof' \
"$route_url"
[[ $(<"$probe_body") == 'postgrest-marker' ]] || fail_case valid_v1
report_pass valid_v1
expect_status valid_legacy 200 "$probe_body" -H "X-API-Key: $legacy_key" 'http://synthetic/dwh/?legacy=one'
[[ $(<"$probe_body") == 'postgrest-marker' ]] || fail_case valid_legacy
report_pass valid_legacy
expect_status invalid_key 401 "$probe_body" \
-H 'X-API-Key: thtdwh_v1.AAAAAAAAAAAAAAAA.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' \
'http://synthetic/dwh/?invalid=one'
report_pass invalid_key
expect_status revoked_key 401 "$probe_body" -H "X-API-Key: $revoked_key" 'http://synthetic/dwh/?revoked=one'
report_pass revoked_key
expect_status expired_key 401 "$probe_body" -H "X-API-Key: $expired_key" 'http://synthetic/dwh/?expired=one'
report_pass expired_key
expect_status duplicate_v1 401 "$probe_body" \
-H "X-API-Key: $v1_key" \
-H "X-API-Key: $v1_key" \
'http://synthetic/dwh/?duplicate=v1'
report_pass duplicate_v1
expect_status duplicate_legacy 401 "$probe_body" \
-H "X-API-Key: $legacy_key" \
-H "X-API-Key: $legacy_key" \
'http://synthetic/dwh/?duplicate=legacy'
report_pass duplicate_legacy
current_case=stopped_verifier
stop_registered_pid "$verifier_pid" || fail_case stopped_verifier
expect_status stopped_verifier 503 "$probe_body" -H "X-API-Key: $v1_key" 'http://synthetic/dwh/?unavailable=one'
report_pass stopped_verifier
current_case=header_and_path_isolation
AUTH_OBSERVATIONS="$auth_observations" MARKER_OBSERVATIONS="$marker_observations" python3 - >"$temp_root/assertions.log" 2>&1 <<'PY' || fail_case header_and_path_isolation
import json
import os
def load(path):
with open(path, encoding="utf-8") as handle:
return [json.loads(line) for line in handle if line.strip()]
auth = load(os.environ["AUTH_OBSERVATIONS"])
marker = load(os.environ["MARKER_OBSERVATIONS"])
assert len(auth) == 8
for request in auth:
assert request["method"] == "GET"
assert request["path"] == "/verify"
assert request["client_header_names"] == ["x-api-key"]
assert not request["has_authorization"]
assert not request["has_cookie"]
assert not request["has_dwh_key_id"]
assert len(marker) == 2
assert marker[0] == {
"has_api_key": False,
"has_dwh_key_id": False,
"path": "/dwh/?keep=exact&second=two",
}
assert marker[1] == {
"has_api_key": False,
"has_dwh_key_id": False,
"path": "/dwh/?legacy=one",
}
PY
report_pass header_and_path_isolation
report_pass summary