Skip to content

Conversation

@tianzhou
Copy link
Contributor

@tianzhou tianzhou commented Jan 4, 2026

Fix #220

Policy expressions (USING/WITH CHECK) now strip same-schema function
qualifiers to prevent perpetual diffs. When a policy references a
function in the same schema (e.g., tenant1.auth_uid()), the qualifier
is normalized away to match PostgreSQL's storage behavior.

Changes:

  • Update normalizePolicyExpression to accept tableSchema parameter
  • Add schema stripping logic matching normalizeDefaultValue pattern
  • Add test case with auth_uid() function and users_isolation policy

🤖 Generated with Claude Code

tianzhou and others added 3 commits January 3, 2026 19:24
Implements PostgreSQL's FORCE ROW LEVEL SECURITY feature, which applies
row-level security policies even to table owners and superusers.

Changes:
- Added RLSForced boolean field to IR Table struct
- Updated database queries to fetch relforcerowsecurity from pg_class
- Extended diff logic to track ENABLE and FORCE changes independently
- Added SQL generation for FORCE/NO FORCE ROW LEVEL SECURITY statements
- Created dedicated test case for FORCE RLS functionality
- Updated fingerprints in existing policy tests to account for new IR field

Test coverage:
- New test: create_policy/force_rls - validates FORCE RLS detection and migration
- All 9 policy integration tests passing
- Both diff and plan/apply tests validated

Fixes #214

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Policy expressions (USING/WITH CHECK) now strip same-schema function
qualifiers to prevent perpetual diffs. When a policy references a
function in the same schema (e.g., tenant1.auth_uid()), the qualifier
is normalized away to match PostgreSQL's storage behavior.

Changes:
- Update normalizePolicyExpression to accept tableSchema parameter
- Add schema stripping logic matching normalizeDefaultValue pattern
- Add test case with auth_uid() function and users_isolation policy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 4, 2026 03:26
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes issue #220 where policy expressions containing same-schema function calls caused perpetual diffs. When PostgreSQL stores RLS policies that reference functions in the same schema (e.g., tenant1.auth_uid()), it strips the schema qualifier as the function is in the search path. However, pgschema was not normalizing these qualifiers during comparison, leading to false positives in plan diffs.

Key changes:

  • Updated normalizePolicy and normalizePolicyExpression to accept tableSchema parameter for context-aware normalization
  • Added same-schema function qualifier stripping logic matching the pattern established in normalizeDefaultValue (from issue #218 fix)
  • Added comprehensive test case with auth_uid() function and users_isolation policy to validate the fix

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
ir/normalize.go Updated normalizePolicy and normalizePolicyExpression to accept table schema parameter and strip same-schema function qualifiers from policy expressions using regex pattern matching
testdata/dump/tenant/tenant.sql Added auth_uid() function and users_isolation RLS policy test case to reproduce and validate the fix for issue #220
testdata/dump/tenant/pgschema.sql Added expected output showing the policy with unqualified function call, ensuring normalized comparison works correctly

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@tianzhou tianzhou merged commit 98f1704 into main Jan 4, 2026
8 checks passed
asonawalla added a commit to asonawalla/pgschema that referenced this pull request Jan 4, 2026
Following the pattern established in PR pgplex#222 for function qualifiers,
this extends policy expression normalization to also strip same-schema
qualifiers from table references.

When a policy expression contains a subquery like:
  FROM public.users u
PostgreSQL's pg_get_expr() returns it without the schema qualifier:
  FROM users u

This caused perpetual diffs because pgschema added the qualifier back.
The fix applies the same normalization approach: strip schema qualifiers
from table references when they match the target schema.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
tianzhou pushed a commit that referenced this pull request Jan 5, 2026
Following the pattern established in PR #222 for function qualifiers,
this extends policy expression normalization to also strip same-schema
qualifiers from table references.

When a policy expression contains a subquery like:
  FROM public.users u
PostgreSQL's pg_get_expr() returns it without the schema qualifier:
  FROM users u

This caused perpetual diffs because pgschema added the qualifier back.
The fix applies the same normalization approach: strip schema qualifiers
from table references when they match the target schema.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
@tianzhou tianzhou deleted the rls branch January 5, 2026 14:12
alecthomas pushed a commit to alecthomas/pgschema that referenced this pull request Jan 26, 2026
* feat: add support for FORCE ROW LEVEL SECURITY

Implements PostgreSQL's FORCE ROW LEVEL SECURITY feature, which applies
row-level security policies even to table owners and superusers.

Changes:
- Added RLSForced boolean field to IR Table struct
- Updated database queries to fetch relforcerowsecurity from pg_class
- Extended diff logic to track ENABLE and FORCE changes independently
- Added SQL generation for FORCE/NO FORCE ROW LEVEL SECURITY statements
- Created dedicated test case for FORCE RLS functionality
- Updated fingerprints in existing policy tests to account for new IR field

Test coverage:
- New test: create_policy/force_rls - validates FORCE RLS detection and migration
- All 9 policy integration tests passing
- Both diff and plan/apply tests validated

Fixes pgplex#214

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: regenerate plan

* fix: normalize policy expression schema qualifiers (pgplex#220)

Policy expressions (USING/WITH CHECK) now strip same-schema function
qualifiers to prevent perpetual diffs. When a policy references a
function in the same schema (e.g., tenant1.auth_uid()), the qualifier
is normalized away to match PostgreSQL's storage behavior.

Changes:
- Update normalizePolicyExpression to accept tableSchema parameter
- Add schema stripping logic matching normalizeDefaultValue pattern
- Add test case with auth_uid() function and users_isolation policy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
alecthomas pushed a commit to alecthomas/pgschema that referenced this pull request Jan 26, 2026
…gplex#226)

Following the pattern established in PR pgplex#222 for function qualifiers,
this extends policy expression normalization to also strip same-schema
qualifiers from table references.

When a policy expression contains a subquery like:
  FROM public.users u
PostgreSQL's pg_get_expr() returns it without the schema qualifier:
  FROM users u

This caused perpetual diffs because pgschema added the qualifier back.
The fix applies the same normalization approach: strip schema qualifiers
from table references when they match the target schema.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Policy expressions show perpetual diff due to schema qualification mismatch

1 participant