You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Three fixtures each independently prevent the test suite from exercising RLS at all:
Where
What
tests/conftest.py:95
Base.metadata.create_all — schema is built from models, so no policies exist
tests/conftest.py:88
connects as the local postgres superuser — superuser bypasses RLS unconditionally, so policies would not apply even if they existed
tests/conftest_optional.py:284
overrides get_current_user — with GUC population living in the auth dependency (#823), every router test validates the override, not the mechanism
The third matters most: it is why the auth-path bug in #823 would have shipped undetected, and it means the canary (#810) and the differential matrix (#809) would both pass against a stubbed principal.
Local development has the same problem. .env.dev sets DB_USERNAME=postgres, and there is no docker-entrypoint-initdb.d mount anywhere, so roles are created nowhere. Without this issue, the first real exercise of the security boundary is production.
The session fixture creates the bootstrap roles and connects as mavedb_api. Seeding paths that need to write across visibility boundaries elevate explicitly.
A path for tests to set a real principal rather than stubbing get_current_user, so the GUC seam is exercised. The override can remain for tests that are not about permissions.
A docker-entrypoint-initdb.d mount running part 1 of the bootstrap (Role topology and idempotent bootstrap script #827), and .env.dev → DB_USERNAME=mavedb_api. Part 2 references application tables, so it needs a schema and cannot run there. Local and CI each need a place to run it after create_all / alembic upgrade head.
Acceptance criteria
Local and CI both connect as a non-superuser, non-owner role with policies present.
A test asserts the fixture role is not superuser, holds no rolbypassrlsdirectly or by inheritance, and is a member of nothing. Use pg_has_role(..., 'MEMBER') for the membership half — a NOINHERIT member reports USAGE false while retaining the ability to SET ROLE, so a USAGE check reports green on a role that can elevate itself.
The fixture role is notNOINHERIT. The guarantee being tested is "member of nothing", and NOINHERIT is precisely the configuration that makes a membership look absent while it is not.
The canary and the differential matrix run against a real principal, not a stubbed dependency.
The existing suite passes under the demoted role — this is where missing grants surface.
A deliberately dropped policy fails the canary in CI, proving the harness has teeth.
Three fixtures each independently prevent the test suite from exercising RLS at all:
tests/conftest.py:95Base.metadata.create_all— schema is built from models, so no policies existtests/conftest.py:88postgressuperuser — superuser bypasses RLS unconditionally, so policies would not apply even if they existedtests/conftest_optional.py:284get_current_user— with GUC population living in the auth dependency (#823), every router test validates the override, not the mechanismThe third matters most: it is why the auth-path bug in #823 would have shipped undetected, and it means the canary (#810) and the differential matrix (#809) would both pass against a stubbed principal.
Local development has the same problem.
.env.devsetsDB_USERNAME=postgres, and there is nodocker-entrypoint-initdb.dmount anywhere, so roles are created nowhere. Without this issue, the first real exercise of the security boundary is production.Scope
after_createDDL events from Define RLS policies for the six permission-aware entities #809, sincecreate_allis what the fixtures use.mavedb_api. Seeding paths that need to write across visibility boundaries elevate explicitly.get_current_user, so the GUC seam is exercised. The override can remain for tests that are not about permissions.docker-entrypoint-initdb.dmount running part 1 of the bootstrap (Role topology and idempotent bootstrap script #827), and.env.dev→DB_USERNAME=mavedb_api. Part 2 references application tables, so it needs a schema and cannot run there. Local and CI each need a place to run it aftercreate_all/alembic upgrade head.Acceptance criteria
rolbypassrlsdirectly or by inheritance, and is a member of nothing. Usepg_has_role(..., 'MEMBER')for the membership half — aNOINHERITmember reportsUSAGEfalse while retaining the ability toSET ROLE, so aUSAGEcheck reports green on a role that can elevate itself.NOINHERIT. The guarantee being tested is "member of nothing", andNOINHERITis precisely the configuration that makes a membership look absent while it is not.