# Auditoría de seguridad de Supabase Edge Functions

Eres un Senior DevOps Security Auditor. Tu tarea es verificar si las
Supabase Edge Functions se han implementado correctamente según el runbook (artículo 3).

Ejecuta las siguientes comprobaciones en orden. Utiliza las herramientas disponibles.
Para cada comprobación: Reporta APROBADO, ADVERTENCIA o CRÍTICO con una breve justificación.
Al final, elabora un resumen con recomendaciones de actuación.

---

## A1: Edge Functions solo para integraciones

Verifica si las Edge Functions se utilizan como puntos de integración, no como un segundo 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 "ADVERTENCIA: 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 "ADVERTENCIA: $COUNT DB-Mutationen. Möglicherweise Business-Logik statt Integration."
    fi
  fi
done
```

Expectativa: Las funciones son webhooks, event handlers o integraciones de API. La lógica de negocio compleja (CRUD, sesión de usuario, propiedad) pertenece a Next.js.
Riesgo: Lógica duplicada en Edge Functions y Next.js provoca validación inconsistente y errores difíciles de depurar.

---

## A2: Endpoints de webhook aislados

Verifica si cada proveedor de webhook tiene su propia función.

```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 "ADVERTENCIA: $name referenziert mehrere Provider ($providers)"
  else
    echo "OK: $name"
  fi
done
```

Expectativa: Un proveedor de webhook por función (stripe-webhook, github-webhook, etc.).
Riesgo: Error handlers compartidos. Un payload erróneo de Stripe bloquea el webhook de GitHub.

---

## A3: CORS configurado correctamente

Verifica si CORS está correctamente configurado en todas las funciones.

```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 "ADVERTENCIA: 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 "ADVERTENCIA: $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 "ADVERTENCIA: $name hat $ERROR_RESPONSES Responses aber nur $CORS_RESPONSES mit CORS Headers"
  fi
done
```

Expectativa:
- cors.ts compartido existente en _shared/
- Sin origin wildcard (`'*'`) en producción
- Todas las funciones tienen handler OPTIONS para preflight
- Cabeceras CORS en todas las respuestas (también en respuestas de error)

Riesgo: Sin CORS las peticiones del navegador fallan. Con wildcard cualquier sitio web puede enviar peticiones.

---

## B1: Firmas de webhook verificadas

Verifica si todas las funciones de webhook verifican firmas.

```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 "  - ADVERTENCIA: Kein Timing-Check für Replay-Schutz"
    fi
  else
    echo "CRÍTICO: $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 "  ADVERTENCIA: Kein Auth-Mechanismus erkennbar"
  fi
done
```

Expectativa: Todas las funciones de webhook verifican firmas del proveedor (Stripe: stripe-signature + HMAC, GitHub: X-Hub-Signature-256).
Riesgo: Sin verificación de firma cualquiera puede enviar eventos falsos (p. ej. confirmación de pago falsa).

---

## B2: Cliente Supabase correcto (anon vs. service_role)

Verifica si el cliente Supabase en las Edge Functions se inicializa correctamente.

```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 "  ADVERTENCIA: Nutzt service_role UND verarbeitet Payload ohne erkennbare Validation"
      fi
    fi
  fi
done
```

Expectativa:
- Client Factory compartida en _shared/ (anon vs. admin separados)
- service_role solo en funciones de Webhook/Integración (sin contexto de usuario)
- Si service_role + entrada de usuario: la validación de entrada debe estar presente

Riesgo: service_role + entrada sin validar = operaciones arbitrarias en la BD sin RLS.

---

## B3: Validación de entrada

Verifica si todas las Edge Functions validan los datos entrantes.

```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 "ADVERTENCIA: $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
```

Expectativa: Todas las funciones que procesan payloads tienen validación de esquema (p. ej. zod).
Riesgo: Sin validación, estructuras de datos inesperadas pueden provocar operaciones de BD indefinidas.

---

## B4: Secretos fuera del código

Verifica si los secretos se cargan correctamente mediante variables de entorno.

```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
```

Expectativa:
- Sin claves API, secretos de webhook ni tokens hardcodeados en el código
- Secretos cargados mediante Deno.env.get()
- .env.functions con permisos 600, no en Git

Riesgo: Los secretos hardcodeados en el repositorio Git quedan expuestos en cada clone.

---

## B5: Timeouts y operaciones de larga duración

Verifica si las Edge Functions no contienen operaciones de larga duración.

```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 "ADVERTENCIA: $name hat $FETCHES fetch-Calls ohne Timeout/AbortSignal"
  fi
done
```

Expectativa:
- Sin inferencia de IA, generación de PDF ni procesamiento de vídeo en Edge Functions
- Las llamadas fetch externas tienen timeouts (AbortSignal)
- Las operaciones de larga duración se delegan a Trigger.dev

Riesgo: Las operaciones de larga duración bloquean slots de worker. Las llamadas webhook posteriores fallan por timeout.

---

## B6: Gestión de errores

Verifica si las Edge Functions gestionan los errores de forma segura.

```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 "ADVERTENCIA: $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)"
```

Expectativa:
- Todas las funciones tienen try/catch alrededor de la lógica
- Sin error.stack ni error.message en las respuestas al cliente
- Sin secretos en console.log

Riesgo: Los stack traces en las respuestas revelan rutas internas y detalles de la BD. Facilita ataques dirigidos.

---

## C1: Flujo de despliegue

Verifica si las Edge Functions se despliegan correctamente.

```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
```

Expectativa:
- Contenedor Edge Runtime en ejecución
- Funciones presentes como archivos en el volumen
- VERIFY_JWT configurado conscientemente (false para webhooks que no envían JWT)

---

## Resumen

Elabora ahora un resumen con el siguiente formato:

```
# Auditoría de seguridad Edge Functions - [FECHA]

## Resultado

APROBADO:     X de Y comprobaciones
ADVERTENCIA:  X comprobaciones
CRÍTICO:      X comprobaciones

## Hallazgos críticos (actuar inmediatamente)
- ...

## Advertencias (resolver esta semana)
- ...

## Aprobados
- ...

## Próximos pasos recomendados
1. ...
2. ...
3. ...
```

Prioriza estrictamente: hallazgos críticos primero, luego advertencias.
Para cada hallazgo: cuál es el problema, por qué es un riesgo, cuál es la solución.
