Skip to content

Conversation

@RJPercival
Copy link

@RJPercival RJPercival commented Nov 15, 2025

Description

Fixes #92

This PR makes the ConstraintQueries class schema-aware to support multi-tenant environments using django-tenants.

There is a similar PR for kraken-core: https://github.com/octoenergy/kraken-core/pull/230402. That PR also adds semgrep rules to mitigate against regressions - since semgrep doesn't seem to be set up for this repo, I haven't included similar rules here.

Problem

Prior to this change, the three constraint check queries (CHECK_EXISTING_CONSTRAINT, CHECK_CONSTRAINT_IS_VALID, and CHECK_CONSTRAINT_IS_NOT_VALID) queried pg_catalog.pg_constraint without filtering by PostgreSQL schema. In multi-tenant setups where each tenant has its own schema, these queries would detect constraints from other tenants' schemas, causing false positives.

For example, when creating a second tenant, migrations would fail with ConstraintAlreadyExists errors because the queries found constraints from the first tenant's schema.

Solution

Added INNER JOINs with pg_catalog.pg_class and pg_catalog.pg_namespace to filter constraints by current_schema(). This ensures that constraint checks only examine the current tenant's schema.

Changes

  • Updated CHECK_EXISTING_CONSTRAINT to filter by schema
  • Updated CHECK_CONSTRAINT_IS_VALID to filter by schema
  • Updated CHECK_CONSTRAINT_IS_NOT_VALID to filter by schema
  • Updated all test assertions to expect the new SQL format
  • Added 5 new multi-schema behavioral tests that detect the bug

Testing

Behavioral Tests

Commit 1 adds 5 integration tests that create multiple PostgreSQL schemas:

  • test_check_existing_constraint_only_sees_current_schema
  • test_check_constraint_is_valid_only_sees_current_schema
  • test_check_constraint_is_not_valid_only_sees_current_schema
  • test_unique_constraint_creation_in_second_schema
  • test_check_constraint_creation_in_second_schema

All tests are marked @pytest.mark.xfail in commit 1, demonstrating they detect the bug:

  • Without fixes: 5 tests xfail as expected ✓
  • With fixes (commit 2): 5 tests pass ✓

The tests use schema-aware SQL for verification to ensure they actually detect the bug, not just test the buggy queries with themselves.

Test Results

  • All 125 tests pass (120 existing + 5 new)
  • Tests validate both SQL format and actual multi-tenant behavior
  • Clearly demonstrates the bug is detected and then fixed

@RJPercival RJPercival requested a review from a team as a code owner November 15, 2025 23:08
Prior to this change, the test suite only verified that the generated
SQL matched the expected format, but didn't test the actual multi-tenant
behavior. The bug would not have been caught by existing tests.

This change adds 5 new integration tests that create multiple PostgreSQL
schemas and verify that constraint queries are schema-aware:

- test_check_existing_constraint_only_sees_current_schema
- test_check_constraint_is_valid_only_sees_current_schema
- test_check_constraint_is_not_valid_only_sees_current_schema
- test_unique_constraint_creation_in_second_schema
- test_check_constraint_creation_in_second_schema

All tests are marked with @pytest.mark.xfail because the bug has not
yet been fixed. They fail as expected, demonstrating the bug:
- First 3 tests: Assert that queries don't see other schemas (they do)
- Last 2 tests: Assert constraints are created in both schemas (they
  aren't, because the buggy queries make the operations think the
  constraint already exists)

These tests use schema-aware SQL for verification to ensure they
actually detect the bug, not just test the buggy queries with
themselves.

Related issue: kraken-tech#92
Prior to this change, the ConstraintQueries class queried
pg_catalog.pg_constraint without filtering by PostgreSQL schema.
This caused incorrect behavior in multi-tenant environments using
django-tenants, where each tenant has its own schema. The queries
would detect constraints from other tenants' schemas, leading to
false positives (e.g., ConstraintAlreadyExists errors when creating
a second tenant).

This change adds INNER JOINs with pg_catalog.pg_class and
pg_catalog.pg_namespace to filter constraints by current_schema().
This ensures that constraint checks only look at the current tenant's
schema, not across all schemas in the database.

Affected queries:
- CHECK_EXISTING_CONSTRAINT
- CHECK_CONSTRAINT_IS_VALID
- CHECK_CONSTRAINT_IS_NOT_VALID

Related issue: kraken-tech#92
@RJPercival RJPercival force-pushed the fix-schema-awareness-multitenancy branch from de312d9 to 779bf2c Compare November 15, 2025 23:41
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.

Constraint queries not schema-aware in multi-tenant environments

1 participant