fix: avoid substring matches in policy table dependency detection#474
fix: avoid substring matches in policy table dependency detection#474meesvandongen wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds identifier-aware detection of whether an RLS policy references other newly-created tables, preventing false positives from substring matches (e.g., orders matching orders_archive).
Changes:
- Updates
policyReferencesOtherNewTableto usecontainsIdentifierinstead of raw substring matching. - Adds a focused unit test to validate identifier-aware matching behavior.
- Adds testdata fixtures reproducing the substring false-positive scenario across multiple plan formats.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| testdata/diff/dependency/policy_identifier_substring_false_positive/plan.txt | Adds plan output fixture for the false-positive scenario. |
| testdata/diff/dependency/policy_identifier_substring_false_positive/plan.sql | Adds SQL plan fixture for the false-positive scenario. |
| testdata/diff/dependency/policy_identifier_substring_false_positive/plan.json | Adds JSON plan fixture for the false-positive scenario. |
| testdata/diff/dependency/policy_identifier_substring_false_positive/old.sql | Adds “empty schema” baseline fixture. |
| testdata/diff/dependency/policy_identifier_substring_false_positive/new.sql | Adds “new schema” fixture including RLS policy and "user" table. |
| testdata/diff/dependency/policy_identifier_substring_false_positive/diff.sql | Adds expected diff fixture for the scenario. |
| internal/diff/policy_dependency_test.go | Adds a unit test ensuring substring-only matches inside longer identifiers don’t trigger deferral. |
| internal/diff/diff.go | Switches policy dependency detection to identifier-aware matching to avoid substring false positives. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if containsIdentifier(expr, tableName) || containsIdentifier(expr, qualifiedName) { | ||
| return true | ||
| } |
| // Skip the policy's own table | ||
| if qualifiedName == ownQualified { | ||
| continue | ||
| } | ||
| // Extract the unqualified table name for substring matching. | ||
| // Policy expressions may use unqualified or qualified references. | ||
| parts := strings.SplitN(qualifiedName, ".", 2) | ||
| tableName := parts[len(parts)-1] | ||
| if strings.Contains(exprLower, tableName) { | ||
| if containsIdentifier(expr, tableName) || containsIdentifier(expr, qualifiedName) { |
Greptile SummaryThis PR makes RLS policy table dependency checks use identifier-aware matching. The main changes are:
Confidence Score: 4/5This looks safe to merge, but a few false-positive cases remain.
internal/diff/diff.go Important Files Changed
Reviews (1): Last reviewed commit: "add test" | Re-trigger Greptile |
| parts := strings.SplitN(qualifiedName, ".", 2) | ||
| tableName := parts[len(parts)-1] | ||
| if strings.Contains(exprLower, tableName) { | ||
| if containsIdentifier(expr, tableName) || containsIdentifier(expr, qualifiedName) { |
There was a problem hiding this comment.
This still treats any whole-word occurrence as a table dependency, even when the word is inside a SQL string literal or comment. For example, if a new table users is added and a policy only has USING (group_name = 'users'), this returns true and unnecessarily defers the policy even though it does not reference that table. That keeps the false-positive class alive for policy dependency detection.
| parts := strings.SplitN(qualifiedName, ".", 2) | ||
| tableName := parts[len(parts)-1] | ||
| if strings.Contains(exprLower, tableName) { | ||
| if containsIdentifier(expr, tableName) || containsIdentifier(expr, qualifiedName) { |
There was a problem hiding this comment.
PostgreSQL identifiers can contain $, but containsIdentifier only treats letters, digits, and _ as identifier characters. A new table named foo will therefore match an unrelated identifier like foo$bar in a policy expression, because $ is treated as a boundary. That can still produce substring-style false positives for valid PostgreSQL identifiers.
Fix false positives when detecting whether an RLS policy depends on another newly added table.
Previously, table names were matched by substring, so identifiers like CURRENT_USER or user_name could be mistaken for references to a new table named
user.This change switches policy dependency detection to identifier-aware matching and adds a focused regression test plus a file-based fixture.