Skip to content

PR#2 (A): escrita via PostgREST nativo + RLS (6 guardas)#525

Merged
adm01-debug merged 2 commits into
fix/c-loud-writesfrom
feat/a-rest-native-writes
May 30, 2026
Merged

PR#2 (A): escrita via PostgREST nativo + RLS (6 guardas)#525
adm01-debug merged 2 commits into
fix/c-loud-writesfrom
feat/a-rest-native-writes

Conversation

@adm01-debug
Copy link
Copy Markdown
Owner

@adm01-debug adm01-debug commented May 30, 2026

Empilha sobre #524 (PR#1/C). Base = fix/c-loud-writes para o diff mostrar só o incremento do Plano A.

O que faz

Reintroduz o caminho de escrita real, agora via PostgREST nativo + RLS (independente da bridge/kill-switch), substituindo o no-op silencioso que o PR#1 passou a sinalizar com erro.

rest-native.ts ganha insert/update/delete/upsert/batch_insert com as 6 guardas:

  • A1 sessão autenticada → delegada ao RLS (supabase-js anexa o JWT).
  • A2 update/delete SEM filtro/id → proibido (proteção contra mutação em massa).
  • A3 escrita SEMPRE na tabela BASE (WRITE_TABLE_ALIASES), nunca na view v_*_public read-only — não reusa o TABLE_ALIASES de leitura.
  • A4 .select() de volta; insert OK com select-back vazio (RLS de SELECT) ainda é sucesso.
  • A5 remap EN→PT no payload e filtros (COLUMN_ALIASES_BY_TABLE), evita 400.
  • Sem retry em escrita (evita insert/upsert duplicado); erro real PROPAGA LOUD.

bridge.ts: WRITE fast-path em invokeExternalDb (após o READ fast-path) + invokeExternalDbDelete roteando REST nativo primeiro. Whitelist de escrita = as 13 tabelas base dos 12 hooks de admin.

Validação

  • tsc --noEmit: 0 erros no source.
  • vitest: rest-native-write.test.ts (12 casos cobrindo as 6 guardas + elegibilidade + propagação LOUD + batch remap) + bridge.test.ts + __tests__/ = 32/32 verdes.
  • bridge.test.ts: 3 testes de contrato da bridge repassados para tabela não-whitelisted (audit_logs, onde a bridge ainda é o caminho); 2 falhas pré-existentes corrigidas de brinde.

Dependência

Para a escrita persistir, precisa do PR#3 (RLS WITH CHECK por role). Sem o PR#3, a escrita falha LOUD (honesto) — nunca silenciosa. Mergear #3 junto/antes.

Série: #1 (C) → #2 (A núcleo)#3 (A RLS) → #4 (aposentar bridge).


Summary by cubic

Habilita escrita nativa via PostgREST com RLS (Plano A), independente da bridge/kill-switch, substituindo o no‑op por operações reais com erro “loud”. Adiciona fast‑path de escrita e guardas para segurança e compatibilidade.

  • New Features

    • Suporte a insert/update/delete/upsert/batch_insert nas 13 tabelas base whitelisted; autorização feita por RLS.
    • Protege contra mutação em massa (bloqueia update/delete sem filtro/id) e sempre escreve na tabela base via WRITE_TABLE_ALIASES (nunca em v_*_public).
    • Retorna .select() após a escrita; insert com select-back vazio ainda é sucesso. Remapeia EN→PT no payload e filtros via COLUMN_ALIASES_BY_TABLE; sem retry; erros propagam “loud”.
    • invokeExternalDb e invokeExternalDbDelete tentam o caminho nativo primeiro; bridge segue para tabelas fora da whitelist. Testes cobrindo elegibilidade, guardas e batch; bridge.test.ts ajustado para audit_logs.
  • Migration

Written for commit 8f8205f. Summary will update on new commits.

Review in cubic

Estende o rest-native para insert/update/delete/upsert/batch_insert, com as 6
guardas do Plano A:
- A1 sessão autenticada → delegada ao RLS (supabase-js anexa o JWT).
- A2 update/delete SEM filtro/id → proibido (proteção contra mutação em massa).
- A3 escrita SEMPRE na tabela BASE (WRITE_TABLE_ALIASES), nunca na view v_*_public
  read-only — NÃO reusa TABLE_ALIASES de leitura.
- A4 `.select()` de volta; insert OK com select-back vazio (RLS de SELECT) ainda é sucesso.
- A5 remap EN→PT no payload e filtros (COLUMN_ALIASES_BY_TABLE), evita 400.
- Sem retry em escrita (evita insert/upsert duplicado); erro real PROPAGA LOUD.

Novos exports: isRestNativeWriteEligible, executeRestNativeWrite, tryExecuteRestNativeWrite.
Whitelist de escrita = as 13 tabelas base usadas pelos 12 hooks de admin.

Testes: src/lib/external-db/__tests__/rest-native-write.test.ts — 12 casos cobrindo
todas as 6 guardas + elegibilidade + propagação LOUD + batch array remap.
…Db + delete

- invokeExternalDb: novo WRITE fast-path (isRestNativeWriteEligible →
  tryExecuteRestNativeWrite) logo após o READ fast-path. Sucesso retorna; erro de
  RLS/validação PROPAGA LOUD; tabela/op não-elegível cai no WriteUnavailableError.
- invokeExternalDbDelete: roteia REST nativo (RLS) primeiro; fallback bridge; senão LOUD.
- bridge.test.ts: os 3 testes de contrato da bridge passam a usar tabela
  NÃO-whitelisted (audit_logs) — onde a bridge continua sendo o caminho — preservando
  a intenção (o caminho REST nativo é coberto por rest-native-write.test.ts). Também
  corrige 2 falhas pré-existentes no arquivo (string de acento + chave auth duplicada).

tsc --noEmit limpo; vitest: bridge.test.ts + __tests__/ = 32/32 verdes.
Depende do PR#3 (RLS WITH CHECK) para a escrita efetivamente persistir; sem ele,
a escrita falha LOUD (honesto), nunca silenciosa.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
we-dream-big Ready Ready Preview, Comment May 30, 2026 4:39pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • main

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 671803da-03f6-421b-9399-f0dcdc5ef091

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/a-rest-native-writes

Comment @coderabbitai help to get the list of available commands and usage tips.

@supabase
Copy link
Copy Markdown

supabase Bot commented May 30, 2026

This pull request has been ignored for the connected project doufsxqlfjyuvxuezpln because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

adm01-debug added a commit that referenced this pull request May 30, 2026
…destrutivo)

O passo destrutivo do PR#4 (deletar a Edge Function + limpar kill-switch) é GATED em
"A verde" (merge de #525/#527 + soak em prod) — A ainda está em draft. Em vez de
disparar a remoção fora de ordem (que quebraria o fallback do main e o rollback do
PR#2), este PR entrega o runbook com a ordem correta e duas armadilhas documentadas:

1. fail-open do kill-switch: DELETE da linha RELIGA a bridge (enabled=true) — nunca
   deletar a linha enquanto o cliente ainda a lê.
2. main ainda usa a bridge como fallback até o PR#2 mergear — não deletar a função antes.

Inclui ordem de execução, critérios de soak e rollback. Nenhuma alteração de código
ou DDL; nada destrutivo é executado aqui.
@adm01-debug adm01-debug marked this pull request as ready for review May 30, 2026 16:53
Copilot AI review requested due to automatic review settings May 30, 2026 16:53
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@adm01-debug adm01-debug merged commit 7b519c2 into fix/c-loud-writes May 30, 2026
11 of 13 checks passed
@adm01-debug adm01-debug deleted the feat/a-rest-native-writes branch May 30, 2026 16:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

adm01-debug added a commit that referenced this pull request May 30, 2026
…atual (#524)

Rebase sobre o main atual (inclui #526, telemetria recordBridgeCall) para
eliminar o conflito do #524. Branch recriada a partir do main + este \u00fanico commit.

- WRITE_OPERATIONS + isWriteOperation + WriteUnavailableError (novos).\n- invokeExternalDb: escrita com bridge OFF/kill-switch/CORS agora THROW
  (ap\u00f3s reportSilentEmpty + recordCall + recordKillSwitchHit do #526);
  leitura segue retornando vazio.\n- invokeExternalDbDelete: THROW em vez de no-op silencioso.\n- index.ts: exporta WriteUnavailableError e isWriteOperation.

Toda a telemetria do #526 preservada (7x recordCall). tsc --noEmit limpo.
Escopo do PR#1 = apenas bridge.ts + index.ts (rest-native writes + testes ficam no PR#2/#525).
adm01-debug added a commit that referenced this pull request May 30, 2026
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).
adm01-debug added a commit that referenced this pull request May 30, 2026
…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
adm01-debug added a commit that referenced this pull request May 31, 2026
…destrutivo) (#528)

O passo destrutivo do PR#4 (deletar a Edge Function + limpar kill-switch) é GATED em
"A verde" (merge de #525/#527 + soak em prod) — A ainda está em draft. Em vez de
disparar a remoção fora de ordem (que quebraria o fallback do main e o rollback do
PR#2), este PR entrega o runbook com a ordem correta e duas armadilhas documentadas:

1. fail-open do kill-switch: DELETE da linha RELIGA a bridge (enabled=true) — nunca
   deletar a linha enquanto o cliente ainda a lê.
2. main ainda usa a bridge como fallback até o PR#2 mergear — não deletar a função antes.

Inclui ordem de execução, critérios de soak e rollback. Nenhuma alteração de código
ou DDL; nada destrutivo é executado aqui.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants