fix(security): Etapa 3 (C2) — fecha vazamento de cost_price ao público (anon)#530
Conversation
…o (anon) Causa-raiz: a policy `products_public_read` concedia SELECT USING(true) a `anon` (além de `authenticated`), e `anon` tinha grant de coluna em cost_price/ suggested_price/supplier_reference/ipi_rate. Assim qualquer cliente com a anon key lia a base `products` direto (6.123 produtos, 6.118 com custo) contornando a view mascarada `v_products_public`. Correção: remove `anon` da policy de SELECT (catálogo público continua via `v_products_public`, security_invoker=false/owner — inalterado) e revoga grants de escrita do `anon` (já bloqueados por RLS is_org_owner_or_admin; higiene). As 8 views derivadas (v_products_complete, vw_products_packaging_info, etc.) são security_invoker=on → herdam a RLS da base e deixam de vazar em cascata (validado). `suppliers` já era seguro p/ anon (policy só authenticated) — sem mudança. Aplicado em produção via Supabase MCP (projeto doufsxqlfjyuvxuezpln); este arquivo é para rastreio em git. Validação: >340 asserções em produção (revertidas), 0 violações.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 20 minutes and 39 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Updates to Preview Branch (fix/etapa3-c2-products-cost-leak) ↗︎
Tasks are run on every commit but only new migration files are pushed.
❌ Branch Error • Sat, 30 May 2026 17:21:31 UTC View logs for this Workflow Run ↗︎. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Rebase limpo sobre main atual (inclui #526 telemetria, #527 RLS, #530). - bridge.ts: WRITE_OPERATIONS + isWriteOperation() + WriteUnavailableError; escrita com bridge OFF / kill-switch / CORS agora LANCA em vez de retornar vazio. Leitura mantem vazio silencioso. Telemetria do #526 preservada (recordBridgeCall/recordKillSwitchHit) — recordCall roda ANTES do throw. - index.ts: exporta isWriteOperation + WriteUnavailableError. Apenas estes 2 arquivos (rest-native writes + testes ficam no #525).
…A) (#531) * PR#1 (C): escrita falha LOUD em vez de no-op silencioso Rebase limpo sobre main atual (inclui #526 telemetria, #527 RLS, #530). - bridge.ts: WRITE_OPERATIONS + isWriteOperation() + WriteUnavailableError; escrita com bridge OFF / kill-switch / CORS agora LANCA em vez de retornar vazio. Leitura mantem vazio silencioso. Telemetria do #526 preservada (recordBridgeCall/recordKillSwitchHit) — recordCall roda ANTES do throw. - index.ts: exporta isWriteOperation + WriteUnavailableError. Apenas estes 2 arquivos (rest-native writes + testes ficam no #525). * test(A): cobertura do caminho de escrita REST nativo (Plano A) — 12 testes das 6 guardas + remap + LOUD * feat(A): escrita REST nativo (Plano A) em rest-native.ts — 6 guardas, remap EN→PT, fail LOUD; preserva telemetria #526 * style(A): normaliza separadores de comentário em rest-native.ts (byte-exato ao artefato validado) * style(A): separadores uniformes em rest-native.ts (determinístico, byte-exato 32a30c5c) * feat(A)+test: wire write fast-path em bridge.ts (tryExecuteRestNativeWrite) + corrige bridge.test.ts (evita REST path no mock) — 23/23 verde
Etapa 3 — Correção C2 (cost leak)
DB já corrigido em produção via Supabase MCP (projeto
doufsxqlfjyuvxuezpln). Este PR adiciona o.sqlemsupabase/migrations/apenas para rastreio/versionamento — o estado do banco já reflete a mudança.Vazamento (confirmado e explorável)
A policy
products_public_readeraSELECT USING (true)para{anon, authenticated}, eanontinha grant de coluna em campos sensíveis. Qualquer pessoa com a anon key (que vai no bundle do front) lia o custo de todos os produtos viaGET /rest/v1/products?select=cost_price,supplier_reference,ipi_rate, contornando a view mascaradav_products_public.cost_priceexposto aoanon.Correção
v_products_public(security_invoker=false, roda como dono, mascara as 16 colunas sensíveis) — catálogo inalterado.v_products_complete,v_products_kit_builder,vw_packagings_catalog,vw_products_packaging_info,vw_products_commercial_packing, ...) sãosecurity_invoker=on→ herdam a RLS da base e deixam de vazar custo em cascata (validado: 0 não-nulos paraanon).suppliersjá era seguro p/anon(policy de SELECT sóauthenticated) — sem mudança.SELECTgrant doanonpara que leituras residuais (ex.:mockup .select('id')) degradem para vazio via RLS em vez depermission denied.Validação (sem mutar produção)
>340 asserções executadas em produção dentro de transações revertidas (
RAISE EXCEPTION), 0 violações. Sentinelas pós-aplicação (estado real):anonbaseproductsanonv_products_complete(cost)authenticatedbaseproductsv_products_publicanonINSERT/UPDATE/DELETEanonSELECT-grant / SELECT na viewproducts_public_readroles{authenticated}Residuais (fora do escopo C2 — passos próprios)
authenticated(logados) ainda leemcost_priceda base (USING true). Se houver clientes logados não-admin, exige separar a leitura de custo do admin (RPC/edge comservice_role).cost_priceNULL com bridge OFF) — possível bug de UX pré-existente.system_kill_switchesé legível poranon(exposição menor de config) — avaliar à parte.🤖 Gerado durante a sessão de remediação do subsistema
invokeExternalDb(Etapa 3/10).Summary by cubic
Closes the
cost_priceleak by removing public (anon) access to the baseproductstable while keeping the public catalog unchanged via the maskedv_products_publicview. Adds a Supabase migration for tracking; production DB was already updated.Bug Fixes
products_public_readtoauthenticatedonly.INSERT,UPDATE,DELETE,TRUNCATEonpublic.productsfromanon.v_products_public(masked).Migration
supabase/migrations/20260530173000_etapa3_c2_products_cost_leak_anon.sqlfor versioning (no runtime changes required).Written for commit e5e255c. Summary will update on new commits.