fix(dispatcher): fail-closed quando secret ausente — SEC-003#63
Conversation
Achado SEC-003 da auditoria back-end sênior 2026-05-22 (PR #55): quando WEBHOOK_DISPATCHER_SECRET ou o secret de cron não estavam configurados em vault nem em env, authorizeDispatcher/authorizeCron aceitavam a chamada como "legacy_no_auth" com apenas console.warn. Em PROD os 3 secrets já estão no vault, mas qualquer clone (staging, dev, preview Lovable, fork) herdava acesso anônimo. Mudanças: - _shared/dispatcher-auth.ts: ambos authorizeDispatcher e authorizeCron agora devolvem 503 service_misconfigured (fail-closed) quando o secret não está disponível. Remove o ramo "legacy_no_auth" dos type unions DispatcherAuthMode e CronAuthMode. - _shared/dispatcher-auth.test.ts: corrige tests para usar `await` (authorizeCron é async desde a integração do vault), substitui o teste "legacy_no_auth (retrocompat)" pelo teste "fail-closed 503 (SEC-003)" que valida status code e body. - webhook-dispatcher/index.ts: atualiza comentário de header para refletir o novo comportamento fail-closed. Operação pós-merge necessária: - Confirmar SIM que os 3 secrets continuam no vault de PROD: WEBHOOK_DISPATCHER_SECRET, CRON_SECRET, CONNECTIONS_AUTO_TEST_SECRET. Validado em 2026-05-22 via vault.decrypted_secrets — os 3 estão lá. - Para staging/dev clones: provisionar os mesmos secrets ANTES de invocar webhook-dispatcher ou qualquer cron, senão 503. https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughPR implementa mudança crítica de segurança: remoção de modo legacy_no_auth (autorização anônima retrocompatível) e adoção de fail-closed para dispatcher e cron. Quando secrets não estão configurados, ambas funções retornam 503 service_misconfigured em vez de permitir acesso. Tipos, implementação, testes e documentação foram atualizados coerentemente. ChangesAutorização Fail-Closed para Webhook Dispatcher e Jobs Cron
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Summary
Fix do achado SEC-003 (🟠 ALTO) da auditoria back-end sênior 2026-05-22.
_shared/dispatcher-auth.ts:240-253(webhook-dispatcher) e:286-294(crons) aceitavam chamadas anônimas como"legacy_no_auth"quando o secret esperado não estava em vault nem em env. Apenasconsole.warnera emitido. PROD está OK (os 3 secrets —WEBHOOK_DISPATCHER_SECRET,CRON_SECRET,CONNECTIONS_AUTO_TEST_SECRET— estão no vault, validado viaSELECT name FROM vault.decrypted_secrets), mas qualquer ambiente clonado herdava o comportamento fail-open.Changes
supabase/functions/_shared/dispatcher-auth.tsauthorizeDispatchereauthorizeCronagora devolvem 503service_misconfiguredquando o secret está ausente, em vez de aceitarlegacy_no_auth. Mode"legacy_no_auth"removido dos type unionsDispatcherAuthModeeCronAuthMode(sem callers externos verificados via grep).supabase/functions/_shared/dispatcher-auth.test.tsawait(a função éasyncdesde a integração do vault — testes anteriores tinham bug silencioso). Troca o teste "env não setada => legacy_no_auth" pelo equivalente fail-closed que valida status503e body{error:"service_misconfigured"}.supabase/functions/webhook-dispatcher/index.tsOperação pós-merge
Obrigatório:
SELECT name FROM vault.decrypted_secrets— todos presentes:CONNECTIONS_AUTO_TEST_SECRET,CRON_SECRET,WEBHOOK_DISPATCHER_SECRET).Para clones (staging, dev, preview Lovable, fork):
cron.jobpara usarpublic.get_edge_function_secret('<NOME>')no headerx-cron-secret(PROD já está assim — verificar em clones).Impacto comportamental
mode: "secret_vault"mode: "secret_vault"(sem mudança)mode: "secret"mode: "secret"(sem mudança)Test plan
grep -rn "legacy_no_auth" supabase/ src/retorna apenas o comentário explicativo no próprio arquivo"legacy_no_auth"(grep emauth.mode,result.mode,DispatcherAuthMode,CronAuthModefora do _shared)Edge Functions — Deno typecheckmode: "secret_vault"continua funcionando (não regressão)Notas sobre CI
3 checks do CI estão falhando em
mainpor motivos não relacionados (issues #58, #59, #61 — typecheck baseline regression, mocks de teste quebrados, smoke E2E timeout). Este PR não introduz nada que conserte ou agrave esses problemas.Severidade & prioridade
https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3
Generated by Claude Code
Summary by cubic
Enforce fail-closed auth for webhook dispatcher and crons: when required secrets are missing, return 503 service_misconfigured instead of accepting anonymous calls (SEC-003). Prod is unchanged; clones without secrets will now get 503 until configured.
Bug Fixes
supabase/functions/_shared/dispatcher-auth.ts,authorizeDispatcherandauthorizeCronreturn 503 with{ error: "service_misconfigured" }when the expected secret is missing; removed"legacy_no_auth"fromDispatcherAuthModeandCronAuthMode.awaitasync calls and validate the 503 path; updated the header comment inwebhook-dispatcher/index.ts.Migration
WEBHOOK_DISPATCHER_SECRET,CRON_SECRET, andCONNECTIONS_AUTO_TEST_SECRETin vault (preferred) or env before deploying non-prod.x-cron-secretusingpublic.get_edge_function_secret('<NAME>').Written for commit 1b50279. Summary will update on new commits. Review in cubic
Summary by CodeRabbit
Bug Fixes
Documentation