Skip to content

feat(rbac): accept service-account actors and make org:rbac:* assignable#2810

Open
mcm wants to merge 1 commit into
TracecatHQ:mainfrom
mcm:mcm/rbac-service-account-actor-role
Open

feat(rbac): accept service-account actors and make org:rbac:* assignable#2810
mcm wants to merge 1 commit into
TracecatHQ:mainfrom
mcm:mcm/rbac-service-account-actor-role

Conversation

@mcm

@mcm mcm commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Checklist

  • Read CONTRIBUTING.md.
  • PR title is short and non-generic (see previously merged PRs for examples).
  • PR only implements a single feature or fixes a single bug.
  • Tests passing (uv run pytest tests)?
  • Lint / pre-commits passing (pre-commit run --all-files)?

Description

The portal's workspace membership-sync principal (a Tracecat service account / API key) calls GET and PATCH /rbac/user-assignments to mirror the Default Workspace's user→role assignments into every tenant workspace. Both calls fail today for two coupled reasons:

  1. ACL rejects service accounts. Every org RBAC endpoint — OSS user-assignments + roles, and the EE scopes/roles/groups/assignments routers — gated on OrgUserRole, whose RoleACL sets allow_api_key=False. A service-account key is rejected at the dependency layer before @require_scope ever runs, regardless of the scopes it holds.

  2. org:rbac:* was never assignable to a service account. org:rbac:read/create/update/delete was absent from ORG_SERVICE_ACCOUNT_ASSIGNABLE_SCOPES, so the scope could not be granted to a service account in the first place.

Changes

  • Swap OrgUserRoleOrgActorRole (allow_api_key=True) on all org RBAC endpoints in tracecat/authz/rbac/router.py and tracecat_ee/rbac/router.py, including the EE _require_rbac_entitlement router dependency. @require_scope("org:rbac:*") remains the real authorization gate — this only widens the who (user or service account), not the what.
  • Add org:rbac:read/create/update/delete to ORG_SERVICE_ACCOUNT_ASSIGNABLE_SCOPES so the scopes can actually be granted to a service account. _resolve_assignable_scopes still prevents privilege escalation (a caller can only grant scopes it already holds).
  • Update test_service_accounts_validation.py: org:rbac:* now asserted assignable to org service accounts.

get_my_scopes (/users/me/scopes) is intentionally left user-only — it is an identity endpoint, not an RBAC-management one.

🤖 Generated with Claude Code


Summary by cubic

Enable service-account API keys to access org RBAC endpoints by accepting service-account actors and making org:rbac:* scopes assignable. This unblocks the membership-sync service account to mirror user→role assignments via GET/PATCH /rbac/user-assignments.

  • New Features

    • Switched router deps from OrgUserRole to OrgActorRole across OSS and EE RBAC routers (incl. entitlement check) so users and service accounts pass ACL; @require_scope("org:rbac:*") remains the gate.
    • Added org:rbac:read, org:rbac:create, org:rbac:update, org:rbac:delete to ORG_SERVICE_ACCOUNT_ASSIGNABLE_SCOPES; callers can only grant scopes they hold.
    • Updated tests to assert org:rbac:* is assignable to org service accounts; get_my_scopes stays user-only.
  • Migration

    • Grant required org:rbac:* scopes to service accounts that manage org RBAC (e.g., the membership-sync key).

Written for commit 33c1ba4. Summary will update on new commits.

Review in cubic

The org RBAC routers (OSS user-assignments/roles and the EE
scopes/roles/groups/assignments routers) gated every endpoint on
OrgUserRole, whose RoleACL sets allow_api_key=False. That made the
entire RBAC surface unreachable by service-account API keys even when
the key held the required org:rbac:* scope — the ACL rejected the
principal before require_scope ran.

Two coupled gaps blocked service-account access:

- ACL: every RBAC endpoint used OrgUserRole. Switch to OrgActorRole
  (allow_api_key=True) so users AND service accounts are admitted; the
  existing @require_scope("org:rbac:*") decorator remains the real gate.
  Also widen the EE _require_rbac_entitlement router dependency.
- Assignability: org:rbac:* was absent from
  ORG_SERVICE_ACCOUNT_ASSIGNABLE_SCOPES, so the scope could never be
  granted to a service account in the first place. Add read/create/
  update/delete.

Unblocks the portal's membership-sync principal, which calls
GET/PATCH /rbac/user-assignments with a service-account key.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-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.

No issues found across 4 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Re-trigger cubic

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