test(auth): KTO-01 Playwright-E2E (api, web, throttle) und CI-Job e2e #42
3 changed files with 57 additions and 17 deletions
|
|
@ -13,12 +13,24 @@ node e2e/support/tcp-forward.mjs "$DOCKER_GW" 54321 54322 54324 9998 &
|
|||
relay=$!
|
||||
trap 'kill "$relay" 2>/dev/null || true' EXIT
|
||||
|
||||
for port in 54321 54322 54324 9998; do
|
||||
for _ in $(seq 1 20); do
|
||||
(exec 3<>"/dev/tcp/127.0.0.1/${port}") 2>/dev/null && break
|
||||
sleep 0.5
|
||||
# Warten, bis die Dienste HINTER dem Relay antworten (nicht nur der lokale Port); Timeout = Fehler.
|
||||
wait_http() {
|
||||
for _ in $(seq 1 60); do
|
||||
curl -fsS -o /dev/null --max-time 3 -H "apikey: ${SUPABASE_ANON_KEY}" "$1" 2>/dev/null && return 0
|
||||
sleep 1
|
||||
done
|
||||
echo "Timeout: $1 nicht erreichbar (Relay zu ${DOCKER_GW})" >&2
|
||||
return 1
|
||||
}
|
||||
wait_http "http://127.0.0.1:54321/auth/v1/health" || exit 1 # Kong -> GoTrue
|
||||
wait_http "http://127.0.0.1:54324/api/v1/info" || exit 1
|
||||
wait_http "http://127.0.0.1:9998/health" || exit 1
|
||||
pg_ok=""
|
||||
for _ in $(seq 1 60); do
|
||||
if (exec 3<>/dev/tcp/127.0.0.1/54322) 2>/dev/null; then pg_ok=1; break; fi
|
||||
sleep 1
|
||||
done
|
||||
[ -n "$pg_ok" ] || { echo "Timeout: Postgres 54322 nicht erreichbar" >&2; exit 1; }
|
||||
|
||||
export SUPABASE_URL=http://127.0.0.1:54321
|
||||
export MAILPIT_URL=http://127.0.0.1:54324
|
||||
|
|
|
|||
|
|
@ -155,6 +155,9 @@ jobs:
|
|||
# Nutzt die eingecheckte supabase/config.toml. Ohne passenden Runner Job bei Bedarf deaktivieren.
|
||||
supabase-tests:
|
||||
runs-on: docker-host
|
||||
concurrency:
|
||||
group: docker-host-supabase
|
||||
cancel-in-progress: false
|
||||
env:
|
||||
DOCKER_CLI_VERSION: 27.3.1
|
||||
DIND_PORT: 2375
|
||||
|
|
@ -187,12 +190,20 @@ jobs:
|
|||
# Läuft wie supabase-tests auf "docker-host" (Docker-CLI + dind per TCP). Der Stack liegt im dind; ein
|
||||
# TCP-Relay (e2e/support/tcp-forward.mjs) macht ihn im Job unter 127.0.0.1 erreichbar.
|
||||
# SICHERHEIT: Der Job führt PR-Code mit Zugriff auf den dind-Daemon des Runners aus (Daemon = Root-Äquivalent).
|
||||
# Deshalb nicht für Fork-PRs (Bedingung unten); Fork-Beiträge nur nach Review und Übernahme in einen Branch dieses Repos.
|
||||
# Gleiches Risiko hat supabase-tests; dort ist es (noch) nicht eingeschränkt.
|
||||
# needs: supabase-tests, weil beide Jobs dieselben festen Container-Namen/Ports (project_id shuffle, 54321 ...) im dind belegen.
|
||||
# Der `if:` unten ist KEIN Schutz vor böswilligen Forks: Bei pull_request kommt der Workflow aus dem PR-Head,
|
||||
# ein Fork kann die Bedingung einfach entfernen. Er verhindert nur versehentliche Läufe. Die echte Absicherung
|
||||
# gehört in Repo-/Runner-Einstellungen (Freigabe für Fork-PRs, Runner nur für vertrauenswürdige Repos; Folge-Issue).
|
||||
# Gleiches Risiko hat supabase-tests.
|
||||
# needs + concurrency: Beide Jobs belegen dieselben festen Container-Namen/Ports (project_id shuffle, 54321 ...) im dind.
|
||||
# `needs` serialisiert innerhalb eines Laufs; die concurrency-Gruppe (auch an supabase-tests) soll Läufe verschiedener
|
||||
# PRs hintereinander schalten. Ob Forgejo 8.0.3 / Runner v5.0.4 Job-concurrency auswertet, ist hier nicht verifiziert;
|
||||
# sonst wird der Schlüssel ignoriert und Kollisionen bleiben möglich (dann Runner mit capacity 1 verwenden).
|
||||
# Der Spike (SPIKE_GOTRUE_URL, Issue #37) läuft nicht in CI.
|
||||
e2e:
|
||||
runs-on: docker-host
|
||||
concurrency:
|
||||
group: docker-host-supabase
|
||||
cancel-in-progress: false
|
||||
needs: [supabase-tests]
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
env:
|
||||
|
|
@ -206,9 +217,11 @@ jobs:
|
|||
- name: Werkzeuge prüfen
|
||||
run: |
|
||||
missing=""
|
||||
for t in git curl unzip xz jq; do command -v "$t" >/dev/null || missing="$missing $t"; done
|
||||
for t in git curl unzip xz jq; do
|
||||
command -v "$t" >/dev/null || { [ "$t" = xz ] && missing="$missing xz-utils" || missing="$missing $t"; }
|
||||
done
|
||||
if [ -n "$missing" ]; then
|
||||
apt-get update -qq && apt-get install -y -qq --no-install-recommends $missing xz-utils ca-certificates
|
||||
apt-get update -qq && apt-get install -y -qq --no-install-recommends $missing ca-certificates
|
||||
fi
|
||||
node --version
|
||||
|
||||
|
|
@ -224,20 +237,27 @@ jobs:
|
|||
DOCKER_HOST="tcp://${gw}:${DIND_PORT}" docker version --format 'dind {{.Server.Version}}'
|
||||
|
||||
- name: Supabase starten (mit Mailpit, ohne Studio u. a.)
|
||||
run: npx --yes supabase@${{ env.SUPABASE_CLI_VERSION }} start -x studio,imgproxy,edge-runtime,logflare,vector
|
||||
# Ausgabe nicht ins Log: Die Zusammenfassung von `start` enthält die lokalen Schlüssel (noch nicht maskiert).
|
||||
run: |
|
||||
if ! npx --yes supabase@${{ env.SUPABASE_CLI_VERSION }} start -x studio,imgproxy,edge-runtime,logflare,vector >"${RUNNER_TEMP:-/tmp}/supabase-start.log" 2>&1; then
|
||||
echo "supabase start fehlgeschlagen, letzte Zeilen (Schlüssel gefiltert):"
|
||||
tail -n 40 "${RUNNER_TEMP:-/tmp}/supabase-start.log" | grep -viE 'key|secret|token|jwt'
|
||||
exit 1
|
||||
fi
|
||||
echo "supabase start ok"
|
||||
|
||||
- name: Datenbank zurücksetzen
|
||||
run: npx --yes supabase@${{ env.SUPABASE_CLI_VERSION }} db reset
|
||||
|
||||
- name: Lokale Schlüssel lesen
|
||||
# Die Werte sind die öffentlichen Demo-Schlüssel der CLI, trotzdem nur maskiert weiterreichen.
|
||||
# Öffentliche Demo-Schlüssel der CLI; trotzdem wird die Maske gesetzt, bevor sie irgendwo ausgegeben werden.
|
||||
run: |
|
||||
status=$(npx --yes supabase@${{ env.SUPABASE_CLI_VERSION }} status -o env)
|
||||
status=$(npx --yes supabase@${{ env.SUPABASE_CLI_VERSION }} status -o env 2>/dev/null)
|
||||
get() { printf '%s\n' "$status" | sed -n "s/^$1=\"\{0,1\}\([^\"]*\)\"\{0,1\}$/\1/p" | head -n1; }
|
||||
anon=$(get ANON_KEY); service=$(get SERVICE_ROLE_KEY)
|
||||
[ -z "$anon" ] || echo "::add-mask::$anon"
|
||||
[ -z "$service" ] || echo "::add-mask::$service"
|
||||
test -n "$anon" && test -n "$service" || { echo "ANON_KEY/SERVICE_ROLE_KEY nicht in 'supabase status -o env' gefunden"; exit 1; }
|
||||
echo "::add-mask::$anon"
|
||||
echo "::add-mask::$service"
|
||||
echo "SUPABASE_ANON_KEY=${anon}" >> "$GITHUB_ENV"
|
||||
echo "SUPABASE_SERVICE_ROLE_KEY=${service}" >> "$GITHUB_ENV"
|
||||
# Env-Datei für den Web-Build: Platzhalter-Datei bleibt unverändert, der Schlüssel kommt zur Laufzeit.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
# Docker-in-Docker (CI, DOCKER_HOST=tcp://...): Der Port wird im dind veroeffentlicht, nicht im Job-Container.
|
||||
# Dann BIND_ADDR=0.0.0.0 und HEALTH_HOST=<dind-Gateway> setzen (siehe .forgejo/workflows/ci.yml, Job e2e);
|
||||
# die Tests erreichen den Container ueber e2e/support/tcp-forward.mjs auf 127.0.0.1.
|
||||
# Bindung: lokal nur 127.0.0.1. Unter dind muss 0.0.0.0 gelten (der Job-Container erreicht den dind nur ueber
|
||||
# das Gateway; eine feinere Bindung ist dort nicht moeglich). Der Port ist dann im Netz des Runners sichtbar.
|
||||
# Nur lokal/CI benutzen: Die kopierte Umgebung enthaelt die lokalen Demo-Secrets der CLI.
|
||||
set -euo pipefail
|
||||
|
||||
|
|
@ -24,7 +26,9 @@ BIND_ADDR="${BIND_ADDR:-127.0.0.1}"
|
|||
HEALTH_HOST="${HEALTH_HOST:-127.0.0.1}"
|
||||
ACTION="${1:-start}"
|
||||
PROFILE="${2:-throttle}"
|
||||
SOURCE="${SOURCE_CONTAINER:-$(docker ps --format '{{.Names}}' | grep -E '^supabase_auth_' | head -n1 || true)}"
|
||||
# Auth-Container gezielt ueber die Projekt-ID (project_id in supabase/config.toml), nicht "erster Treffer"
|
||||
PROJECT_ID="${SUPABASE_PROJECT_ID:-shuffle}"
|
||||
SOURCE="${SOURCE_CONTAINER:-supabase_auth_${PROJECT_ID}}"
|
||||
|
||||
case "$PROFILE" in
|
||||
throttle) NAME="${CONTAINER_NAME:-shuffle_auth_throttle}"; HOST_PORT="${HOST_PORT:-9998}" ;;
|
||||
|
|
@ -39,8 +43,8 @@ if [ "$ACTION" = "stop" ]; then
|
|||
fi
|
||||
[ "$ACTION" = "start" ] || { echo "Aktion: start|stop" >&2; exit 2; }
|
||||
|
||||
if [ -z "$SOURCE" ]; then
|
||||
echo "Kein laufender supabase_auth_*-Container gefunden. Zuerst 'supabase start'." >&2
|
||||
if ! docker inspect "$SOURCE" >/dev/null 2>&1; then
|
||||
echo "Container $SOURCE nicht gefunden. Zuerst 'supabase start' (oder SUPABASE_PROJECT_ID setzen)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -52,6 +56,7 @@ ENV_ARGS=()
|
|||
while IFS= read -r -d '' entry; do
|
||||
case "$entry" in
|
||||
GOTRUE_RATE_LIMIT_HEADER=*) continue ;; # wird unten gezielt gesetzt
|
||||
API_EXTERNAL_URL=*) continue ;; # wird unten explizit gesetzt
|
||||
GOTRUE_SMTP_PORT=*) [ "$PROFILE" = "smtp-down" ] && continue ;;
|
||||
esac
|
||||
ENV_ARGS+=(-e "$entry")
|
||||
|
|
@ -62,6 +67,9 @@ case "$PROFILE" in
|
|||
smtp-down) ENV_ARGS+=(-e "GOTRUE_SMTP_PORT=1") ;; # Host bleibt Mailpit, Port 1 lehnt die Verbindung ab
|
||||
esac
|
||||
|
||||
# API_EXTERNAL_URL explizit (Spec D2): Kong-URL der CLI, nur Basis fuer Links in Mails/Redirects.
|
||||
ENV_ARGS+=(-e "API_EXTERNAL_URL=${API_EXTERNAL_URL:-http://127.0.0.1:54321}")
|
||||
|
||||
docker run -d --name "$NAME" --network "$NETWORK" -p "${BIND_ADDR}:${HOST_PORT}:9999" \
|
||||
"${ENV_ARGS[@]}" "$IMAGE" auth >/dev/null
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue