Skip to content

test(perms): tripwire every grant-cutover mutation for a gate - #2453

Open
vecchp wants to merge 2 commits into
chore/fe-drop-org-headerfrom
test/perm-org-mutation-gating
Open

vecchp wants to merge 2 commits into
chore/fe-drop-org-headerfrom
test/perm-org-mutation-gating

Conversation

@vecchp

@vecchp vecchp commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

What

A meta-test (common/tests/test_org_mutation_gating.py) that fails CI when a mutation in a grant-cutover module (accounts, teams, shelters, reports) ships without a grant gate.

Rule

Each @mutation resolver in those schemas must either:

  1. gate in its own bodyrequire_can( / can_anywhere( / can_obj( / visible( / scoped *_get/*_queryset load (ADR 0001 §2.6), or
  2. delegate (one hop) to a service/selector function in the same app that gates — this is how the thin shelters.schema resolvers pass, or
  3. be listed in GATE_EXEMPT with a reason — only the non-org mutations: login, logout, update_current_user, update_user_profile, delete_current_user, create_organization.

A second test keeps the exemption table honest: a stale entry (no such mutation any more) or a missing reason fails the suite. It is a heuristic tripwire, not a proof — the docstring says so; the point is every new mutation forces a conscious gate-or-exempt decision.

Verified

  • 9/9 new tests pass; common/tests 232 passed; ruff clean.
  • Negative checks (run out-of-band): a brand-new ungated resolver is caught; a delegated gate passes; a stale exemption is caught.

Stacked on #2452 (last layer of the perm stack). Frontend for the header removal: #2452; meta-test stack position: after it.

Summary by Sourcery

Enforce conscious grant-gating decisions for every mutation in grant-cutover modules.

Enhancements:

  • Add a meta-test that checks grant-cutover GraphQL mutations are gated directly, through a same-app delegate, or via an explicitly justified exemption.
  • Validate that configured grant-gated schema modules exist and that exemption entries reference current mutations with reasons.

Tests:

  • Add AST-based tests covering mutation gating, exemption validity, and configured schema presence.

Chores:

  • Apply formatting cleanup in the shared test utilities.

Add a common/tests meta-test that walks accounts/teams/shelters/reports
Mutation resolvers and fails unless each one gates on the grant
predicates (require_can/can_anywhere/can_obj/visible — or a scoped
*_get/*_queryset load, ADR 0001 §2.6), delegates to a service/selector
that does, or is deliberately exempted with a reason (auth + self-service
mutations in accounts, plus create_organization).

Verified by negative checks: a new ungated mutation is caught, a
delegated gate passes, and a stale exemption entry fails the suite.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry @vecchp, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 3 hours and 56 minutes by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Introduces a heuristic AST-based CI tripwire for grant gating: every mutation in accounts, reports, shelters, and teams must gate directly, delegate once to a gated service/selector, or use a documented valid exemption, while configuration and exemption drift fail loudly.

File-Level Changes

Change Details Files
Adds an AST-based meta-test that enforces grant gates on mutations in the four grant-cutover schemas.
  • Discovers @mutation resolvers in each app's Mutation class.
  • Accepts direct gate markers, scoped permission loads, or one-hop delegation to gated service/selector functions.
  • Reports all ungated mutations with actionable remediation guidance.
apps/betterangels-backend/common/tests/test_org_mutation_gating.py
Adds explicit, validated exemptions for intentionally non-org mutations.
  • Documents the six allowed authentication, self-service, and organization-creation exemptions with reasons.
  • Fails when an exemption is missing a reason or references a removed mutation.
apps/betterangels-backend/common/tests/test_org_mutation_gating.py
Protects the configured cutover scope from silently becoming stale.
  • Verifies each configured app schema still exists.
  • Keeps the test heuristic intentionally limited to source markers and one delegation hop.
apps/betterangels-backend/common/tests/test_org_mutation_gating.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

CI lint (uv run ruff format --check .) caught a wrap that fits on one
line (108 < 120 columns).
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.

2 participants