diff mrjunejune/test/config_validation_test.sh @ 264:04fee26ecce0

add authenticated JRPG conversation platform Add reusable auth/session storage, owned conversation recovery, guest quotas, admin workflows, URL-routed conversation UI, mobile frame support, and parallel browser acceptance. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Fri, 07 Aug 2026 07:34:12 -0700
parents
children 056790c4fb0d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/config_validation_test.sh	Fri Aug 07 07:34:12 2026 -0700
@@ -0,0 +1,247 @@
+#!/usr/bin/env bash
+# config_validation_test.sh — startup config validation tests.
+#
+# Verifies that the server binary exits 1 (fail-closed) on bad config,
+# starts cleanly on env-only config (no .config file), and enforces the
+# loopback requirement for AUTH_DEV_INSECURE_COOKIE.
+#
+# Bazel passes the server binary path as $1.
+set -euo pipefail
+
+server="$(realpath "$1")"
+tmpdir="$(mktemp -d)"
+trap 'rm -rf "$tmpdir"' EXIT
+
+pass() { printf "  %-62s PASS\n" "$1"; }
+fail() { echo "FAIL: $1" >&2; exit 1; }
+
+# A valid 64-hex-char secret (32 random bytes) for success cases.
+GOOD_SECRET="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+
+# Helper: run $@ as a command, expect it to exit non-zero ≤ 3 seconds.
+run_expect_fail() {
+  local label="$1"; shift
+  local out
+  set +e
+  out=$(timeout 3 "$@" 2>&1)
+  local code=$?
+  set -e
+  if [[ $code -eq 0 || $code -eq 124 ]]; then
+    echo "FAIL: '$label' — expected exit 1, got code $code" >&2
+    echo "$out" >&2
+    exit 1
+  fi
+  pass "$label"
+}
+
+# Helper: run $@ as a command; expect it to emit an "Initialised" or
+# listen/startup log line within 5 seconds, then kill it.
+run_expect_start() {
+  local label="$1"; shift
+  local logfile="$tmpdir/start_${RANDOM}.log"
+  set +e
+  timeout 5 "$@" >"$logfile" 2>&1 &
+  local pid=$!
+  local started=false
+  for _ in $(seq 1 50); do
+    sleep 0.1
+    if grep -q -E 'Initialised|Listening|WTF is going on' "$logfile" 2>/dev/null; then
+      started=true
+      break
+    fi
+    if ! kill -0 "$pid" 2>/dev/null; then
+      break
+    fi
+  done
+  kill "$pid" 2>/dev/null || true
+  wait "$pid" 2>/dev/null || true
+  set -e
+  if [[ "$started" != "true" ]]; then
+    echo "FAIL: '$label' — server did not start (log below)" >&2
+    cat "$logfile" >&2
+    exit 1
+  fi
+  pass "$label"
+}
+
+echo ""
+echo "[config validation]"
+
+# ── Fail cases ─────────────────────────────────────────────────────────────────
+
+# Missing secret → exit 1
+run_expect_fail "missing AUTH_COOKIE_SECRET → exit 1" \
+  env -i "TEST_TMPDIR=$tmpdir" "$server"
+
+# Secret too short (62 hex chars = 31 bytes)
+run_expect_fail "short AUTH_COOKIE_SECRET (62 hex) → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Secret with non-hex characters
+run_expect_fail "non-hex AUTH_COOKIE_SECRET → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# AUTH_DEV_INSECURE_COOKIE=true with non-loopback SERVER_HOST → exit 1
+run_expect_fail "insecure cookie without loopback SERVER_HOST → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=0.0.0.0" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# AUTH_DEV_INSECURE_COOKIE=true with no SERVER_HOST → exit 1
+run_expect_fail "insecure cookie without any SERVER_HOST → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Bootstrap username set without hash → exit 1
+run_expect_fail "bootstrap username without hash → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_BOOTSTRAP_USERNAME=admin" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Bootstrap hash with wrong format → exit 1
+run_expect_fail "bootstrap hash with wrong format → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_BOOTSTRAP_USERNAME=admin" \
+    "AUTH_BOOTSTRAP_PASSWORD_HASH=not-a-real-hash" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Bootstrap hash with partial/truncated format → exit 1
+run_expect_fail "bootstrap hash truncated (only prefix) → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_BOOTSTRAP_USERNAME=admin" \
+    "AUTH_BOOTSTRAP_PASSWORD_HASH=zenbu-scrypt\$v=1\$N=32768\$r=8\$p=1\$" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# idle TTL > abs TTL → exit 1
+run_expect_fail "idle TTL exceeds abs TTL → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_SESSION_IDLE_TTL=9999999" \
+    "AUTH_SESSION_ABS_TTL=100" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Malformed AUTH_SESSION_IDLE_TTL (non-integer) → exit 1
+run_expect_fail "malformed AUTH_SESSION_IDLE_TTL → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_SESSION_IDLE_TTL=3600abc" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Malformed AUTH_SESSION_ABS_TTL (non-integer) → exit 1
+run_expect_fail "malformed AUTH_SESSION_ABS_TTL → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_SESSION_ABS_TTL=not_a_number" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Malformed S3_URL_EXPIRES (non-integer) → exit 1
+run_expect_fail "malformed S3_URL_EXPIRES → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "S3_URL_EXPIRES=3600x" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# S3_URL_EXPIRES = 0 (not positive) → exit 1
+run_expect_fail "S3_URL_EXPIRES=0 (non-positive) → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "S3_URL_EXPIRES=0" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Trusted proxy with invalid chars → exit 1
+run_expect_fail "invalid trusted proxy (bad chars) → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_TRUSTED_PROXY=not an ip!" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Trusted proxy with out-of-range IPv4 octet (999.999.999.999) → exit 1
+run_expect_fail "trusted proxy 999.999.999.999 → exit 1" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_TRUSTED_PROXY=999.999.999.999" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# ── Success cases ─────────────────────────────────────────────────────────────
+# env-only startup (no .config file) with loopback host
+run_expect_start "env-only startup (no .config) with loopback host" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "MRJUNEJUNE_PORT=16969" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Valid IPv4 trusted proxy is accepted
+run_expect_start "valid IPv4 trusted proxy accepted" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_TRUSTED_PROXY=10.0.0.1" \
+    "MRJUNEJUNE_PORT=16970" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+# Valid IPv6 trusted proxy (canonical ::1) is accepted
+run_expect_start "valid IPv6 trusted proxy (::1) accepted" \
+  env -i \
+    "AUTH_COOKIE_SECRET=$GOOD_SECRET" \
+    "SERVER_HOST=127.0.0.1" \
+    "AUTH_DEV_INSECURE_COOKIE=true" \
+    "AUTH_TRUSTED_PROXY=::1" \
+    "MRJUNEJUNE_PORT=16971" \
+    "TEST_TMPDIR=$tmpdir" \
+    "$server"
+
+echo ""