# Auditoria de Seguranca de Background Jobs Trigger.dev

Voce e um Senior DevOps Security Auditor. Sua tarefa e verificar se o setup
do Trigger.dev foi implementado corretamente conforme o runbook (artigo 4).

Execute os seguintes checks na ordem. Utilize as ferramentas disponiveis.
Para cada check: reporte APROVADO, AVISO ou CRITICO com justificativa breve.
Ao final, elabore um resumo com recomendacoes de acao.

---

## A1: Trigger.dev como servico independente

Verifique se o Trigger.dev roda separado do Next.js e do Supabase.

```bash
# Trigger.dev Container/Prozesse
echo "=== Trigger.dev Container ==="
docker ps --format '{{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null | grep -i "trigger"

# Eigene Datenbank?
echo "=== Trigger.dev Datenbank ==="
ss -tlnp | grep 5433 2>/dev/null || echo "Port 5433 nicht aktiv"

# Supabase DB auf anderem Port?
echo "=== Supabase Datenbank ==="
ss -tlnp | grep 5432 2>/dev/null || echo "Port 5432 nicht aktiv"

# Trigger.dev docker-compose vorhanden?
echo "=== Trigger.dev Compose ==="
find /opt -name "docker-compose*" -path "*trigger*" 2>/dev/null | head -5

# Dashboard nur intern?
echo "=== Dashboard Port ==="
ss -tlnp | grep 3040 2>/dev/null
```

Expectativa:
- Containers do Trigger.dev em execucao (Platform + DB)
- PostgreSQL proprio na porta 5433 (nao o DB do Supabase na porta 5432)
- Dashboard (porta 3040) apenas em 127.0.0.1 (nao em 0.0.0.0)

Risco: Trigger.dev no banco do Supabase = queries da fila de jobs competem com requests de usuarios. Dashboard externo = acesso ao historico de execucoes e logs.

---

## A2: Acesso ao banco de dados controlado

Verifique se as tasks restringem corretamente o acesso ao banco de dados.

```bash
# Trigger Tasks Verzeichnis finden
TASKS_DIR=$(find . -path "*/trigger/tasks" -type d 2>/dev/null | grep -v node_modules | head -1)
TASKS_DIR=${TASKS_DIR:-"trigger/tasks"}

# Shared Supabase Client vorhanden?
echo "=== Shared Client ==="
find . -path "*/trigger/lib/*" -name "*.ts" 2>/dev/null | grep -v node_modules

# Wo wird service_role / DATABASE_URL verwendet?
echo "=== service_role in Tasks ==="
grep -rn "SERVICE_ROLE\|service_role\|createTaskClient\|createAdminClient" \
  ${TASKS_DIR}/ --include="*.ts" 2>/dev/null | head -10

# Direkte DB-Connection?
echo "=== Direkte DB-Connection ==="
grep -rn "DATABASE_URL\|postgres(\|pg\.connect\|new Pool" \
  trigger/ --include="*.ts" 2>/dev/null | grep -v node_modules | head -10

# Connection Pool Limits?
echo "=== Connection Pool Config ==="
grep -rn "max:\|pool\|idle_timeout\|connect_timeout" \
  trigger/ --include="*.ts" 2>/dev/null | grep -v node_modules | head -10

# SELECT * Patterns (zu breiter Zugriff)?
echo "=== SELECT * Patterns ==="
grep -rn "\.select('\\*')\|\.select(\`\\*\`)\|SELECT \\*" \
  ${TASKS_DIR}/ --include="*.ts" 2>/dev/null | head -10
```

Expectativa:
- Client Factory compartilhado em trigger/lib/ (nao em cada task individualmente)
- service_role apenas na Client Factory, nao diretamente nas tasks
- Connection Pool com limite max (5-10)
- Sem SELECT * (apenas campos necessarios)

Risco: Tasks contornam RLS. Sem limitacao de escopo = acesso total ao banco. Sem limite de pool = Connection Starvation.

---

## B1: Definicoes de Tasks corretas

Verifique se todas as tasks estao corretamente definidas conforme a API v3.

```bash
TASKS_DIR=$(find . -path "*/trigger/tasks" -type d 2>/dev/null | grep -v node_modules | head -1)
TASKS_DIR=${TASKS_DIR:-"trigger/tasks"}

# Alle Task-Dateien
echo "=== Task-Dateien ==="
ls ${TASKS_DIR}/*.ts 2>/dev/null

# Exportierte Tasks?
echo "=== Nicht-exportierte Tasks ==="
for file in ${TASKS_DIR}/*.ts 2>/dev/null; do
  [ -f "$file" ] || continue
  name=$(basename "$file" .ts)
  if ! grep -q "export const" "$file"; then
    echo "CRÍTICO: $name ist nicht exportiert"
  fi
done

# Task IDs vorhanden und eindeutig?
echo "=== Task IDs ==="
grep -rn "id:" ${TASKS_DIR}/ --include="*.ts" 2>/dev/null | grep "task({" -A1 | grep "id:" | \
  awk -F'"' '{print $2}' | sort | uniq -c | sort -rn | head -10

# Werden Tasks aus Client-Code getriggert?
echo "=== Tasks aus Client Code ==="
grep -rn "tasks\.trigger\|\.trigger(" app/ --include="*.tsx" 2>/dev/null | \
  grep -v "use server" | grep -v node_modules | head -5
```

Expectativa:
- Todas as tasks exportadas (export const)
- Todas as tasks com IDs unicos
- Tasks acionadas APENAS a partir de contexto server (nao de .tsx Client Components)

Risco: Tasks nao exportadas sao ignoradas no deploy sem mensagem de erro. Tasks acionadas do client code expoem a API do Trigger.

---

## B2: Idempotencia

Verifique se as tasks sao idempotentes, especialmente em chamadas de API externas.

```bash
TASKS_DIR=$(find . -path "*/trigger/tasks" -type d 2>/dev/null | grep -v node_modules | head -1)
TASKS_DIR=${TASKS_DIR:-"trigger/tasks"}

# Tasks mit externen API-Calls
echo "=== Tasks mit externen Calls ==="
for file in ${TASKS_DIR}/*.ts 2>/dev/null; do
  [ -f "$file" ] || continue
  name=$(basename "$file" .ts)
  if grep -qE "fetch\(|stripe\.|resend\.|sendgrid\.|openai\.|anthropic\." "$file"; then
    HAS_IDEM=$(grep -cE "idempotencyKey|idempotencyKeys" "$file" || echo 0)
    if [ "$HAS_IDEM" -gt 0 ]; then
      echo "OK: $name hat externe Calls + Idempotency Keys"
    else
      echo "AVISO: $name hat externe Calls OHNE Idempotency Keys"
    fi
  fi
done

# DB-Operationen: upsert statt insert?
echo "=== Insert vs Upsert ==="
grep -rn "\.insert(" ${TASKS_DIR}/ --include="*.ts" 2>/dev/null | head -5
grep -rn "\.upsert(" ${TASKS_DIR}/ --include="*.ts" 2>/dev/null | head -5

# Idempotency beim Triggern (aus Next.js)?
echo "=== Idempotency beim Triggern ==="
grep -rn "idempotencyKey" app/ --include="*.ts" 2>/dev/null | grep -v node_modules | head -10
```

Expectativa:
- Tasks com chamadas de API externas (Stripe, e-mail, etc.) possuem idempotencyKeys
- Operacoes de banco utilizam upsert onde possivel (ao inves de insert)
- Chamadas trigger no Next.js possuem idempotencyKey onde double-trigger e possivel

Risco: Sem idempotencia no retry = pagamentos duplicados, e-mails duplicados, registros duplicados no banco.

---

## B3: Timeouts e Concurrency

Verifique se todas as tasks possuem maxDuration e limites de Concurrency.

```bash
TASKS_DIR=$(find . -path "*/trigger/tasks" -type d 2>/dev/null | grep -v node_modules | head -1)
TASKS_DIR=${TASKS_DIR:-"trigger/tasks"}

# Tasks ohne maxDuration
echo "=== maxDuration ==="
for file in ${TASKS_DIR}/*.ts 2>/dev/null; do
  [ -f "$file" ] || continue
  name=$(basename "$file" .ts)
  if grep -q "maxDuration" "$file"; then
    DURATION=$(grep "maxDuration" "$file" | grep -oP '\d+' | head -1)
    echo "OK: $name (maxDuration: ${DURATION}s)"
  else
    echo "AVISO: $name hat KEIN maxDuration"
  fi
done

# Tasks ohne Concurrency Limit
echo "=== Concurrency ==="
for file in ${TASKS_DIR}/*.ts 2>/dev/null; do
  [ -f "$file" ] || continue
  name=$(basename "$file" .ts)
  if grep -qE "concurrencyLimit|queue:" "$file"; then
    LIMIT=$(grep "concurrencyLimit" "$file" | grep -oP '\d+' | head -1)
    echo "OK: $name (concurrency: ${LIMIT:-shared queue})"
  else
    echo "AVISO: $name hat KEIN Concurrency Limit"
  fi
done

# Shared Queues?
echo "=== Shared Queues ==="
grep -rn "queue({" trigger/ --include="*.ts" 2>/dev/null | grep -v node_modules | head -5
```

Expectativa:
- Todas as tasks possuem maxDuration (e-mail: 30s, PDF: 120s, IA: 300s)
- Todas as tasks possuem concurrencyLimit ou utilizam uma shared queue
- Shared queues para tasks que utilizam o mesmo servico externo

Risco: Sem maxDuration = task trava indefinidamente em caso de timeout de API. Sem concurrency = todos os worker slots bloqueados.

---

## B4: Estrategia de Retry

Verifique se as tasks possuem uma configuracao de retry adequada.

```bash
TASKS_DIR=$(find . -path "*/trigger/tasks" -type d 2>/dev/null | grep -v node_modules | head -1)
TASKS_DIR=${TASKS_DIR:-"trigger/tasks"}

echo "=== Retry Konfiguration ==="
for file in ${TASKS_DIR}/*.ts 2>/dev/null; do
  [ -f "$file" ] || continue
  name=$(basename "$file" .ts)
  if grep -q "retry:" "$file"; then
    ATTEMPTS=$(grep -A5 "retry:" "$file" | grep "maxAttempts" | grep -oP '\d+' | head -1)
    echo "OK: $name (maxAttempts: ${ATTEMPTS:-?})"
  else
    echo "AVISO: $name hat KEINE Retry-Konfiguration (nutzt Default: kein Retry)"
  fi
done

# onFailure Hooks für kritische Tasks?
echo "=== onFailure Hooks ==="
for file in ${TASKS_DIR}/*.ts 2>/dev/null; do
  [ -f "$file" ] || continue
  name=$(basename "$file" .ts)
  if grep -q "onFailure" "$file"; then
    echo "OK: $name hat onFailure Hook"
  else
    echo "INFO: $name hat keinen onFailure Hook"
  fi
done
```

Expectativa:
- Todas as tasks possuem configuracao de retry com maxAttempts e backoff exponencial
- Tasks criticas (pagamentos, sync importantes) possuem hooks onFailure

Risco: Sem retry = erro temporario de API leva a perda permanente de dados. Sem onFailure = tasks com falha passam despercebidas.

---

## B5: Gerenciamento de Secrets

Verifique se os secrets estao sendo gerenciados corretamente.

```bash
# Hardcoded Secrets in Tasks?
echo "=== Hardcoded Secrets ==="
grep -rn "sk_live\|sk_test\|SG\.\|sk-proj\|sk-ant\|Bearer ey\|whsec_" \
  trigger/ --include="*.ts" 2>/dev/null | grep -v node_modules || \
  echo "Keine hardcoded Secrets gefunden (gut)"

# Secrets über process.env geladen?
echo "=== process.env Nutzung ==="
grep -rn "process\.env\." trigger/ --include="*.ts" 2>/dev/null | \
  grep -v node_modules | head -10

# .env.trigger nicht im Git?
echo "=== .env.trigger im Git? ==="
git ls-files .env.trigger 2>/dev/null || echo "Nicht im Git (gut)"

# .env.trigger Rechte
echo "=== .env.trigger Rechte ==="
ENV_TRIGGER=$(find . /opt -name ".env.trigger" 2>/dev/null | head -1)
if [ -n "$ENV_TRIGGER" ]; then
  stat -c "%a %U" "$ENV_TRIGGER"
fi
```

Expectativa:
- Sem API keys hardcoded no codigo
- Secrets carregados via process.env
- .env.trigger fora do Git, permissoes 600

Risco: Secrets no codigo acabam no repositorio Git e nas imagens de workers.

---

## B6: Logging

Verifique se as tasks utilizam o logger do Trigger.dev e nao logam dados sensiveis.

```bash
TASKS_DIR=$(find . -path "*/trigger/tasks" -type d 2>/dev/null | grep -v node_modules | head -1)
TASKS_DIR=${TASKS_DIR:-"trigger/tasks"}

# console.log statt logger?
echo "=== console.log in Tasks ==="
grep -rn "console\.log\|console\.error\|console\.warn" \
  ${TASKS_DIR}/ --include="*.ts" 2>/dev/null || echo "Keine console.log gefunden (gut)"

# Trigger.dev logger importiert?
echo "=== logger Import ==="
grep -rn "from.*@trigger.dev.*logger\|import.*logger" \
  trigger/ --include="*.ts" 2>/dev/null | grep -v node_modules | head -5

# Sensible Daten in Logs?
echo "=== Sensible Daten in logger Calls ==="
grep -rn "logger\.\(info\|error\|warn\)" trigger/ --include="*.ts" 2>/dev/null | \
  grep -iE "password|secret|key|token|email.*:" | grep -v node_modules | head -5
```

Expectativa:
- Sem console.log nas tasks (sempre utilizar o logger do Trigger.dev)
- Sem dados sensiveis (senhas, tokens, e-mails de usuarios) nas chamadas de log

Risco: O Trigger.dev armazena todos os logs no dashboard. Dados sensiveis ficam visiveis para qualquer pessoa com acesso ao dashboard, mesmo meses depois.

---

## C1: Tratamento de Dead Letter

Verifique se tasks com falha sao capturadas.

```bash
# failed_jobs Tabelle vorhanden?
echo "=== failed_jobs Tabelle ==="
docker compose exec -T postgres psql -U postgres -c \
  "SELECT tablename FROM pg_tables WHERE tablename = 'failed_jobs';" 2>/dev/null || \
  echo "Konnte DB nicht prüfen"

# Unresolvierte Failed Jobs?
echo "=== Offene Failed Jobs ==="
docker compose exec -T postgres psql -U postgres -c \
  "SELECT count(*) as offen FROM failed_jobs WHERE resolved = false;" 2>/dev/null || \
  echo "Konnte nicht prüfen (Tabelle fehlt oder DB nicht erreichbar)"

# onFailure Hooks in kritischen Tasks?
TASKS_DIR=$(find . -path "*/trigger/tasks" -type d 2>/dev/null | grep -v node_modules | head -1)
TASKS_DIR=${TASKS_DIR:-"trigger/tasks"}

echo "=== Tasks OHNE onFailure ==="
for file in ${TASKS_DIR}/*.ts 2>/dev/null; do
  [ -f "$file" ] || continue
  name=$(basename "$file" .ts)
  if ! grep -q "onFailure" "$file"; then
    # Ist es ein kritischer Task?
    if grep -qE "payment\|invoice\|order\|billing\|charge\|subscription" "$file"; then
      echo "AVISO: Kritischer Task $name hat keinen onFailure Hook"
    else
      echo "INFO: $name hat keinen onFailure Hook"
    fi
  fi
done
```

Expectativa:
- Tabela failed_jobs existente (ou sistema equivalente)
- Sem failed jobs antigos nao resolvidos
- Tasks criticas (pagamentos, pedidos) possuem hooks onFailure

Risco: Tasks com falha sem alertas passam despercebidas ate que um cliente reclame.

---

## C2: Monitoramento

Verifique se o monitoramento do Trigger.dev esta configurado.

```bash
# Dashboard erreichbar (intern)?
echo "=== Dashboard ==="
curl -s -o /dev/null -w "%{http_code}" http://localhost:3040 2>/dev/null || echo "Nicht erreichbar"

# Dashboard NICHT extern erreichbar?
echo "=== Dashboard extern ==="
EXTERNAL_HOST=$(hostname -I | awk '{print $1}')
curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 "http://${EXTERNAL_HOST}:3040" 2>/dev/null || echo "Nicht extern erreichbar (gut)"

# Health Check Script vorhanden?
echo "=== Health Check ==="
find /opt -name "*trigger*health*" -o -name "*check*trigger*" 2>/dev/null | head -5

# Cron Job für Monitoring?
echo "=== Cron ==="
crontab -l 2>/dev/null | grep -i "trigger"
```

Expectativa:
- Dashboard acessivel internamente
- Dashboard NAO acessivel externamente
- Health check ou monitoramento configurado

---

## Resumo

Elabore agora um resumo neste formato:

```
# Auditoria de Seguranca Trigger.dev - [DATA]

## Resultado

APROVADO:  X de Y Checks
AVISO:     X Checks
CRITICO:   X Checks

## Findings Criticos (agir imediatamente)
- ...

## Avisos (resolver nesta semana)
- ...

## Aprovados
- ...

## Proximos Passos Recomendados
1. ...
2. ...
3. ...
```

Priorize estritamente: Findings criticos primeiro, depois avisos.
Para cada finding: Qual e o problema, por que e um risco, qual e a solucao.
