一键导入
db-rls-audit
Report tables with/without RLS and list all policies
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Report tables with/without RLS and list all policies
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Execute story development with selectable automation modes to accommodate different developer preferences, skill levels, and story complexity.
Set up a Kord-aligned documentation baseline (no legacy frameworks)
Create Next Story Task methodology and workflow
Validate Next Story Task methodology and workflow
advanced-elicitation methodology and workflow
No checklists needed - this task facilitates brainstorming sessions, validation is through user interaction methodology and workflow
| name | db-rls-audit |
| description | Report tables with/without RLS and list all policies |
| agent | architect |
| subtask | false |
Report tables with/without RLS and list all policies
Parameter:* mode (optional, default: interactive)
Purpose:* Definitive pass/fail criteria for task completion
Checklist:*
acceptance-criteria:
- [ ] Data persisted correctly; constraints respected; no orphaned data
type: acceptance-criterion
blocker: true
validation: |
Assert data persisted correctly; constraints respected; no orphaned data
error_message: "Acceptance criterion not met: Data persisted correctly; constraints respected; no orphaned data"
Strategy:* retry
Common Errors:*
Error:* Connection Failed
Error:* Query Syntax Error
Error:* Transaction Rollback
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 <<'SQL'
\echo '=== RLS Coverage Audit ==='
\echo ''
-- Tables with/without RLS
WITH t AS (
SELECT tablename, rowsecurity
FROM pg_tables WHERE schemaname='public'
)
SELECT
tablename,
CASE WHEN rowsecurity THEN '✓ ENABLED' ELSE '❌ DISABLED' END AS rls_status,
(SELECT json_agg(json_build_object(
'policy', policyname,
'cmd', cmd,
'roles', roles,
'qual', qual,
'with_check', with_check
))
FROM pg_policies p
WHERE p.tablename=t.tablename
AND p.schemaname='public') AS policies
FROM t
ORDER BY rowsecurity DESC, tablename;
\echo ''
\echo '=== Summary ==='
SELECT
COUNT(*) AS total_tables,
COUNT(*) FILTER (WHERE rowsecurity) AS rls_enabled,
COUNT(*) FILTER (WHERE NOT rowsecurity) AS rls_disabled
FROM pg_tables
WHERE schemaname='public';
\echo ''
\echo '=== Tables Without RLS (Security Risk) ==='
SELECT tablename
FROM pg_tables
WHERE schemaname='public'
AND rowsecurity = false
ORDER BY tablename;
\echo ''
\echo '=== Policy Coverage ==='
SELECT
t.tablename,
COUNT(p.policyname) AS policy_count,
ARRAY_AGG(p.cmd) AS commands_covered
FROM pg_tables t
LEFT JOIN pg_policies p ON p.tablename = t.tablename AND p.schemaname = 'public'
WHERE t.schemaname = 'public'
AND t.rowsecurity = true
GROUP BY t.tablename
ORDER BY policy_count, t.tablename;
SQL
✓ ENABLED - Table has RLS active (good)
❌ DISABLED - Table has no RLS (security risk)
Good coverage:*
FOR ALL (KISS approach), ORIncomplete coverage:*
No coverage:*
Problem*: RLS enabled but no policies defined
Impact*: Table is inaccessible to all users
Fix*: Add policies or disable RLS
-- Add KISS policy
ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;
CREATE POLICY "table_name_all"
ON table_name FOR ALL
TO authenticated
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
Or use: policy-apply table_name kiss
Problem*: Table accessible without restrictions
Impact*: Security vulnerability, data exposure
Fix*: Enable RLS and add policies
ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;
-- Then add policies
Problem*: RLS enabled with 1-3 policies (not covering all operations)
Impact*: Some operations may be blocked unexpectedly
Fix*: Either add missing policies or switch to KISS approach
Tables that should be publicly readable:
-- Public read, authenticated write
CREATE POLICY "public_read"
ON table_name FOR SELECT
TO anon, authenticated
USING (true);
CREATE POLICY "authenticated_write"
ON table_name FOR INSERT
TO authenticated
WITH CHECK (auth.uid() = user_id);
Use KISS policy:
policy-apply table_name kiss
Organization-scoped access:
CREATE POLICY "org_isolation"
ON table_name FOR ALL
TO authenticated
USING (org_id = (auth.jwt() ->> 'org_id')::uuid)
WITH CHECK (org_id = (auth.jwt() ->> 'org_id')::uuid);
After fixing issues, test with:
impersonate {user_id}
# Then run queries to verify access
✅ Enable RLS on all tables with sensitive data*
✅ Use KISS policies for simple owner-based access*
✅ Document why RLS is disabled if intentional*
✅ Test policies with real user contexts*
✅ Index columns used in RLS policies*
✅ Run this audit after every migration*
❌ Don't enable RLS without policies*
❌ Don't use service role to bypass RLS in app code*
❌ Don't forget to test negative cases*
Run RLS audit:
smoke-test → rls-auditrls-auditrls-auditrls-audit