Skip to content

feat(auth): enforce the role matrix on every data route (M2c, #94) - #101

Merged
amar-python merged 1 commit into
mainfrom
feat/m2c-role-matrix
Oct 26, 2026
Merged

amar-python merged 1 commit into
mainfrom
feat/m2c-role-matrix

Conversation

@amar-python

Copy link
Copy Markdown
Owner

Fixes #94. This is part 3 of ART Milestone 2 (BR-36; the roles come from ADR-0003).

The matrix (also in docs/ROLES.md)

Action uploader reviewer tenant_admin auditor
preview, upload ✓ ✓
list files, read rows, list T&E tables ✓ ✓ ✓ ✓
delete file ✓
read audit log ✓ ✓

This is my recommended default and needs your sign-off. I picked it for three reasons:

  • Only tenant admins can destroy data.
  • Auditors are read-only but can see the audit trail.
  • Reviewers stay read-only until approval and editing arrive (M4 and M6).

Changing it means editing one line in PERMISSIONS and the matching row in the doc. The test fails if the two disagree.

How

  • PERMISSIONS in api/auth.py maps each action to the roles allowed to do it.
  • allow(action) is a route dependency that returns 403 to any other signed-in role. It reuses the request's tenant_scope result, so the session is looked up only once.
  • Requests without a session (shared API key, or dev) aren't role-checked. They keep today's access until the shared key is retired.
  • Isolation tests (M2b: route every request to its tenant's schema (BR-36) #93) now use tenant admins. Cross-tenant isolation is checked at the highest privilege level.

Evidence

All runs are against local PostgreSQL 16.

Check Result
Local replica of the CI integration job (scripts/test_report.py --strict) 281 passed, 0 failed, 0 skipped (277 on main + 4 new)
Evals p,i,s,e 26/26
tests/test_roles.py 4 passed: doc matches code; every role × every route (28 combinations)
Same tests with the role check disabled all 9 refused combinations fail (as expected)
DB-free pytest 128 passed
scripts/lint.sh clean

Generated by Claude Code

PERMISSIONS in api/auth.py maps each action to the roles allowed it;
allow(action) returns 403 for any other signed-in role. docs/ROLES.md
shows the same table and tests/test_roles.py fails if they drift, then
tries every role against every route. Requests without a session keep
the shared-key access. Isolation tests now use tenant admins, so they
check isolation at the highest privilege.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YPoXzBSj89ZHgw7nfTmbB
@amar-python amar-python added this to the ART extension milestone Oct 26, 2026 — with Claude
@amar-python amar-python added enhancement New feature or request art ART framework extension work labels Oct 26, 2026 — with Claude

Copy link
Copy Markdown
Owner Author

Role matrix approved as proposed by the product owner on 26 Oct.


Generated by Claude Code

@amar-python
amar-python merged commit de01ed7 into main Oct 26, 2026
3 checks passed
@amar-python
amar-python deleted the feat/m2c-role-matrix branch October 27, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

art ART framework extension work enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

M2c: role-based authorisation matrix (BR-36)

2 participants