Move the permissions table off the legacy entity and scope type enums
- Dominant language
- Python
- Stars
- 670
- Forks
- 183
- Avg merge
- 15h 13m
- Merged PRs (30d)
- 368
Description
The virtual-scope chain spans two migration states, and operations whose entity type has already moved to the open type cannot be granted to anyone but a superadmin.
### Where the boundary is
The chain joins entity_memberships -> scope_bindings -> permissions. The first two carry entity_type / scope_type as sa.String(32), holding the open ai.backend.common.data.entity.types.EntityType. permissions.entity_type and permissions.scope_type are still StrEnumType over the legacy ai.backend.common.data.permission.types enums, as is association_scopes_entities.entity_type.
### What that costs
The chain query binds the open type as a plain VARCHAR so an unknown type matches nothing rather than failing enum coercion (permission_controller/db_source/db_source.py:1347). That is fail-closed: an entity type absent from the legacy enum matches no permission row, resolves to Permission.NONE and is denied. The write side is closed too — PermissionRow.entity_type binds through value.value, so a permission row can only be authored with a legacy enum member. The permission cannot be read, and it cannot be granted either.
13 of the 48 entity types in the wiring catalog are not members of that enum. Of the 379 wired rows that actually run a permission query (single_entity, bulk and scope shapes behind the permission gate), 58 ask with one of the 13. The largest are vfolder_invitation (9 rows), role_preset (9) and entity_invitation (6) — operations meant for ordinary users. Today they are superadmin-only in effect.
### What to do
- Move permissions.entity_type and permissions.scope_type to sa.String(32), matching entity_memberships and scope_bindings.
- Decide whether association_scopes_entities.entity_type moves in the same change; it has the same shape and the same boundary.
- Drop the VARCHAR-literal bind once both sides hold the open type, so the seam does not outlive the migration.
- Adding members to the legacy enum is not the fix — it reverses the migration.
### Done when
A non-superadmin holding a role that grants a permission on one of the 13 entity types passes the check. Whether the 58 rows are denied today or a legacy path quietly grants them is confirmed by BA-7489; this issue stands either way, and that answer only decides how urgent it is.
Evidence and the full type list: docs/reports/v2-action-audit/02-permission-logic.md
JIRA Issue: BA-7493
Contributor guide
Research direction
Start by reading permission_controller/db_source/db_source.py around line 1347 and the type definitions named in the issue, then review docs/reports/v2-action-audit/02-permission-logic.md and BA-7489. Trace the entity_memberships → scope_bindings → permissions chain and decide whether association_scopes_entities.entity_type follows the same migration. Done means applicable non-superadmin permissions for open entity types pass the check and the obsolete VARCHAR-literal bind is removed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- authorization, backend, databases
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100