UNPKG

@rip-user/rls-debugger-mcp

Version:

AI-powered MCP server for debugging Supabase Row Level Security policies with Claude structured outputs

115 lines 3.55 kB
/** * SQL query to fetch all RLS policies from PostgreSQL system tables */ export const GET_ALL_RLS_POLICIES = ` SELECT nsp.nspname AS schemaname, rel.relname AS tablename, pol.polname AS policyname, CASE pol.polpermissive WHEN true THEN 'PERMISSIVE' WHEN false THEN 'RESTRICTIVE' END AS polpermissive, CASE WHEN cardinality(pol.polroles) > 0 THEN pg_get_userbyid(pol.polroles[1]) ELSE 'public' END AS policyrole, CASE pol.polcmd WHEN '*' THEN 'ALL' WHEN 'r' THEN 'SELECT' WHEN 'a' THEN 'INSERT' WHEN 'w' THEN 'UPDATE' WHEN 'd' THEN 'DELETE' END AS polcmd, pg_get_expr(pol.polqual, pol.polrelid) AS policyqual, pg_get_expr(pol.polwithcheck, pol.polrelid) AS policywithcheck FROM pg_catalog.pg_policy pol JOIN pg_catalog.pg_class rel ON pol.polrelid = rel.oid JOIN pg_catalog.pg_namespace nsp ON rel.relnamespace = nsp.oid WHERE nsp.nspname = 'public' ORDER BY rel.relname, pol.polname; `; /** * SQL query to get policies for a specific table */ export function getTablePoliciesQuery(tableName) { return ` SELECT nsp.nspname AS schemaname, rel.relname AS tablename, pol.polname AS policyname, CASE pol.polpermissive WHEN true THEN 'PERMISSIVE' WHEN false THEN 'RESTRICTIVE' END AS polpermissive, CASE WHEN cardinality(pol.polroles) > 0 THEN pg_get_userbyid(pol.polroles[1]) ELSE 'public' END AS policyrole, CASE pol.polcmd WHEN '*' THEN 'ALL' WHEN 'r' THEN 'SELECT' WHEN 'a' THEN 'INSERT' WHEN 'w' THEN 'UPDATE' WHEN 'd' THEN 'DELETE' END AS polcmd, pg_get_expr(pol.polqual, pol.polrelid) AS policyqual, pg_get_expr(pol.polwithcheck, pol.polrelid) AS policywithcheck FROM pg_catalog.pg_policy pol JOIN pg_catalog.pg_class rel ON pol.polrelid = rel.oid JOIN pg_catalog.pg_namespace nsp ON rel.relnamespace = nsp.oid WHERE nsp.nspname = 'public' AND rel.relname = '${tableName}' ORDER BY pol.polname; `; } /** * Fetch all RLS policies from Supabase */ export async function fetchAllPolicies(supabase) { // Use raw SQL query directly const { data, error } = await supabase.rpc('exec_sql', { query: GET_ALL_RLS_POLICIES }); if (error) { // Try alternative approach using information_schema const altQuery = ` SELECT schemaname, tablename, policyname FROM pg_policies WHERE schemaname = 'public'; `; const { data: altData, error: altError } = await supabase.rpc('exec_sql', { query: altQuery }); if (altError) { throw new Error(`Failed to fetch RLS policies: ${error.message || altError.message}`); } return altData || []; } return data || []; } /** * Fetch policies for a specific table */ export async function fetchTablePolicies(supabase, tableName) { const allPolicies = await fetchAllPolicies(supabase); return allPolicies.filter(p => p.tablename === tableName); } /** * Check if a table has RLS enabled */ export async function isRLSEnabled(supabase, tableName) { const query = ` SELECT relrowsecurity FROM pg_class WHERE relname = '${tableName}'; `; const { data, error } = await supabase.rpc('exec_sql', { query }); if (error || !data || data.length === 0) { return false; } return data[0].relrowsecurity === true; } //# sourceMappingURL=rls-queries.js.map