feat(onda-9.1): migration SQL vault healthcheck — persiste recovery da Onda 9#124
Conversation
Persiste no repositório os 7 objetos SQL criados em produção durante
a recuperação cirúrgica do Vault na Onda 9 (2026-05-09).
Componentes:
- public.vault_healthcheck_log (tabela append-only)
- public.fn_vault_healthcheck() (read-only, valida 24/24)
- public.fn_vault_healthcheck_run() (executa + log)
- public.fn_vault_healthcheck_cleanup() (retenção 30d)
- public.v_vault_health (view top-20)
- cron 'vault_healthcheck' (a cada 15min)
- cron 'vault_healthcheck_cleanup' (4am UTC diário)
Idempotência: 100% — testada aplicando em produção:
- Tabela: NOTICE 'already exists, skipping' (dados preservados)
- Index: NOTICE 'already exists, skipping'
- Funções/View: CREATE OR REPLACE
- Cron: cron.unschedule() em DO...EXCEPTION + cron.schedule()
Smoke test em produção (post-apply):
{"ok": 24, "fail": 0, "defer": 7, "status": "healthy"}
Ref: /workspace/notes/onda-9-vault-recovery-2026-05-09.md (doc-mãe RCA + recovery)
Ref: PR Onda 9.2 (docs) — segue separado.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughMigração idempotente que implementa um sistema de monitoramento contínuo do vault através de uma função de healthcheck, tabela de logging append-only, view de exposição de dados, funções de limpeza de retenção e automação agendada via cron jobs. ChangesVault Healthcheck System
Pontos Críticos de Segurança e Performance🔴 Segurança
🟡 Performance
🟢 Smoke Test & Idempotência
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutos 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5abfc7df4e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Este PR adiciona uma migration idempotente para persistir no repositório os objetos SQL do “Vault Healthcheck” criados diretamente em produção durante a recuperação do Supabase Vault (Onda 9), garantindo que eles não se percam em redeploy/reset/clone do banco.
Changes:
- Cria tabela de log
public.vault_healthcheck_log+ índice porchecked_at. - Adiciona funções de healthcheck, execução/persistência e limpeza por retenção.
- Cria view de leitura e agenda 2 cron jobs (
vault_healthcheckevault_healthcheck_cleanup), além de um smoke test viaRAISE NOTICE.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@supabase/migrations/20260510131942_a5fcc99c-92cc-4be6-895a-f9a0d453a871.sql`:
- Around line 55-57: As funções fn_vault_healthcheck() e
fn_vault_healthcheck_run() usam SECURITY DEFINER mas não têm hardening de
execução; REVOKE ALL ON FUNCTION fn_vault_healthcheck() FROM PUBLIC e REVOKE ALL
ON FUNCTION fn_vault_healthcheck_run() FROM PUBLIC should be added after
function creation, then explicitly GRANT EXECUTE ON FUNCTION
fn_vault_healthcheck() TO <trusted_role> and GRANT EXECUTE ON FUNCTION
fn_vault_healthcheck_run() TO <trusted_role> (replace <trusted_role> with the
minimal role(s) that require invocation); keep the existing search_path and
SECURITY DEFINER unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: f99046b2-14f7-497e-aed9-10dc5f199e31
📒 Files selected for processing (1)
supabase/migrations/20260510131942_a5fcc99c-92cc-4be6-895a-f9a0d453a871.sql
… Major) Aplica least privilege nas 3 funções do healthcheck após feedback do CodeRabbit no PR #124. ## O que muda Adiciona 3 blocos REVOKE/GRANT após cada COMMENT ON FUNCTION: - fn_vault_healthcheck() → REVOKE FROM public, anon GRANT EXECUTE TO authenticated, service_role - fn_vault_healthcheck_run() → REVOKE FROM public, anon GRANT EXECUTE TO service_role - fn_vault_healthcheck_cleanup() → REVOKE FROM public, anon GRANT EXECUTE TO service_role (LANGUAGE sql, SECURITY INVOKER — restringimos surface por consistência) ## Padrão seguido Idêntico ao precedente do projeto: supabase/migrations/20260423174952_*.sql linhas 42-43: REVOKE ALL ON FUNCTION public.cleanup_failed_messages() FROM public, anon; GRANT EXECUTE ON FUNCTION public.cleanup_failed_messages() TO authenticated, service_role; ## Validação em produção Aplicado v2 em produção como idempotency test: - NOTICE 'already exists, skipping' (tabela/index — dados preservados) - 3× CREATE FUNCTION (REPLACE) - 3× REVOKE + 3× GRANT (NOVOS — antes ACL estava vazia) - 1× CREATE VIEW (REPLACE) - 2× cron unschedule + reschedule (idempotente) - Smoke test: {"ok": 24, "fail": 0, "defer": 7, "status": "healthy"} ACL pós-apply (pg_proc.proacl): fn_vault_healthcheck → postgres, authenticated, service_role fn_vault_healthcheck_run → postgres, service_role fn_vault_healthcheck_cleanup → postgres, service_role (PUBLIC e anon revogados ✅) Resolves: CodeRabbit review comment #124 (linha 57, severity Major) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@coderabbitai obrigado pelo feedback! Aplicado em O que mudouAdicionados 3 blocos
Padrão seguidoIdêntico ao precedente do projeto em REVOKE ALL ON FUNCTION public.cleanup_failed_messages() FROM public, anon;
GRANT EXECUTE ON FUNCTION public.cleanup_failed_messages() TO authenticated, service_role;Validação em produçãoMigration v2 aplicada como idempotency test: ACL final em PUBLIC e anon não aparecem = REVOKE funcionou. Least privilege aplicado. |
|
Tip For best results, initiate chat on the files or code changes.
A matriz de permissões está correta e bem justificada:
O dump do ᓚᘏᗢ ✨ |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7c78acb9e6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
* docs(onda-9.2): handoff RCA + runbook supabase volumes Persiste no repositório a documentação produzida durante a Onda 9 (recuperação cirúrgica do Vault — 2026-05-09). ## Arquivos novos - docs/handoff-2026-05-09-onda-9-vault-recovery.md (+419 linhas) Doc-mãe: RCA, decisões D1-D11, recovery 24/24, 7 DEFER documentados, backlog de pendências externas. Versão REDACTADA — credenciais sensíveis substituídas por <REDACTED-*>. - docs/runbooks/SUPABASE-VOLUMES-DOS-AND-DONTS.md (+181 linhas) Runbook prático: volumes críticos, operações proibidas (DO NOT), procedimentos corretos (DO), caso histórico Onda 9, plano de migração futura (deprecação pgsodium). ## Por que dois arquivos - doc-mãe: histórico/forense da Onda 9 (consultar quando vault quebrar de novo) - runbook: manual operacional (consultar ANTES de tocar no stack supabase) ## Secrets Auditoria pré-commit: zero secrets críticos (api keys, passwords, account IDs) na versão pública. Versão original com plaintext permanece em /workspace/notes/ (acesso restrito). Ref: PR Onda 9.1 (#124) — migration SQL do healthcheck. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(onda-9.2): aplicar 3 correções do CodeRabbit (Major + 2 Minor) ## Issue 1 (Major) — Sanitizar paths internos no doc público CodeRabbit (linha 2): caminhos /workspace/notes/* expostos no doc público facilitam enumeração de infra. Substituídos por placeholders genéricos: /workspace/notes/onda-9-vault-recovery-2026-05-09.md → 'armazenamento interno com acesso controlado' /workspace/notes/runbooks/SUPABASE-VOLUMES-DOS-AND-DONTS.md → docs/runbooks/SUPABASE-VOLUMES-DOS-AND-DONTS.md (versionado) /workspace/notes/backups/supabase_db_config_*.tar.gz → <internal-backup-storage>/supabase_db_config_*.tar.gz /workspace/notes/backups/ → 'armazenamento interno (acesso controlado)' 7 ocorrências em 6 linhas (2, 250, 257, 264, 307, 412, 418). Auditoria pós-edit: 0 ocorrências de '/workspace' no documento. ## Issue 2 (Minor) — markdownlint warnings CodeRabbit (linha 24): code blocks sem linguagem (MD040) + headings duplicados (MD024). - 5 code fences de abertura ganharam linguagem 'text' (linhas 19, 91, 234, 256, 396). Os 6 fences de fechamento permanecem sem linguagem (não exigido pelo lint). - 3 headings 'Estado atual' renomeados para únicos: Linha 138: '## Estado atual (pós-F1 RCA)' Linha 200: '## Estado atual (pós-F3 recovery)' Linha 301: '## Estado atual (encerramento F4)' CodeRabbit citou 2 duplicados; encontrei 3 — todos resolvidos. ## Issue 3 (Minor) — Inconsistência factual DEFER 8/31 vs 7/31 CodeRabbit (linha 187): linha 187 dizia 'DEFER: 8/31', mas o resto do doc mostra 7/31. Bug factual corrigido. Antes: '**Coletados: 23/31 | DEFER: 8/31**' Depois: '**Coletados: 23/31 | DEFER: 7/31**' ## Validação final (auditoria 8/8 critérios) 1. Paths internos: 0 ✅ 2. Code blocks sem linguagem: 6 (todos closing) ✅ 3. Code blocks com linguagem: 6 ✅ 4. Heading 'Estado atual' duplicado: 0 ✅ 5. Heading 'Estado atual …' único: 3 ✅ 6. DEFER: 8/31: 0 ✅ 7. DEFER: 7/31: 1 ✅ 8. Secrets sensíveis: 0 ✅ Resolves: CodeRabbit review comments #125 (linhas 2, 24, 187) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…128) Após merge dos PRs #124 e #125, descobri 4 review threads abertas de GitHub Copilot e ChatGPT Codex Connector que CodeRabbit não cobriu. Esse PR endereça as 4 críticas reais (P2/Minor mas válidas). ## Issue 1: Migration sem CREATE EXTENSION pg_cron (Copilot, P2) Localização: supabase/migrations/20260510131942_*.sql A migration usa cron.unschedule/cron.schedule mas não garante a extensão pg_cron. 3 outras migrations do projeto seguem o pattern defensivo (precedente): supabase/migrations/20260319134320_*.sql supabase/migrations/20260409013312_*.sql supabase/migrations/20260423174952_*.sql Em prod atual já está instalada (re-aplicação confirmou 'extension already exists, skipping' = no-op idempotente). Em ambiente novo, a anterior 20260423174952 já cria, mas adicionar aqui mantém defensive pattern e evita assumption. ## Issue 2: Vazamento parcial de credencial 429683... (Copilot, P2) Localização: docs/handoff-2026-05-09-onda-9-vault-recovery.md L228 L228 tinha: | F3.14 Test fn_get_vault_secret('evolution_api_key') | ✅ retorna '429683...' | Mesmo prefixo parcial pode ajudar em enumeração. CodeRabbit pediu sanitização similar nas linhas 2/250/257/264/307/412/418 mas não pegou a 228. Substituído por '<REDACTED-evolution-api-key-prefix>'. ## Issue 3: Referência a arquivo inexistente docker-compose-supabase.yml (Copilot, P2) Localização: docs/runbooks/SUPABASE-VOLUMES-DOS-AND-DONTS.md L130 + docs/handoff-2026-05-09-onda-9-vault-recovery.md L272, L390 O runbook recomenda 'docker stack deploy -c docker-compose-supabase.yml' mas esse arquivo não existe no repo. O nome real do compose Supabase self-hosted nesta VPS é '/root/supabase.yaml' (host filesystem), documentado em docs/DEPLOYMENT.md. Corrigido para apontar pra '/root/supabase.yaml'. ## Issue 4: Path interno /workspace/notes/backups/ no runbook L180 Localização: docs/runbooks/SUPABASE-VOLUMES-DOS-AND-DONTS.md L180 + supabase/migrations/20260510131942_*.sql L22 CodeRabbit pediu sanitização similar no handoff (linhas 250, 257, 264, 307, 412, 418 — todas resolvidas no PR #125), mas o runbook L180 e a migration L22 ainda tinham /workspace/notes/. Inconsistência corrigida: L180 → '<internal-backup-storage>/supabase_db_config_*.tar.gz' L22 → '-- Ref: internal incident record (Onda 9)' ## Validação Migration v3 aplicada em produção como idempotency test: NOTICE: extension 'pg_cron' already exists, skipping CREATE EXTENSION CREATE FUNCTION x3 (REPLACE) REVOKE x3 + GRANT x3 (idempotente) CREATE VIEW cron schedule | 51, 52 (reagendados) Smoke test: {'ok': 24, 'fail': 0, 'defer': 7, 'status': 'healthy'} Banco produção continua healthy. ACL hardening preservada. ## Auditoria final 9/9 critérios 1. Migration tem CREATE EXTENSION pg_cron: ✅ 1 ocorrência 2. Migration sem /workspace: ✅ 0 3. Handoff sem 429683: ✅ 0 4. Handoff sem docker-compose-supabase: ✅ 0 5. Handoff sem /workspace: ✅ 0 6. Runbook sem docker-compose-supabase: ✅ 0 7. Runbook sem /workspace: ✅ 0 8. Banco prod healthy pós-apply: ✅ healthy 9. Cron jobs ativos: ✅ 51 + 52 reagendados Resolves: 4 review threads abertas pós-PRs #124 e #125 - copilot-pull-request-reviewer: pg_cron L192, prefixo 429683 L228, docker-compose L130 - (descoberta na auditoria): /workspace L180 runbook, L22 migration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
🧹 Encerramento das review threads (auditoria pós-merge)Auditoria completa realizada. Todas as 7 threads abertas pelos reviewers Copilot e Codex foram avaliadas e marcadas como Resolved com a justificativa abaixo: ✅ Endereçadas (correção em main)
🟡 Backlog aceito (não bloqueante)
Validação em produção (hoje): Onda 9 oficialmente arquivada. Documentação consolidada em |
🌊 Onda 9.1 — Persistir o Vault Healthcheck no repositório
Em 09/05 a Onda 9 fez recuperação cirúrgica do Supabase Vault (24 secrets corrompidos por substituição de chave pgsodium em 2026-04-29). Toda a operação foi feita direto no banco via psql — incluindo 7 objetos SQL de monitoramento contínuo que ficaram só em produção.
Este PR persiste esses 7 objetos como migration idempotente — protegendo contra perda em redeploy/reset/clone.
🎯 O que entra (1 arquivo)
supabase/migrations/20260510131942_a5fcc99c-92cc-4be6-895a-f9a0d453a871.sql📦 Componentes da migration
public.vault_healthcheck_logidx_vault_healthcheck_log_checked_atchecked_atpublic.fn_vault_healthcheck()jsonbcomok/fail/defer/status. Iteravault.secrets, tenta decifrar cada viavault.decrypted_secrets. Cada decryption em sub-bloco EXCEPTION para capturarinvalid ciphertextsem abortar o looppublic.fn_vault_healthcheck_run()vault_healthcheck_logpublic.fn_vault_healthcheck_cleanup()public.v_vault_healthage()calculadavault_healthcheckSELECT public.fn_vault_healthcheck_run();vault_healthcheck_cleanupSELECT public.fn_vault_healthcheck_cleanup();🛡️ Idempotência 100% — testado em produção
Critério: rodar 2x não pode causar erro nem perda de dados.
CREATE TABLE IF NOT EXISTSNOTICE: relation "vault_healthcheck_log" already exists, skippingCREATE INDEX IF NOT EXISTSNOTICE: relation "idx_vault_healthcheck_log_checked_at" already exists, skippingCREATE OR REPLACE FUNCTIONCREATE FUNCTION(replace)CREATE OR REPLACE VIEWCREATE VIEW(replace)cron.unschedule()emDO...EXCEPTION+cron.schedule()RAISE NOTICEcom payload{"ok": 24, "fail": 0, "defer": 7, "status": "healthy"}Comportamento idêntico ao precedente do PR
20260423174952(cleanup-failed-messages-daily).🧪 Validação executada
Migration foi aplicada em produção durante o desenvolvimento deste PR:
Estado pós-apply do
cron.job:🎯 Por que isso é importante
Antes deste PR: os 7 objetos viviam só em
supabase_db. Qualquer reset, redeploy, ou clone do banco perderia o healthcheck silenciosamente — ninguém notaria até o vault quebrar de novo (Onda 9 mostrou que a primeira vez ninguém notou por 6 dias).Depois deste PR: a migration faz parte do source-of-truth. CI/dev/staging/prod ficam alinhados.
🔍 Risco
🟢 Zero. A migration é idempotente e foi validada em produção como no-op (objetos já existem). CI não aplica migrations automaticamente (validado em
.github/workflows/). Migration só roda quando explicitamente invocada (supabase db pushoupsql -f).📋 Contexto Onda 9 (3 PRs sequenciais)
docs/)🤖 Review
@coderabbitai full review
🤖 Generated with Claude Code
Summary by CodeRabbit
Notas da Versão