Skip to content

[RBAC PR 1] Enforce MANAGE permission on RBAC and group admin APIs#2230

Open
philipfweiss wants to merge 2 commits into
DataJunction:mainfrom
philipfweiss:rbac-manage-enforcement
Open

[RBAC PR 1] Enforce MANAGE permission on RBAC and group admin APIs#2230
philipfweiss wants to merge 2 commits into
DataJunction:mainfrom
philipfweiss:rbac-manage-enforcement

Conversation

@philipfweiss

@philipfweiss philipfweiss commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Tracking: #2234 (step 1 of the RBAC enablement sequence).

The RBAC engine already exists, but every role/group admin endpoint was auth-only, so any logged-in user could self-grant any role. That makes restrictive access policies unenforceable.

This PR enforces the MANAGE action on those endpoints:

  • Roles (api/rbac.py): create/update/delete, add/remove scope, assign/revoke now require MANAGE on the resources the scope targets. You can only grant access you already manage (prevents privilege escalation).
  • Groups (api/groups.py): register and membership changes require a global MANAGE grant.
  • Adds AccessChecker.add_scope() helper.

Why this won't take effect now: DJ’s default access policy is still permissive, so the new MANAGE checks allow requests when no explicit restrictive grant/policy denies them.

When this will start taking effect: Once a deployment enables restrictive RBAC. Since this isn't enabled today, this is a no-op. Once we seed roles, this change will become relevant.


Verification:

  1. Started local DJ server
./dev.sh up -d
DJ  : http://localhost:8000
UI  : http://localhost:3000
GET /health/
attempt=1 status=200 body=[{"name":"database","status":"ok"}]
  1. Enabled RBAC restrictive setting
authorization_provider= rbac
default_access_policy= restrictive
  1. Seeded one allowed grant for the local dj user: MANAGE on finance.*. Also seeded growth roles for denied-path tests.
name                         | action | scope_type | scope_value | assigned_to
manual-finance-manager       | MANAGE | NAMESPACE  | finance.*   | dj
manual-growth-assigned-role  | READ   | NAMESPACE  | growth.*    | dj
manual-growth-role           | READ   | NAMESPACE  | growth.*    |
  1. Logged in as non-admin user dj
POST /basic/login/ -> HTTP_STATUS:200
GET /whoami/ -> {"username":"dj","is_admin":false} HTTP_STATUS:200
  1. Verified role creation requires MANAGE on the role scopes.
POST /roles/ finance.* role -> HTTP_STATUS:201
POST /roles/ growth.* role -> {"message":"Access denied to 1 resource(s): growth.*"} HTTP_STATUS:403
  1. Verified adding, deleting, role metadata, assigning roles, revoking roles, deleting roles all require MANAGE

note that POST here is shorthand for the actual payload, something like

POST /roles/
{
  "name": "manual-finance-reader",
  "description": "Manual PR 2230 allowed role",
  "scopes": [
    {
      "action": "read",
      "scope_type": "namespace",
      "scope_value": "finance.*"
    }
  ]
}
POST /roles/manual-empty-role/scopes/ finance.* -> HTTP_STATUS:201
POST /roles/manual-empty-role/scopes/ growth.* -> {"message":"Access denied to 1 resource(s): growth.*"} HTTP_STATUS:403
...
DELETE /roles/manual-empty-role/scopes/write/namespace/finance.* -> HTTP_STATUS:204
DELETE /roles/manual-growth-role/scopes/read/namespace/growth.* -> {"message":"Access denied to 1 resource(s): growth.*"} HTTP_STATUS:403
...
POST /roles/manual-finance-reader/assign -> HTTP_STATUS:201
POST /roles/manual-growth-role/assign -> {"message":"Access denied to 1 resource(s): growth.*"} HTTP_STATUS:403
...
DELETE /roles/manual-finance-reader/assignments/dj -> HTTP_STATUS:204
DELETE /roles/manual-growth-assigned-role/assignments/dj -> {"message":"Access denied to 1 resource(s): growth.*"} HTTP_STATUS:403
...
DELETE /roles/manual-finance-reader -> HTTP_STATUS:204
DELETE /roles/manual-growth-role -> {"message":"Access denied to 1 resource(s): growth.*"} HTTP_STATUS:403

Require a matching MANAGE grant to create, modify, hand out, or revoke
roles and to administer groups, so principals can only delegate access
they already control. Without this, any authenticated user could
self-grant arbitrary roles, making restrictive access policies
unenforceable.

Co-authored-by: Cursor <cursoragent@cursor.com>
@netlify

netlify Bot commented Jun 5, 2026

Copy link
Copy Markdown

Deploy Preview for thriving-cassata-78ae72 canceled.

Name Link
🔨 Latest commit c544b6e
🔍 Latest deploy log https://app.netlify.com/projects/thriving-cassata-78ae72/deploys/6a4591edafd55f00080288a6

@philipfweiss philipfweiss changed the title Enforce MANAGE permission on RBAC and group admin APIs [RBAC PR 1] Enforce MANAGE permission on RBAC and group admin APIs Jul 1, 2026
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.

1 participant