A verificação de FORCE RLS lia pg_class sem filtrar relkind e pegava índices como spreadsheet_adapter_settings_pkey, que nunca têm RLS. Agora lê só tabelas (r/p) do schema public e compara com a lista exata das dez tabelas protegidas pela 0003_rls.sql. O teste de auditoria reutilizava $1 como uuid (workspace_id) e text (resource_id), e o Postgres recusava antes de testar a permissão. Cada coluna tem seu parâmetro e o teste exige o código 42501 em update e delete, confirmando que o registro continua intacto. Regressão do catálogo de RLS também roda na suíte padrão (PGlite). Nenhuma migration, política ou permissão foi alterada. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
36 lines
1.2 KiB
TypeScript
36 lines
1.2 KiB
TypeScript
import type { Query } from "@/infra/db/types";
|
|
|
|
/** Tabelas que as migrations colocam sob RLS + FORCE RLS (migrations/0003_rls.sql). */
|
|
export const RLS_TABLES = [
|
|
"audit_log",
|
|
"profiles",
|
|
"spreadsheet_adapter_settings",
|
|
"spreadsheet_job_mappings",
|
|
"spreadsheet_job_sources",
|
|
"spreadsheet_jobs",
|
|
"spreadsheet_models",
|
|
"workspace_members",
|
|
"workspace_module_flags",
|
|
"workspaces",
|
|
] as const;
|
|
|
|
export type RlsRow = { relname: string; relkind: string; relrowsecurity: boolean; relforcerowsecurity: boolean };
|
|
|
|
/**
|
|
* Só tabelas comuns e particionadas (`relkind` r/p) do schema public. Sem esse
|
|
* filtro, `like 'spreadsheet%'` também traz índices (`*_pkey`, relkind `i`),
|
|
* que nunca têm RLS e fazem a verificação falhar por engano.
|
|
*/
|
|
export async function readRlsCatalog(query: Query): Promise<RlsRow[]> {
|
|
return query.query<RlsRow>(
|
|
`select c.relname, c.relkind::text as relkind, c.relrowsecurity, c.relforcerowsecurity
|
|
from pg_class c
|
|
join pg_namespace n on n.oid = c.relnamespace
|
|
where n.nspname = 'public'
|
|
and c.relkind in ('r', 'p')
|
|
and (c.relname like 'spreadsheet%' or c.relname = any($1::text[]))
|
|
order by c.relname`,
|
|
[[...RLS_TABLES]],
|
|
);
|
|
}
|