view mrjunejune/test/config_validation_test.sh @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents 056790c4fb0d
children
line wrap: on
line source

#!/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"

# A service-owned config outside the bundle/workspace is authoritative. The
# deliberately bad environment secret must not override the valid file.
external_config="$tmpdir/service.config"
cat > "$external_config" <<EOF
AUTH_COOKIE_SECRET=$GOOD_SECRET
SERVER_HOST=127.0.0.1
AUTH_DEV_INSECURE_COOKIE=true
MRJUNEJUNE_ALLOW_GUEST_INFERENCE=false
DB_PATH=$tmpdir/external-config.db
EOF
run_expect_start "external config path loads and overrides compatibility env" \
  env -i \
    "MRJUNEJUNE_CONFIG_PATH=$external_config" \
    "AUTH_COOKIE_SECRET=bad-env-secret" \
    "MRJUNEJUNE_PORT=16972" \
    "TEST_TMPDIR=$tmpdir" \
    "$server"

echo ""