Protocolo de Segurança para Mudanças Críticas
Status: Obrigatório
Data: 2026-04-07
Origem: Incidente de consistência — WITH CHECK omitido na entrega seguinte à criação do RLS_DESIGN_GUIDE.md
Última atualização: 2026-04-07
Por que este protocolo existe
Na sprint de abril/2026, o RLS_DESIGN_GUIDE.md foi criado com a regra obrigatória de WITH CHECK em toda policy de escrita. Na entrega imediatamente seguinte, o SQL gerado omitiu WITH CHECK — violando a regra que acabou de ser documentada.
A falha não foi de conhecimento — foi de processo. O plano aprovado já continha o erro. A execução seguiu o plano sem revalidar o SQL linha a linha contra o guia. O resultado: uma policy de UPDATE em coordenador_cores entrou em produção sem WITH CHECK, permitindo potencialmente que um usuário alterasse usuario_id ou escola_id durante um update.
Por que isso é grave no contexto OLP:
- Migrations Supabase entram em produção imediatamente após deploy — não existe "testar antes de ativar" para banco
- Edge Functions são ativadas automaticamente — não dependem de publicação do frontend
- RLS incorreto = superfície de ataque real (escalação de privilégios) ou bloqueio total de usuários (policy restritiva demais)
- Isso não é dívida técnica — é risco operacional imediato
1. Classificação de Risco por Tipo de Mudança
| Nível | Escopo | Justificativa | Protocolo |
|---|---|---|---|
| 🔴 Crítico | Migrations SQL, policies RLS, Edge Functions, supabase-client.ts, _shared/*.ts | Entram em produção imediatamente. RLS incorreto = superfície de ataque ou bloqueio de usuários. Não existe ambiente controlado pré-ativação. Edge Functions e banco afetam todos os usuários instantaneamente. | Protocolo de 3 Fases |
| 🟡 Alto | Hooks de auth (useAuth*), lógica de permissões frontend, supabase-client.ts (leitura), componentes de login/role | Controlam acesso visual e fluxo de dados no frontend. Erro = tela em branco, redirect loop, ou dados expostos no cliente. Reversíveis apenas com nova publicação. | Protocolo Reduzido |
| 🟢 Normal | Componentes UI, helpers puros, estilos, documentação | Não tocam banco nem auth. Erros são visíveis na preview e reversíveis com nova publicação. Impacto limitado e detectável. | Fluxo padrão (sem protocolo especial) |
Como classificar mudanças mistas
Se uma entrega contém mudanças de múltiplos níveis, o nível mais alto prevalece para toda a entrega. Exemplo: se há 5 componentes UI + 1 migration SQL → toda a entrega é Crítica.
2. Protocolo de 3 Fases — Mudanças Críticas
Fase 1 — Planejamento Textual
Objetivo: Alinhar O QUE será feito antes de escrever qualquer código.
Entregar:
- [ ] Quais tabelas/funções serão criadas, alteradas ou removidas
- [ ] Qual o impacto esperado (novas policies, novas colunas, novos endpoints)
- [ ] Quais documentos da
docs/foram consultados para embasar as decisões - [ ] Quais riscos foram identificados (ex: tabela sem policy temporariamente)
Proibido nesta fase: SQL, código TypeScript, migrations. Apenas linguagem natural.
⛔ PARADA OBRIGATÓRIA: Aguardar aprovação explícita ("aprovado, pode avançar para Fase 2") antes de prosseguir.
Fase 2 — SQL e Código Completo para Revisão
Objetivo: Apresentar o código final exato que será executado, após validação interna.
Antes de apresentar, executar o Checklist Interno Obrigatório item por item. Não apresentar SQL que não passou no checklist.
Entregar:
- [ ] SQL completo das migrations, linha a linha
- [ ] Policies RLS completas com
USING+WITH CHECK(quando aplicável) - [ ] Código das Edge Functions afetadas (diff ou arquivo completo)
- [ ] Código dos shared helpers afetados
- [ ] Resultado do checklist interno (confirmar que todos os itens passaram)
Se qualquer item do checklist falhar: Seguir o protocolo de auto-reporte — pausar, reportar, aguardar.
⛔ PARADA OBRIGATÓRIA: Aguardar aprovação explícita do SQL exato antes de executar.
Fase 3 — Execução
Objetivo: Implementar exatamente o que foi aprovado na Fase 2.
Regras:
- [ ] Implementar o SQL aprovado sem alterações
- [ ] Sem "otimizações de última hora" não aprovadas
- [ ] Sem "pequenas melhorias" adicionais
- [ ] Sem ajustes de formatação que alterem lógica
- [ ] Se durante a execução identificar um problema no SQL aprovado → pausar e reportar (não corrigir silenciosamente)
Após execução: O Checklist de Auditoria (@audit) permanece como validação pós-entrega.
3. Checklist Interno Obrigatório (Fase 2)
Este checklist é executado pelo próprio implementador na Fase 2, antes de apresentar o SQL/código para aprovação. Cada item é derivado de documentação real do projeto.
3.1 RLS — Policies de Segurança
Fonte: RLS_DESIGN_GUIDE.md
- [ ] Toda policy de INSERT tem
WITH CHECK(nunca apenasUSING) - [ ] Toda policy de UPDATE tem
USINGEWITH CHECK - [ ] Policies separadas por operação: SELECT, INSERT, UPDATE, DELETE — nunca
FOR ALL - [ ] Policies direcionadas a
TO authenticated— nuncaTO public - [ ] Cast
::textem colunas UUID comparadas com JWT (escola_id::text = auth.jwt()->>'escola_id') - [ ] Filtro
escola_idpresente em tabelas school-scoped - [ ] Filtro
sub(user ID) presente em tabelas self-access - [ ]
USING (true)usado apenas em SELECT de dados não-sensíveis — nunca em escrita - [ ] RLS habilitado (
ENABLE ROW LEVEL SECURITY) na mesma migration que cria a tabela
3.2 Clientes Supabase
Fonte: ADR_SERVICE_ROLE_USAGE.md
- [ ]
createSupabaseSystem()usado apenas para: logging (registrarLog), auth (pre-auth), crons, tabelas sem policies por design - [ ]
createSupabaseClient(req)usado para todas as operações autenticadas - [ ] Nenhum
createClient()inline fora desupabase-client.ts - [ ] Se
createSupabaseSystem()é usado em contexto novo → justificativa documentada no ADR
3.3 Migrations — Resiliência Multi-Ambiente
Fonte: MIGRATION_GUIDELINES.md
- [ ]
WHERE EXISTSem todo INSERT com UUID literal referenciando FK - [ ]
ON CONFLICTpara idempotência (re-execução segura) - [ ] Migration funciona em banco vazio (staging sem dados de produção)
- [ ] Sem
INSERT INTO ... VALUEScom FK hardcoded — usarSELECT ... WHERE EXISTS - [ ] JOINs dinâmicos preferidos sobre UUIDs literais
3.4 Edge Functions — Estrutura
Fonte: AUDIT_CHECKLIST.md §§4-5
- [ ] Silent failure tratada: após
.update()e.delete(), verificar resultado (.select()encadeado ou check dedata) - [ ]
getCorsHeaders(req)em todas as respostas (incluindocatchblocks) - [ ]
registrarLog()em todo Create/Update/Delete comreqcomo parâmetro - [ ] Formato de resposta:
{ success, data }ou{ success, message } - [ ]
extractAuthenticatedUser(req)chamado após actions públicas, antes das autenticadas
3.5 Validação Final
- [ ] Reli o SQL completo linha a linha contra os itens 3.1-3.4
- [ ] Comparei cada policy com os templates do RLS_DESIGN_GUIDE.md §4
- [ ] Verifiquei que não há discrepância entre o plano da Fase 1 e o SQL da Fase 2
4. Protocolo Reduzido — Mudanças de Alto Risco
Para mudanças classificadas como Alto (hooks de auth, lógica de permissões frontend), não é necessário o protocolo de 3 fases, mas um checklist mínimo pré-entrega é obrigatório:
- [ ] Auth flow verificado: login → cookie → redirecionamento funciona
- [ ] Permissões checadas:
useMyPermissionsfiltra corretamente - [ ]
enabledem queries dependentes de parâmetros que podem serundefined - [ ] Sem anti-padrão
useState([]) + useEffectpara fetch — usar React Query - [ ] Papéis sem tela (pedagogico, professor, marketing) permanecem bloqueados
- [ ]
requireRole()presente em operações sensíveis com papel correto - [ ] Componentes de login/role não expõem dados sensíveis no DOM
5. Auto-Reporte de Violação
Se durante a Fase 2 (ou durante a execução da Fase 3) o implementador identificar que o plano aprovado contém um problema — qualquer item do checklist falha, ou uma inconsistência é detectada — o procedimento é:
O que fazer
- Pausar imediatamente — não continuar a implementação
- Reportar o problema encontrado com:
- Qual item do checklist falhou
- Citação exata do trecho problemático
- Qual documento/regra está sendo violado
- Propor correção — apresentar a versão corrigida
- Aguardar nova aprovação — não implementar a correção sem aprovação
O que é proibido
- ❌ Corrigir silenciosamente e seguir em frente (mascara o problema)
- ❌ Ignorar para "não atrasar" (o atraso de reportar é menor que o risco)
- ❌ Assumir que a correção é óbvia e não precisa de aprovação
- ❌ Adicionar "melhorias" não planejadas junto com a correção
Exemplo de reporte correto
⚠️ Violação detectada na Fase 2:
O SQL do plano aprovado (Fase 1) para a tabela
coordenador_corescontém uma policy UPDATE semWITH CHECK:sqlCREATE POLICY "cores_update_self" ON public.coordenador_cores FOR UPDATE TO authenticated USING (usuario_id::text = auth.jwt()->>'sub');Isso viola o item 3.1 do checklist: "Toda policy de UPDATE tem USING E WITH CHECK" (ref: RLS_DESIGN_GUIDE.md §2).
Correção proposta:
sqlCREATE POLICY "cores_update_self" ON public.coordenador_cores FOR UPDATE TO authenticated USING (usuario_id::text = auth.jwt()->>'sub' AND escola_id::text = auth.jwt()->>'escola_id') WITH CHECK (usuario_id::text = auth.jwt()->>'sub' AND escola_id::text = auth.jwt()->>'escola_id');Aguardando aprovação para prosseguir.
6. Integração com @audit
Este documento e o Checklist de Auditoria (@audit) são complementares:
| Documento | Quando | Objetivo |
|---|---|---|
| MIGRATION_SAFETY_PROTOCOL (este) | Pré-entrega | Prevenir erros antes que entrem em produção |
| AUDIT_CHECKLIST (@audit) | Pós-entrega | Detectar erros que passaram pela prevenção |
Fluxo completo
Fase 1 (Planejamento) → Aprovação
↓
Fase 2 (Checklist + SQL) → Aprovação
↓
Fase 3 (Execução)
↓
@audit (Validação pós-entrega)A existência do protocolo pré-entrega não elimina a necessidade do @audit. Defesas em profundidade: se o protocolo falha em prevenir, o @audit detecta.
7. Incidente Original — Registro
O que aconteceu
- Interação N: Criado
RLS_DESIGN_GUIDE.mdcom regra obrigatória: "Toda policy INSERT/UPDATE tem WITH CHECK" - Interação N+1: Gerado SQL de migration para
coordenador_corescom policy UPDATE semWITH CHECK - Resultado: Policy entrou em produção permitindo potencialmente alteração de
usuario_id/escola_iddurante update
Causa raiz
- O plano de implementação (Fase 1 equivalente) já continha o SQL com erro
- O plano foi aprovado sem que o SQL fosse validado contra o guia recém-criado
- A execução (Fase 3 equivalente) seguiu o plano aprovado fielmente — o que normalmente é correto, mas neste caso propagou o erro
- Não havia protocolo de revalidação entre aprovação e execução
Correção aplicada
Migration 20260406232628: DROP + re-CREATE da policy com WITH CHECK.
Lição
O protocolo de 3 fases com checklist obrigatório na Fase 2 teria detectado o erro antes da aprovação do SQL. O auto-reporte de violação teria pausado a execução se o erro fosse detectado durante a Fase 3.
Referências Cruzadas
| Documento | Relação |
|---|---|
| RLS_DESIGN_GUIDE.md | Regras obrigatórias de RLS — fonte do checklist §3.1 |
| RLS_POLICIES.md | Inventário de policies existentes — referência de padrão |
| ADR_SERVICE_ROLE_USAGE.md | Quando usar service_role — fonte do checklist §3.2 |
| MIGRATION_GUIDELINES.md | Migrations multi-ambiente — fonte do checklist §3.3 |
| AUDIT_CHECKLIST.md | Checklist pós-entrega — complementar a este protocolo |
| NEW_EDGE_FUNCTION.md | Template de Edge Function — referência de estrutura |