Skip to content

Test and local fixture parity with the production role topology #834

Description

@bencap

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.

Scope

  • Policies present in the test database, via the after_create DDL events from Define RLS policies for the six permission-aware entities #809, since create_all is what the fixtures use.
  • 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.devDB_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 rolbypassrls directly 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 not NOINHERIT. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    app: backendTask implementation touches the backend

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions