warn-rls-policy-completeness
RLS policies should cover all operations (SELECT, INSERT, UPDATE, DELETE) to avoid silent access denial.
- operation
- Privileges and RLS
- lock taken
- no table lock
- remediation
- Manual rewrite
- category
- Privileges & RLS
- Can lose data
What triggers it
The AT_EnableRowSecurity subcommand of ALTER TABLE, when the migration's own CREATE POLICY statements for that table (found by scanning originalSql for the table name) cover some but not all of SELECT/INSERT/UPDATE/DELETE, and none of them uses FOR ALL.
What does not
Non-AlterTableStmt statements, and ALTER TABLE statements that don't enable RLS. A policy anywhere in the migration written FOR ALL clears the whole table. If the migration enables RLS but adds no policies at all, this rule stays quiet on purpose — that case is MP057's job.
Where it applies
Applies to every PostgreSQL version MigrationPilot targets. It works on the SQL text alone — no database connection needed.
The lock, and what it blocks
None — the risk here isn't a lock, it's that PostgreSQL denies uncovered operations silently instead of raising an error.
Why it matters
When RLS is enabled, any operation without a policy is silently denied — queries return zero rows instead of raising an error. Always create policies for all operations or use a FOR ALL policy.
Unsafe, and safe
Flagged
ALTER TABLE posts ENABLE ROW LEVEL SECURITY; CREATE POLICY posts_select ON posts FOR SELECT USING (true); -- Missing INSERT, UPDATE, DELETE policies!
Safe alternative
ALTER TABLE posts ENABLE ROW LEVEL SECURITY; CREATE POLICY posts_all ON posts FOR ALL USING (true);
What it assumes
Assumes every policy for the table lives in this same migration file — a policy created earlier, in a different file, won't be seen, so a table that's actually fully covered can still get flagged. Coverage detection is also a text match on create policy plus the table name, not a structural link between policy and table, so it can misjudge coverage in an unusual layout.
What the CLI prints
⚠ [MP079] WARNING (line 1) RLS on "posts" has policies for select but missing insert, update, delete. Uncovered operations will be silently denied. Safe alternative: CREATE POLICY posts_insert ON posts FOR INSERT USING (true); CREATE POLICY posts_update ON posts FOR UPDATE USING (true); CREATE POLICY posts_delete ON posts FOR DELETE USING (true); Why: When RLS is enabled, any operation without a policy is silently denied: queries return zero rows instead of raising an error. If you create a SELECT policy but forget INSERT, all inserts silently fail (or error on PG 15+). Always create policies for all operations or use a permissive ALL policy as a baseline. Docs: https://migrationpilot.dev/rules/mp079
Generated by running the CLI's own formatter over the flagged example above, so it is the text the tool actually produces. A real run also reports the other rules that fire on the same statement; those blocks are left out here.
Turning it off
For one statement, put a comment on the line before it:
-- migrationpilot-disable MP079 ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
For the whole project, in .migrationpilotrc.yml — by name or by id:
rules:
MP079: false
# or keep it, and downgrade it
rules:
MP079:
severity: warningTry it
Open this rule's flagged example in the playground. It runs in your browser — edit it and watch the finding appear and disappear.
Run MP079 in the playground