fix: harden DWH Nginx integration gates

This commit is contained in:
User
2026-08-21 03:37:01 +02:00
parent 1b18a0fb25
commit d0f7e0497d
2 changed files with 156 additions and 12 deletions
+35 -1
View File
@@ -55,6 +55,10 @@ location_block() {
' "$file"
}
location_declarations() {
effective_lines "$1" | awk "/^location / { print }"
}
contains_exactly_once() {
local haystack=$1
local needle=$2
@@ -70,13 +74,19 @@ contains_line() {
check_templates() {
local http=$1
local location=$2
local http_lines auth_lines unavailable_lines dwh_lines
local http_lines auth_lines unavailable_lines dwh_lines locations
[[ -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/')
locations=$(location_declarations "$location")
[[ $(wc -l <<<"$locations") -eq 3 ]] || return 1
[[ $(grep -Fxc -- "location = /_check_dwh_key {" <<<"$locations" || true) -eq 1 ]] || return 1
[[ $(grep -Fxc -- "location @dwh_auth_unavailable {" <<<"$locations" || true) -eq 1 ]] || return 1
[[ $(grep -Fxc -- "location /dwh/ {" <<<"$locations" || true) -eq 1 ]] || return 1
contains_exactly_once "$auth_lines" 'internal;' || return 1
contains_exactly_once "$auth_lines" 'proxy_method GET;' || return 1
@@ -157,6 +167,24 @@ expect_http_rejected() {
! check_templates "$fixture/http.conf" "$fixture/location.conf"
}
expect_postgrest_regex_bypass_rejected() {
local fixture="$temp_root/postgrest_regex_bypass"
mkdir -- "$fixture"
cp -- "$http_template" "$fixture/http.conf"
cp -- "$location_template" "$fixture/location.conf"
printf "%s\n" "location ~ ^/dwh/ {" " proxy_pass http://127.0.0.1:3001;" "}" >>"$fixture/location.conf"
! check_templates "$fixture/http.conf" "$fixture/location.conf"
}
expect_postgrest_duplicate_bypass_rejected() {
local fixture="$temp_root/postgrest_duplicate_bypass"
mkdir -- "$fixture"
cp -- "$http_template" "$fixture/http.conf"
cp -- "$location_template" "$fixture/location.conf"
printf "%s\n" "location /dwh/ {" " proxy_pass http://127.0.0.1:3001;" "}" >>"$fixture/location.conf"
! 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
@@ -208,6 +236,12 @@ expect_location_rejected postgrest_bypass 'auth_request /_check_dwh_key;' '# dir
|| report_fail negative_postgrest_bypass
report_pass negative_postgrest_bypass
expect_postgrest_regex_bypass_rejected || report_fail negative_postgrest_regex_bypass
report_pass negative_postgrest_regex_bypass
expect_postgrest_duplicate_bypass_rejected || report_fail negative_postgrest_duplicate_bypass
report_pass negative_postgrest_duplicate_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
+121 -11
View File
@@ -27,15 +27,9 @@ 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
stop_registered_pid "$pid" || true
done
registered_pids=()
if [[ "$temp_root" == /tmp/thothii-dwh-auth-nginx-integration.* && -d "$temp_root" ]]; then
rm -rf -- "$temp_root"
fi
@@ -119,13 +113,124 @@ expect_status() {
[[ "$status" == "$expected" ]] || fail_case "$name"
}
unregister_pid() {
local target=$1
local candidate
local retained=()
for candidate in "${registered_pids[@]}"; do
[[ "$candidate" == "$target" ]] || retained+=("$candidate")
done
registered_pids=("${retained[@]}")
}
pid_exited_or_zombie() {
local pid=$1
local state
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
[[ ! -d "/proc/$pid" ]] && return 0
state=$(awk "{print \$3}" "/proc/$pid/stat" 2>/dev/null) || return 0
[[ "$state" == Z* ]]
}
pid_is_direct_child() {
local pid=$1
local parent
[[ -r "/proc/$pid/stat" ]] || return 1
parent=$(awk "{print \$4}" "/proc/$pid/stat" 2>/dev/null) || return 1
[[ "$parent" == "$$" ]]
}
reap_if_direct_child() {
local pid=$1
if pid_is_direct_child "$pid"; then
wait "$pid" 2>/dev/null || true
fi
}
wait_for_exit_or_zombie() {
local pid=$1
local attempts=${2:-10}
local attempt
for ((attempt = 0; attempt < attempts; attempt++)); do
pid_exited_or_zombie "$pid" && return 0
sleep 0.05
done
pid_exited_or_zombie "$pid"
}
tcp_listener_for_pid() {
local pid=$1
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
ss -ltnpH 2>/dev/null | grep -Eq "(^|[^0-9])pid=$pid([,)]|$)"
}
wait_for_tcp_listener_pid() {
local pid=$1
local attempt
for ((attempt = 0; attempt < 10; attempt++)); do
tcp_listener_for_pid "$pid" && return 0
sleep 0.05
done
tcp_listener_for_pid "$pid"
}
stop_registered_pid() {
local pid=$1
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
if kill -0 "$pid" 2>/dev/null; then
kill -TERM "$pid"
wait "$pid"
if pid_exited_or_zombie "$pid"; then
reap_if_direct_child "$pid"
unregister_pid "$pid"
return 0
fi
if ! kill -TERM "$pid" 2>/dev/null; then
wait_for_exit_or_zombie "$pid" 1 || return 1
fi
if ! wait_for_exit_or_zombie "$pid"; then
kill -KILL "$pid" 2>/dev/null || return 1
wait_for_exit_or_zombie "$pid" || return 1
fi
reap_if_direct_child "$pid"
unregister_pid "$pid"
}
run_term_ignored_regression() {
local child_pid started_seconds registered_pid
current_case=cleanup_term_ignored_bounded
python3 -c "import signal; signal.signal(signal.SIGTERM, signal.SIG_IGN); signal.pause()" >"$temp_root/term-ignored.log" 2>&1 &
child_pid=$!
register_pid "$child_pid"
started_seconds=$SECONDS
if ! stop_registered_pid "$child_pid"; then
fail_case cleanup_term_ignored_bounded
fi
if kill -0 "$child_pid" 2>/dev/null; then
fail_case cleanup_term_ignored_bounded
fi
for registered_pid in "${registered_pids[@]}"; do
[[ "$registered_pid" != "$child_pid" ]] || fail_case cleanup_term_ignored_bounded
done
((SECONDS - started_seconds < 3)) || fail_case cleanup_term_ignored_bounded
report_pass cleanup_term_ignored_bounded
}
run_tcp_listener_detector_positive() {
local probe_pid
current_case=tcp_listener_detector_positive
python3 - >"$temp_root/tcp-listener.log" 2>&1 <<PY &
import signal
import socket
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.bind(("127.0.0.1", 0))
listener.listen()
signal.pause()
PY
probe_pid=$!
register_pid "$probe_pid"
wait_for_tcp_listener_pid "$probe_pid" || fail_case tcp_listener_detector_positive
report_pass tcp_listener_detector_positive
stop_registered_pid "$probe_pid" || fail_case tcp_listener_detector_positive
! tcp_listener_for_pid "$probe_pid" || fail_case tcp_listener_detector_positive
}
for command in nginx curl python3 ss date; do
@@ -139,6 +244,8 @@ temp_root=$(mktemp -d /tmp/thothii-dwh-auth-nginx-integration.XXXXXXXX) || fail_
chmod 0700 "$temp_root" || fail_case fixture_root
umask 077
run_term_ignored_regression
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
@@ -197,6 +304,8 @@ register_pid "$verifier_pid"
wait_for_socket "$service_socket" || fail_case verifier_start
report_pass verifier_start
run_tcp_listener_detector_positive
current_case=synthetic_upstreams
AUTH_PROXY_SOCKET="$auth_proxy_socket" \
VERIFIER_SOCKET="$service_socket" \
@@ -370,6 +479,7 @@ 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
! tcp_listener_for_pid "$verifier_pid" || fail_case auth_socket_unix_only
report_pass auth_socket_unix_only
probe_body="$temp_root/probe.body"