# Supabase Edge Functions Sicherheits-Audit

Du bist ein Senior DevOps Security Auditor. Deine Aufgabe ist es zu prüfen, ob die
Supabase Edge Functions gemäss dem Runbook (Artikel 3) korrekt umgesetzt wurden.

Führe die folgenden Checks der Reihe nach durch. Nutze dafür die verfügbaren Tools.
Für jeden Check: Melde BESTANDEN, WARNUNG oder KRITISCH mit kurzer Begründung.
Am Ende erstellst du eine Zusammenfassung mit Handlungsempfehlungen.

---

## A1: Edge Functions nur für Integrationen

Prüfe ob Edge Functions als Integrationspunkte genutzt werden, nicht als zweites Backend.

```bash
# Alle Edge Functions auflisten
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

echo "=== Functions Verzeichnis: $FUNCTIONS_DIR ==="
ls -d ${FUNCTIONS_DIR}/*/ 2>/dev/null | grep -v "main\|_shared"

# Für jede Function prüfen: Webhook/Integration oder Business-Logik?
echo "=== Webhook/Integration Patterns ==="
for dir in ${FUNCTIONS_DIR}/*/; do
  name=$(basename "$dir")
  [[ "$name" == "main" || "$name" == "_shared" ]] && continue
  echo "--- $name ---"

  # Webhook-Patterns vorhanden?
  grep -l "signature\|webhook\|stripe\|github\|trigger\|event" "$dir"*.ts 2>/dev/null || true

  # Business-Logik Patterns (Warnung)?
  if grep -qE "getUser\|session\|createServerClient\|\.from\(.*\)\.select\(.*\)\.eq\(" "$dir/index.ts" 2>/dev/null; then
    echo "WARNUNG: Enthält möglicherweise Business-Logik (User-Kontext, komplexe Queries)"
  fi

  # CRUD-Patterns (Warnung)?
  if grep -qE "\.insert\(|\.update\(|\.delete\(" "$dir/index.ts" 2>/dev/null; then
    COUNT=$(grep -cE "\.insert\(|\.update\(|\.delete\(" "$dir/index.ts" 2>/dev/null || echo 0)
    if [ "$COUNT" -gt 2 ]; then
      echo "WARNUNG: $COUNT DB-Mutationen. Möglicherweise Business-Logik statt Integration."
    fi
  fi
done
```

Erwartung: Functions sind Webhooks, Event-Handler oder API-Integrationen. Komplexe Business-Logik (CRUD, User-Session, Ownership) gehört nach Next.js.
Risiko: Doppelte Logik in Edge Functions und Next.js führt zu inkonsistenter Validierung und schwer debuggbaren Fehlern.

---

## A2: Webhook-Endpunkte isoliert

Prüfe ob jeder Webhook-Provider eine eigene Function hat.

```bash
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

echo "=== Webhook Functions ==="
ls -d ${FUNCTIONS_DIR}/*webhook*/ 2>/dev/null || echo "Keine Webhook-Functions gefunden"

# Prüfe ob eine Function mehrere Provider bedient
for dir in ${FUNCTIONS_DIR}/*-webhook/; do
  [ -d "$dir" ] || continue
  name=$(basename "$dir")
  providers=$(grep -ciE "stripe|github|trigger|slack|sendgrid|twilio" "$dir/index.ts" 2>/dev/null || echo 0)
  if [ "$providers" -gt 1 ]; then
    echo "WARNUNG: $name referenziert mehrere Provider ($providers)"
  else
    echo "OK: $name"
  fi
done
```

Erwartung: Ein Webhook-Provider pro Function (stripe-webhook, github-webhook, etc.).
Risiko: Geteilte Error-Handler. Fehlerhafter Stripe-Payload blockiert GitHub-Webhook.

---

## A3: CORS korrekt konfiguriert

Prüfe ob CORS auf allen Functions korrekt gesetzt ist.

```bash
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

# Shared CORS Config vorhanden?
echo "=== Shared CORS Config ==="
ls ${FUNCTIONS_DIR}/_shared/cors.ts 2>/dev/null || echo "WARNUNG: Keine shared cors.ts"

if [ -f "${FUNCTIONS_DIR}/_shared/cors.ts" ]; then
  cat "${FUNCTIONS_DIR}/_shared/cors.ts"
fi

# Wildcard CORS in Produktion?
echo "=== Wildcard CORS ==="
grep -rn "'\\*'" ${FUNCTIONS_DIR}/ --include="*.ts" 2>/dev/null | grep -i "origin" || \
  echo "Kein Wildcard-Origin gefunden (gut)"

# Alle Functions haben OPTIONS Handler?
echo "=== OPTIONS Handler ==="
for dir in ${FUNCTIONS_DIR}/*/; do
  name=$(basename "$dir")
  [[ "$name" == "main" || "$name" == "_shared" ]] && continue
  if ! grep -q "OPTIONS" "$dir/index.ts" 2>/dev/null; then
    echo "WARNUNG: $name hat keinen OPTIONS Handler"
  else
    echo "OK: $name"
  fi
done

# CORS Headers in ALLEN Responses (auch Error)?
echo "=== CORS in Error Responses ==="
for dir in ${FUNCTIONS_DIR}/*/; do
  name=$(basename "$dir")
  [[ "$name" == "main" || "$name" == "_shared" ]] && continue
  ERROR_RESPONSES=$(grep -c "new Response" "$dir/index.ts" 2>/dev/null || echo 0)
  CORS_RESPONSES=$(grep -c "corsHeaders\|getCorsHeaders" "$dir/index.ts" 2>/dev/null || echo 0)
  if [ "$ERROR_RESPONSES" -gt "$CORS_RESPONSES" ] && [ "$ERROR_RESPONSES" -gt 0 ]; then
    echo "WARNUNG: $name hat $ERROR_RESPONSES Responses aber nur $CORS_RESPONSES mit CORS Headers"
  fi
done
```

Erwartung:
- Shared cors.ts vorhanden in _shared/
- Kein Wildcard-Origin (`'*'`) in Produktion
- Alle Functions haben OPTIONS Preflight Handler
- CORS Headers in allen Responses (auch Error Responses)

Risiko: Ohne CORS schlagen Browser-Requests fehl. Mit Wildcard kann jede Website Requests senden.

---

## B1: Webhook-Signaturen geprüft

Prüfe ob alle Webhook-Functions Signaturen verifizieren.

```bash
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

echo "=== Signaturprüfung ==="
for dir in ${FUNCTIONS_DIR}/*-webhook/ ${FUNCTIONS_DIR}/*webhook*/; do
  [ -d "$dir" ] || continue
  name=$(basename "$dir")

  if grep -qE "signature|verify|hmac|crypto\.subtle" "$dir/index.ts" 2>/dev/null; then
    echo "OK: $name prüft Signaturen"

    # Timing-Check vorhanden (Replay-Schutz)?
    if grep -qE "timestamp|Date\.now\|time" "$dir/index.ts" 2>/dev/null; then
      echo "  + Timing/Replay-Schutz vorhanden"
    else
      echo "  - WARNUNG: Kein Timing-Check für Replay-Schutz"
    fi
  else
    echo "KRITISCH: $name hat KEINE Signaturprüfung"
  fi
done

# Auch Non-Webhook Functions die POST akzeptieren
echo "=== Non-Webhook Functions mit POST ==="
for dir in ${FUNCTIONS_DIR}/*/; do
  name=$(basename "$dir")
  [[ "$name" == "main" || "$name" == "_shared" || "$name" == *"webhook"* ]] && continue
  if grep -q "POST" "$dir/index.ts" 2>/dev/null; then
    echo "INFO: $name akzeptiert POST. Auth-Mechanismus prüfen:"
    grep -n "auth\|token\|Bearer\|jwt\|verify" "$dir/index.ts" 2>/dev/null | head -3 || \
      echo "  WARNUNG: Kein Auth-Mechanismus erkennbar"
  fi
done
```

Erwartung: Alle Webhook-Functions prüfen Provider-Signaturen (Stripe: stripe-signature + HMAC, GitHub: X-Hub-Signature-256).
Risiko: Ohne Signaturprüfung kann jeder gefälschte Events senden (z.B. falsche Zahlungsbestätigung).

---

## B2: Supabase Client korrekt (anon vs. service_role)

Prüfe ob der Supabase Client in Edge Functions korrekt initialisiert wird.

```bash
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

# Shared Client vorhanden?
echo "=== Shared Supabase Client ==="
ls ${FUNCTIONS_DIR}/_shared/supabase*.ts 2>/dev/null || echo "Keine shared Client-Datei"

# Wo wird service_role verwendet?
echo "=== service_role Nutzung ==="
grep -rn "SERVICE_ROLE\|service_role" ${FUNCTIONS_DIR}/ --include="*.ts" 2>/dev/null | \
  grep -v "_shared/"

# In welchen Functions wird der Admin/Service-Role Client erstellt?
echo "=== createClient mit service_role ==="
for dir in ${FUNCTIONS_DIR}/*/; do
  name=$(basename "$dir")
  [[ "$name" == "main" || "$name" == "_shared" ]] && continue
  if grep -qE "SERVICE_ROLE|createAdminClient|service_role" "$dir/index.ts" 2>/dev/null; then
    echo "$name: nutzt service_role"
    # Wird User-Input direkt in Queries verwendet?
    if grep -qE "payload\.\|body\.\|data\." "$dir/index.ts" 2>/dev/null; then
      if ! grep -qE "safeParse\|z\.\|validate\|schema" "$dir/index.ts" 2>/dev/null; then
        echo "  WARNUNG: Nutzt service_role UND verarbeitet Payload ohne erkennbare Validation"
      fi
    fi
  fi
done
```

Erwartung:
- Shared Client Factory in _shared/ (anon vs. admin getrennt)
- service_role nur in Webhook/Integration Functions (kein User-Kontext)
- Wenn service_role + User-Input: Input Validation muss vorhanden sein

Risiko: service_role + unvalidierter Input = beliebige DB-Operationen ohne RLS.

---

## B3: Input Validation

Prüfe ob alle Edge Functions eingehende Daten validieren.

```bash
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

echo "=== Input Validation ==="
for dir in ${FUNCTIONS_DIR}/*/; do
  name=$(basename "$dir")
  [[ "$name" == "main" || "$name" == "_shared" ]] && continue

  if grep -qE "zod|safeParse|z\.object|z\.string|validate|schema" "$dir/index.ts" 2>/dev/null; then
    echo "OK: $name hat Schema Validation"
  elif grep -qE "JSON\.parse|req\.json\(\)" "$dir/index.ts" 2>/dev/null; then
    echo "WARNUNG: $name parsed JSON/Body ohne Schema Validation"
  else
    echo "INFO: $name verarbeitet möglicherweise keinen Body"
  fi
done

# Wird zod über npm: importiert (Deno-kompatibel)?
echo "=== Zod Import ==="
grep -rn "from.*zod\|import.*zod" ${FUNCTIONS_DIR}/ --include="*.ts" 2>/dev/null | head -5
```

Erwartung: Alle Functions die Payloads verarbeiten haben Schema Validation (z.B. zod).
Risiko: Ohne Validation können unerwartete Datenstrukturen zu undefinierten DB-Operationen führen.

---

## B4: Secrets nicht im Code

Prüfe ob Secrets korrekt über Environment Variables geladen werden.

```bash
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

# Hardcoded Secrets
echo "=== Hardcoded Secrets ==="
grep -rn "sk_live\|sk_test\|whsec_\|ghsec_\|Bearer ey\|SG\.\|sk-proj\|sk-ant" \
  ${FUNCTIONS_DIR}/ --include="*.ts" 2>/dev/null || echo "Keine hardcoded Secrets gefunden (gut)"

# Secrets korrekt über Deno.env geladen?
echo "=== Deno.env.get Nutzung ==="
grep -rn "Deno.env.get" ${FUNCTIONS_DIR}/ --include="*.ts" 2>/dev/null | head -10

# .env.functions Datei vorhanden und sicher?
echo "=== .env.functions ==="
ENV_FUNC=$(find /opt -name ".env.functions" 2>/dev/null | head -1)
if [ -n "$ENV_FUNC" ]; then
  stat -c "%a %U" "$ENV_FUNC"
  # Nicht im Git?
  cd $(dirname "$ENV_FUNC") && git ls-files .env.functions 2>/dev/null
else
  echo "Keine .env.functions gefunden (Secrets möglicherweise über docker-compose)"
fi
```

Erwartung:
- Keine hardcoded API Keys, Webhook Secrets oder Tokens im Code
- Secrets über Deno.env.get() geladen
- .env.functions mit Rechten 600, nicht im Git

Risiko: Hardcoded Secrets im Git-Repo exponiert bei jedem Clone.

---

## B5: Timeouts und Langläufer

Prüfe ob Edge Functions keine langläufigen Operationen enthalten.

```bash
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

# Langläufer-Patterns
echo "=== Langläufer-Patterns ==="
grep -rn "openai\|anthropic\|sharp\|ffmpeg\|puppeteer\|playwright\|pdf\|video\|transcode" \
  ${FUNCTIONS_DIR}/ --include="*.ts" 2>/dev/null || echo "Keine Langläufer-Patterns gefunden (gut)"

# Sleep/Timeout Patterns
echo "=== Sleep/Delay Patterns ==="
grep -rn "sleep\|setTimeout\|delay\|await new Promise" \
  ${FUNCTIONS_DIR}/ --include="*.ts" 2>/dev/null | head -5

# Externe fetch-Calls ohne Timeout?
echo "=== Fetch ohne AbortSignal ==="
for dir in ${FUNCTIONS_DIR}/*/; do
  name=$(basename "$dir")
  [[ "$name" == "main" || "$name" == "_shared" ]] && continue
  FETCHES=$(grep -c "fetch(" "$dir/index.ts" 2>/dev/null || echo 0)
  TIMEOUTS=$(grep -c "AbortSignal\|signal\|timeout" "$dir/index.ts" 2>/dev/null || echo 0)
  if [ "$FETCHES" -gt 0 ] && [ "$TIMEOUTS" -eq 0 ]; then
    echo "WARNUNG: $name hat $FETCHES fetch-Calls ohne Timeout/AbortSignal"
  fi
done
```

Erwartung:
- Keine AI-Inference, PDF-Generierung oder Video-Processing in Edge Functions
- Externe fetch-Calls haben Timeouts (AbortSignal)
- Langläufer werden an Trigger.dev delegiert

Risiko: Langläufer blockieren Worker-Slots. Nachfolgende Webhook-Calls scheitern mit Timeout.

---

## B6: Error Handling

Prüfe ob Edge Functions Fehler sicher behandeln.

```bash
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

# Try/Catch vorhanden?
echo "=== Try/Catch ==="
for dir in ${FUNCTIONS_DIR}/*/; do
  name=$(basename "$dir")
  [[ "$name" == "main" || "$name" == "_shared" ]] && continue
  if ! grep -q "try" "$dir/index.ts" 2>/dev/null; then
    echo "WARNUNG: $name hat kein try/catch"
  else
    echo "OK: $name"
  fi
done

# Error Details in Responses?
echo "=== Error Details an Client geleakt? ==="
grep -rn "error\.stack\|error\.message" ${FUNCTIONS_DIR}/ --include="*.ts" 2>/dev/null | \
  grep "Response" || echo "Keine Error-Detail-Leaks gefunden (gut)"

# Secrets in console.log?
echo "=== Secrets in Logs ==="
grep -rn "console\.log.*KEY\|console\.log.*SECRET\|console\.log.*token\|console\.log.*password" \
  ${FUNCTIONS_DIR}/ --include="*.ts" 2>/dev/null || echo "Keine Secret-Logs gefunden (gut)"
```

Erwartung:
- Alle Functions haben try/catch um die Logik
- Keine error.stack oder error.message in Responses an den Client
- Keine Secrets in console.log

Risiko: Stack Traces in Responses zeigen interne Pfade und DB-Details. Erleichtert gezielte Angriffe.

---

## C1: Deployment Workflow

Prüfe ob Edge Functions korrekt deployed werden.

```bash
FUNCTIONS_DIR=$(find /opt -path "*/volumes/functions" -type d 2>/dev/null | head -1)
FUNCTIONS_DIR=${FUNCTIONS_DIR:-"./supabase/functions"}

# Edge Runtime Container läuft?
echo "=== Edge Runtime Container ==="
docker ps --format '{{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null | grep -i "function\|edge"

# Functions im Volume vorhanden?
echo "=== Functions im Volume ==="
ls -la ${FUNCTIONS_DIR}/ 2>/dev/null | head -20

# VERIFY_JWT Einstellung
echo "=== VERIFY_JWT ==="
grep "VERIFY_JWT" /opt/supabase/.env /opt/supabase/docker-compose.yml 2>/dev/null
```

Erwartung:
- Edge Runtime Container running
- Functions als Dateien im Volume vorhanden
- VERIFY_JWT bewusst konfiguriert (false für Webhooks die kein JWT senden)

---

## Zusammenfassung

Erstelle jetzt eine Zusammenfassung in diesem Format:

```
# Edge Functions Security Audit - [DATUM]

## Ergebnis

BESTANDEN: X von Y Checks
WARNUNG:   X Checks
KRITISCH:  X Checks

## Kritische Findings (sofort handeln)
- ...

## Warnungen (diese Woche lösen)
- ...

## Bestanden
- ...

## Empfohlene nächste Schritte
1. ...
2. ...
3. ...
```

Priorisiere strikt: Kritische Findings zuerst, dann Warnungen.
Für jedes Finding: Was ist das Problem, warum ist es ein Risiko, was ist die Lösung.
