#!/usr/bin/env bash
# test-certs.sh — Generate throwaway test certs for unit tests in
# internal/auth/mtls_test.go. NOT for production. Creates a temp
# self-signed CA + a few leaf certs (valid, expired, wrong-CN, untrusted)
# in scripts/cert-manager/testdata/ so tests can read them with
# crypto/x509.ReadFile.
#
# Usage:
#   scripts/cert-manager/test-certs.sh
#   scripts/cert-manager/test-certs.sh clean   # remove testdata
#
# Idempotent: regenerates the dir each run.

set -euo pipefail

TESTDATA="$(dirname "$0")/testdata"

case "${1:-}" in
  clean)
    rm -rf "$TESTDATA"
    echo "removed $TESTDATA"
    exit 0
    ;;
  "")
    ;;
  *)
    echo "usage: $0 [clean]" >&2
    exit 1
    ;;
esac

rm -rf "$TESTDATA"
mkdir -p "$TESTDATA"

# --- Test CA (self-signed) -------------------------------------------------
TEST_CA_KEY="$TESTDATA/test-ca.key"
TEST_CA_CRT="$TESTDATA/test-ca.crt"
openssl genrsa -out "$TEST_CA_KEY" 2048 2>/dev/null
openssl req -new -x509 -key "$TEST_CA_KEY" -sha256 -days 365 \
  -subj "/CN=broad-announce Test CA/O=test/OU=test" \
  -addext "basicConstraints=critical,CA:TRUE" \
  -out "$TEST_CA_CRT"

# Helper: generate a leaf signed by the test CA
gen_leaf() {
  local name="$1" cn="$2" san="$3" days="$4"
  local key="$TESTDATA/${name}.key"
  local csr="$TESTDATA/${name}.csr"
  local crt="$TESTDATA/${name}.crt"
  openssl genrsa -out "$key" 2048 2>/dev/null
  if [[ -n "$san" ]]; then
    openssl req -new -key "$key" -sha256 \
      -subj "/CN=$cn/O=test/OU=test" \
      -addext "subjectAltName=$san" \
      -out "$csr"
  else
    openssl req -new -key "$key" -sha256 \
      -subj "/CN=$cn/O=test/OU=test" \
      -out "$csr"
  fi
  # Build extfile: include subjectAltName only if non-empty
  local extfile
  if [[ -n "$san" ]]; then
    extfile=$(mktemp)
    cat > "$extfile" <<EOF
basicConstraints=CA:FALSE
keyUsage=critical,digitalSignature,keyEncipherment
extendedKeyUsage=clientAuth
subjectAltName=$san
EOF
  else
    extfile=$(mktemp)
    cat > "$extfile" <<'EOF'
basicConstraints=CA:FALSE
keyUsage=critical,digitalSignature,keyEncipherment
extendedKeyUsage=clientAuth
EOF
  fi
  openssl x509 -req -in "$csr" -CA "$TEST_CA_CRT" -CAkey "$TEST_CA_KEY" \
    -CAcreateserial -sha256 -days "$days" \
    -extfile "$extfile" \
    -out "$crt"
  rm -f "$extfile"
}

# --- Test fixtures ---------------------------------------------------------
# source_cn format: source:<source_id>.<company_slug>
gen_leaf "valid"        "source:src-123.acme-001"  "DNS:source.src-123.acme-001"  30
gen_leaf "wrong-cn"     "source:src-999.acme-001"  "DNS:source.src-999.acme-001"  30
gen_leaf "no-san"       "source:src-789.acme-001"  ""                              30
# Note: "expired" is generated in-memory in internal/auth/mtls_test.go
# (template.NotAfter in the past), not as a file fixture, because openssl
# refuses to sign certs with end-before-start dates.

# An UNTRUSTED leaf — signed by a different CA
UNTRUSTED_KEY="$TESTDATA/untrusted-ca.key"
UNTRUSTED_CRT="$TESTDATA/untrusted-ca.crt"
UNTRUSTED_LEAF_KEY="$TESTDATA/untrusted.key"
UNTRUSTED_LEAF_CRT="$TESTDATA/untrusted.crt"
openssl genrsa -out "$UNTRUSTED_KEY" 2048 2>/dev/null
openssl req -new -x509 -key "$UNTRUSTED_KEY" -sha256 -days 30 \
  -subj "/CN=untrusted-attacker/O=evil/OU=evil" \
  -addext "basicConstraints=critical,CA:TRUE" \
  -out "$UNTRUSTED_CRT"
openssl genrsa -out "$UNTRUSTED_LEAF_KEY" 2048 2>/dev/null
openssl req -new -key "$UNTRUSTED_LEAF_KEY" -sha256 \
  -subj "/CN=source:src-123.acme-001/O=evil/OU=evil" \
  -addext "subjectAltName=DNS:source.src-123.acme-001" \
  -out "$TESTDATA/untrusted.csr"
openssl x509 -req -in "$TESTDATA/untrusted.csr" -CA "$UNTRUSTED_CRT" -CAkey "$UNTRUSTED_KEY" \
  -CAcreateserial -sha256 -days 30 \
  -extfile <(echo "extendedKeyUsage=clientAuth") \
  -out "$UNTRUSTED_LEAF_CRT"

# --- Write a manifest for the tests ----------------------------------------
cat > "$TESTDATA/MANIFEST.txt" <<EOF
test-ca.crt                  — self-signed test CA (the trust anchor for tests)
test-ca.key                  — test CA private key (DO NOT use in prod)

valid.{key,crt}              — leaf with correct CN/SAN, valid 30d
wrong-cn.{key,crt}           — leaf with correct format but wrong source_id in CN
no-san.{key,crt}             — leaf with correct CN but no SAN
untrusted.{key,crt}          — leaf signed by an UNTRUSTED CA (simulates attacker)
untrusted-ca.{key,crt}       — the attacker's CA

Note: "expired" fixture is generated in-memory in
internal/auth/mtls_test.go (template.NotAfter in the past), not as a
file fixture, because openssl refuses to sign certs with
end-before-start dates.

Production uses scripts/cert-manager/ca-init.sh to generate the real PKI.
This dir is .gitignored.
EOF

echo "test certs generated in $TESTDATA"
ls "$TESTDATA" | head
