VIBE IN PUBLIC_

RLS Supabase: por que "já existe" engana quem faz vibe coding

O agente respondeu que o RLS já existe na base, e isso não garante cobertura em cada tabela. O mínimo de segurança que danilixz cobra na live.

Na abertura do Day 01 do CavernaCODING, danilixz já estava com a mão na segurança do próprio projeto, antes de mexer em funcionalidade:

"Aqui estamos fazendo a [...] nossa página de segurança, certo? Botando os nossos RLS, proteger o nosso sistema aqui"

E a régua que ele estabelece na sequência não deixa margem:

"Precisa de ter RLS na tua base de dados, tá? Para sua segurança. É o mínimo, ok? É o mínimo, mínimo, mínimo."

Logo depois, o agente reportou o estado do projeto e devolveu uma resposta que soa como aprovação:

"base de dados [...] RLS já existe, ó."

A pergunta "tem RLS?" aceita uma resposta boa demais. Quem para de checar ali sai com uma sensação de cobertura que a configuração não sustenta.

RLS é recurso do Postgres, e o Supabase é onde a maior parte de quem faz vibe coding encontra esse recurso. O enquadramento de plataforma é meu: na live ele fala de RLS e de base de dados, sem citar plataforma nenhuma. O mesmo problema apareceu em supabase pricing.

O que "já existe" responde e o que fica de fora

A resposta do agente é verdadeira no nível em que foi feita. Existe RLS na base, e é uma resposta sobre o projeto inteiro, do tipo que fecha a conversa.

O que ela não diz é onde. Proteção de linha não funciona como chave geral do banco: ela é ligada tabela por tabela, e a regra que decide quem lê e quem escreve é escrita por tabela também. Uma base pode ter RLS ligado na maior parte das tabelas e desligado numa delas, e continuar respondendo "já existe" para qualquer pergunta feita no nível da base. O agente não mentiu, respondeu a pergunta que foi feita.

O buraco que ele descreve mora no campo, não na base

Mais tarde na mesma live, comentando uma ferramenta de análise de segurança que ele estava divulgando, danilixz descreve para quem assiste o cenário típico que uma varredura dessas encontra:

"de repente estás com algum campo na sua base de dados que não tem RLS, que é o que eu estou fazendo ali dentro do meu"

Essa frase é dirigida ao espectador e está no condicional, no sentido de "vai que você tem". Não é um achado sobre a base dele. A oração final diz justamente o contrário: ele está pondo RLS no projeto dele enquanto fala. E o veredito que ele dá para quem estiver na situação que descreveu:

"Você já tá ali na época dos Freston, que a sua segurança, infelizmente, é muito arcaica."

A distância entre as 2 falas é o que interessa aqui. O relatório respondeu no nível da base. O buraco que ele desenha mora um nível abaixo, na tabela e na coluna. Uma resposta afirmativa sobre a base não garante cobertura em cada tabela nem em cada campo dentro dela, e o pior caso é a tabela criada depois da última conferência, que entra desprotegida quando ninguém pede o contrário.

Por que o vibe coding produz tabela sem proteção

O agente cria estrutura quando precisa dela, e é aí que isso deixa de ser descuido e vira rotina. Você pede um sistema de comentários, e no meio do caminho aparece uma tabela de comentários. Você pede upload de foto de perfil, e aparece uma tabela de arquivos. Nenhum desses pedidos era sobre banco de dados, e a tarefa termina sem um relatório dizendo "criei uma tabela e ela está aberta". Foi o mesmo caminho de supabase self hosted.

A revisão que você faz depois é da funcionalidade. Você testa o comentário e vê que ele aparece na tela. Ninguém abre o painel do banco para conferir o que nasceu por baixo da tela que funcionou. Esse é o ponto cego de quem trabalha por conversa: o que apareceu no banco nunca entrou na conversa. É uma consequência direta de como o vibe coding entrega valor rápido, e o preço é a superfície do banco crescendo sem passar por revisão. Isso aparece também em anonimização de dados.

A camada que ele trata como piso

Da mesma live saiu um post sobre camadas de segurança, onde o argumento é somar proteções, cada uma encarecendo o trabalho de quem tenta entrar. RLS é a camada que danilixz trata como piso, e o "mínimo, mínimo, mínimo" está falando disso.

Somar camadas e ter camada cobrindo tudo são coisas diferentes. Uma camada com um furo continua contando como camada em uma lista de proteções, e é ali que a soma engana. A conversa sobre quantas camadas você tem só faz sentido depois que cada uma foi conferida no nível em que ela realmente atua.

Minha análise, não a dele

2 ressalvas que não estão na live e são responsabilidade minha.

A primeira: "está ligado" e "está correto" são perguntas diferentes. Uma tabela pode ter RLS ativo e uma regra permissiva demais, do tipo que libera leitura para qualquer usuário autenticado quando deveria liberar só para o dono da linha. Essa tabela protege muito menos do que parece, e aparece como protegida em qualquer conferência superficial, inclusive nas que o agente faz por você.

A segunda: a conferência que vale é por tabela e por operação, separando leitura, escrita, atualização e remoção. E é uma lista que envelhece. Ela vale para o estado do banco no dia em que foi feita, e cada migração posterior pode invalidá-la. Conferir uma vez e considerar o assunto resolvido é o mesmo erro de confiar no "já existe", só que com mais trabalho no caminho.

O que pedir ao agente hoje

Peça 2 listas, nessa ordem. A primeira: todas as tabelas da base com a proteção de linha desligada. A segunda: todas as tabelas com a proteção ligada, e ao lado de cada uma, qual regra ela aplica e para qual operação. A primeira lista mostra o buraco óbvio, a segunda mostra o buraco que parece cobertura.

Depois disso, adote uma regra de trabalho: tabela nova é tabela desprotegida até prova em contrário. Toda vez que uma tarefa terminar com estrutura nova no banco, a lista anterior venceu.

Vale assistir à live pelo tom com que ele trata o assunto. A régua dele é curta: RLS é o mínimo. O que o dia mostra, sem que ele diga com essas palavras, é que o mínimo precisa ser conferido no lugar onde ele pode faltar.