Skip to content

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ívelEscopoJustificativaProtocolo
🔴 CríticoMigrations SQL, policies RLS, Edge Functions, supabase-client.ts, _shared/*.tsEntram 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
🟡 AltoHooks de auth (useAuth*), lógica de permissões frontend, supabase-client.ts (leitura), componentes de login/roleControlam 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
🟢 NormalComponentes UI, helpers puros, estilos, documentaçãoNã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 apenas USING)
  • [ ] Toda policy de UPDATE tem USING E WITH CHECK
  • [ ] Policies separadas por operação: SELECT, INSERT, UPDATE, DELETE — nunca FOR ALL
  • [ ] Policies direcionadas a TO authenticatednunca TO public
  • [ ] Cast ::text em colunas UUID comparadas com JWT (escola_id::text = auth.jwt()->>'escola_id')
  • [ ] Filtro escola_id presente 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 de supabase-client.ts
  • [ ] Se createSupabaseSystem() é usado em contexto novo → justificativa documentada no ADR

3.3 Migrations — Resiliência Multi-Ambiente

Fonte: MIGRATION_GUIDELINES.md

  • [ ] WHERE EXISTS em todo INSERT com UUID literal referenciando FK
  • [ ] ON CONFLICT para idempotência (re-execução segura)
  • [ ] Migration funciona em banco vazio (staging sem dados de produção)
  • [ ] Sem INSERT INTO ... VALUES com FK hardcoded — usar SELECT ... 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 de data)
  • [ ] getCorsHeaders(req) em todas as respostas (incluindo catch blocks)
  • [ ] registrarLog() em todo Create/Update/Delete com req como 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: useMyPermissions filtra corretamente
  • [ ] enabled em queries dependentes de parâmetros que podem ser undefined
  • [ ] Sem anti-padrão useState([]) + useEffect para 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

  1. Pausar imediatamente — não continuar a implementação
  2. Reportar o problema encontrado com:
    • Qual item do checklist falhou
    • Citação exata do trecho problemático
    • Qual documento/regra está sendo violado
  3. Propor correção — apresentar a versão corrigida
  4. 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_cores contém uma policy UPDATE sem WITH CHECK:

sql
CREATE 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:

sql
CREATE 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:

DocumentoQuandoObjetivo
MIGRATION_SAFETY_PROTOCOL (este)Pré-entregaPrevenir erros antes que entrem em produção
AUDIT_CHECKLIST (@audit)Pós-entregaDetectar 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.md com regra obrigatória: "Toda policy INSERT/UPDATE tem WITH CHECK"
  • Interação N+1: Gerado SQL de migration para coordenador_cores com policy UPDATE sem WITH CHECK
  • Resultado: Policy entrou em produção permitindo potencialmente alteração de usuario_id/escola_id durante update

Causa raiz

  1. O plano de implementação (Fase 1 equivalente) já continha o SQL com erro
  2. O plano foi aprovado sem que o SQL fosse validado contra o guia recém-criado
  3. A execução (Fase 3 equivalente) seguiu o plano aprovado fielmente — o que normalmente é correto, mas neste caso propagou o erro
  4. 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

DocumentoRelação
RLS_DESIGN_GUIDE.mdRegras obrigatórias de RLS — fonte do checklist §3.1
RLS_POLICIES.mdInventário de policies existentes — referência de padrão
ADR_SERVICE_ROLE_USAGE.mdQuando usar service_role — fonte do checklist §3.2
MIGRATION_GUIDELINES.mdMigrations multi-ambiente — fonte do checklist §3.3
AUDIT_CHECKLIST.mdChecklist pós-entrega — complementar a este protocolo
NEW_EDGE_FUNCTION.mdTemplate de Edge Function — referência de estrutura