Skip to content

Local and CI role parity with production #830

Closed as not planned
Closed as not planned

Description

@bencap

Why this is not optional

Today DB_USERNAME=postgres and POSTGRES_USER=postgres locally, and pytest_postgresql hands the test suite a superuser. Verified: a superuser reads every row even with policies present, RLS enabled, and FORCE ROW LEVEL SECURITY set — silently. So without parity, the first real exercise of the security boundary is production, and the test suite would pass while enforcing nothing.

Scope

  • A docker-entrypoint-initdb.d mount running bootstrap-roles.sql. No such mount exists today, which is why roles are created nowhere.
  • settings/.env.dev: DB_USERNAME=mavedb_api, keeping POSTGRES_USER=postgres as the cluster owner.
  • tests/conftest.py: the session fixture creates the roles and connects as mavedb_api.

Note that the test suite builds schema with Base.metadata.create_all, not alembic, so policies must also exist as after_create DDL events (#809) for any of this to be meaningful.

Acceptance criteria

  • Local stack and CI both connect as a non-superuser, non-owner role.
  • A test asserts the fixture role is not a superuser, has no inherited rolbypassrls, and is NOINHERIT.
  • Existing tests pass under the demoted role — this is where missing grants surface.

Activity

  1. added theissue type on Aug 7, 2026
  2. bencap commented on Aug 7, 2026

    @bencap
    CollaboratorAuthor

    Closing as a duplicate of #834, which covers the same three surfaces — the docker-entrypoint-initdb.d mount, .env.dev's DB_USERNAME, and the conftest.py session fixture — and additionally owns the get_current_user override, which is the fixture that would have silently invalidated the canary and the differential matrix.

    The one acceptance criterion here that #834 did not already carry was that the fixture role hold no inherited rolbypassrls. That distinction is worth keeping and has been folded into #834.

    The other distinct criterion — that the fixture role be NOINHERIT — is not carried over, because it is wrong in the same direction the design record warns about. #827 creates mavedb_api with plain LOGIN, so this criterion would have failed against its own foundation script. More importantly, NOINHERIT is precisely the configuration log #35 identifies as reporting green while retaining the ability to SET ROLE: a NOINHERIT member of mavedb_system shows USAGE false and can still elevate itself and read every row. The property to assert is "member of nothing", tested with pg_has_role(..., 'MEMBER') — which #834 now states explicitly.

    #808's sequencing step 0 has been updated to list #827 and #834 only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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