Pular para o conteúdo
Beneverso
Equipe

Guia

O que está exposto aqui

A área da equipe não tem senha, e o banco também não — 15 das 16 tabelas são legíveis por fora do site. O que já foi fechado, o que depende de decisão, o caminho barato que ninguém tinha visto, e a régua do que NÃO escrever aqui enquanto isso.

SistemaConsulta obrigatória

Original no vault: Beneverso_Vault/99_⚙️_Sistema/Exposicao_da_Area_da_Equipe.md

Isto não é alarme, é inventário. Escrito em 02/09/2026 para que a decisão que falta seja tomada com o número na mão, e não no susto.

A frase curta

equipe.beneverso.com.br não tem senha, e o banco por trás dele também não. Qualquer pessoa que descubra o endereço lê tudo — e, pior, quem souber ler o JavaScript da página pública consegue ler o banco inteiro sem nem abrir a área da equipe.

O que exatamente está aberto

1. A área da equipe, sem senha

O Basic Auth do Traefik saiu em 13/08/2026, a pedido do Felipe, porque travava o uso no celular. As duas linhas que o ligavam de volta continuam escritas no docker-compose.yml, comentadas.

Alcance: quem tiver o link. Não está indexado no Google (o robots.txt e a vedação do proxy cuidam do host público), mas link se compartilha.

2. O banco, direto — sem passar pelo site

Esta é a parte que quase ninguém espera, e é a mais séria.

15 das 16 tabelas têm leitura liberada para o papel public (remedido em 02/09/2026 direto em pg_policies; só membros_equipe está fechada). A chave anon do Supabase, que é necessária para o site funcionar, vai embutida no JavaScript entregue ao navegador — inclusive em beneverso.com.br, que é o site público. Com essa chave e o endereço do projeto, dá para consultar as tabelas por REST, de qualquer lugar, sem abrir nossa área.

O efeito prático: as vedações que o site faz por campo protegem só o HTML. Por exemplo, a /pautas apaga como_aborda e limites antes de mandar a página ao público — e os dois campos continuam legíveis por consulta direta.

O que fica ao alcance de quem fizer isso:

TabelaO que tem dentro
adversarioso dossiê inteiro: polemicas, como_mencionar, atencao
paginas_colabcom quem falamos, o que cada página aceita, quando pedimos
agenda_postso que vai ao ar, quando, e as observações de aprovação
pautascomo_aborda e limites — a nota interna de cada bandeira
timeline_eventssugestao_editorial e status
citacoesuso, verificar, link_confirmacao
sugestoes, metricas_*, aprovacoeso resto do trabalho interno

Só membros_equipe está fechada de verdade.

3. Os MP4 da série, em bucket público

Os cortes da série do Senado estão no Supabase Storage num bucket público, desde 28/08 — inclusive as sete peças anônimas. A URL é adivinhável a partir do nome do episódio.

⚠️ E a /serie promete o contrário, por escrito: "não reproduz vídeo, não hospeda nada e não aponta para lugar público". A promessa está errada e a /videos toca esses arquivos por essa URL.

O que JÁ foi fechado (02/09/2026)

A escrita pública em sugestoes. A tabela aceitava INSERT e UPDATE do papel public: qualquer pessoa na internet podia criar e alterar sugestões sem nunca ter visitado a nossa área. As duas políticas foram derrubadas.

Não quebrou nada, e o motivo está medido: todas as escritas do site passam por server action com a chave service_role, que ignora RLS. A leitura continua aberta, senão a /videos para de funcionar.

O que NÃO dá para consertar sem uma decisão

Fechar a leitura das 15 tabelas derruba o site inteiro — se nada mais mudar. Não há login: o site lê tudo com a chave anon, e é ela que as políticas liberam. Trocar using (true) por using (is_membro()) — que é a função certa, e ela já existe no banco, sem nenhuma política a usando — apagaria todas as telas.

Ou seja: é decisão do Felipe, não conserto de migração. As opções são três:

CaminhoCustoO que resolve
Voltar o Basic Auth — as duas linhas já estão no docker-compose.ymlminutosfecha a área da equipe. NÃO fecha o banco: a chave anon continua no bundle público
Login de verdade (Supabase Auth + is_membro() nas políticas)horas, e mexe em tudofecha os dois. É a solução completa
Aceitar e conviverzeroassumir que o material interno é semi-público, e não escrever nada que não possa vazar

⚠️ Se algum dia o login for ligado, há uma armadilha esperando: 9 tabelas dão ALL (inclusive DELETE) para authenticated com using (true). Hoje isso é inofensivo porque não existe um único usuário. No dia em que existir, qualquer conta autenticada apaga a linha do tempo inteira. Prender essas 9 a is_membro() antes de ligar login não é opcional.

O quarto caminho — descoberto em 02/09/2026

A tabela acima dá três opções e a completa custa "horas, e mexe em tudo". Há uma quarta, bem mais barata, e ela existe por um motivo que ninguém tinha medido: nenhuma tela deste site lê o banco pelo navegador.

Medição: os sete componentes "use client" que importam de lib/supabase.ts — adversários, calendário, citações, pautas, produção, projetos e linha do tempo — não chamam supabase. uma única vez. Todos recebem os dados já prontos, por props, do componente de servidor. Os dois casos que a busca aponta são comentários citando o nome do arquivo.

Se toda leitura é no servidor, o navegador não precisa de chave nenhuma. Daí:

  1. Trocar a chave que lib/supabase.ts usa: de NEXT_PUBLIC_SUPABASE_ANON_KEY para uma variável sem o prefixo NEXT_PUBLIC_ (que é o que faz o Next embutir o valor no pacote do navegador).
  2. Rotacionar a chave anon no painel do Supabase. Sem isto, nada muda de fato: a chave antiga já está publicada e continua valendo para sempre.
  3. Fechar as políticas de SELECT para public.

O site continua funcionando porque nenhuma leitura passa pelo navegador. Não precisa de login, não precisa de is_membro(), não mexe em tela nenhuma.

🚨 A armadilha deste caminho — leia antes de tentar

Três componentes de cliente importam CONSTANTES de lib/supabase.ts, e não só tipos:

ArquivoO que importa
app/calendario/calendario-client.tsxMESES
app/pautas/pautas-client.tsxPRIORIDADE
app/timeline/timeline-client.tsxCATEGORIAS

Importar valor arrasta o módulo inteiro para o pacote do navegador — e junto vai a chave que estiver dentro dele. É exatamente assim que a chave anon foi parar lá. Os outros quatro usam import type, que o compilador apaga e não arrasta nada.

Se alguém trocar a chave por uma de servidor sem resolver estes três antes, a chave de SERVIÇO vai para o navegador — e essa ignora RLS e escreve. Seria trocar um problema de leitura por um de escrita total, que é ordens de grandeza pior.

O conserto dos três é passar a constante como prop do componente de servidor, como já é feito com os dados. Depois disso, confira no pacote antes de publicar:

grep -r "SUPABASE" .next/static/chunks/ | head

Tem que sair vazio.

A régua enquanto a decisão não vem

Foi ela que guiou as correções de 02/09, e vale para quem escrever qualquer coisa nova:

  1. Preço e valor não entram. A tabela da LUZ saiu por isso: a Julia declarou o PDF não público, e a nossa área não tem senha.
  2. Nada sobre terceiro que não está no grupo. Especialmente posição política. Saiu a linha sobre a simpatia do Marcus di Flora.
  3. Nada que avalie pessoa. Cansaço, humor, capacidade. Fato operacional ("desliga às 21h30") entra; diagnóstico não.
  4. Antes de escrever, o teste: isto pode ser lido por alguém de fora amanhã? Se a resposta for não, não escreva — conversa.

Notas

Transcrição do vault. Mudou o arquivo lá? Atualize lib/guias.ts — o vault é a fonte, esta página é o espelho.