Skip to content

Commit f4d759e

Browse files
fregataaclaude
andauthored
feat(BA-4526): Unify ScopeType/EntityType to RBACElementType in domain repos (#10336)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9bcd5c0 commit f4d759e

10 files changed

Lines changed: 44 additions & 36 deletions

File tree

changes/10336.enhance.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Unify ScopeType/EntityType to RBACElementType in domain data types, non-permission-controller repositories, and vfolder grant/revoke operations

src/ai/backend/manager/data/domain/types.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from datetime import datetime
77
from typing import Any, override
88

9+
from ai.backend.common.data.permission.types import RBACElementType
910
from ai.backend.common.data.user.types import UserRole
1011
from ai.backend.common.types import ResourceSlot, VFolderHostPermissionMap
1112
from ai.backend.manager.data.permission.id import ScopeId
@@ -46,9 +47,9 @@ def scope_id(self) -> ScopeId:
4647
def role_name(self) -> str:
4748
return f"domain-{self.name}-admin"
4849

49-
def entity_operations(self) -> Mapping[EntityType, Iterable[OperationType]]:
50+
def entity_operations(self) -> Mapping[RBACElementType, Iterable[OperationType]]:
5051
return {
51-
entity: OperationType.admin_operations()
52+
entity.to_element(): OperationType.admin_operations()
5253
for entity in EntityType.admin_accessible_entity_types_in_domain()
5354
}
5455

src/ai/backend/manager/data/group/types.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from datetime import datetime
88
from typing import Any, override
99

10+
from ai.backend.common.data.permission.types import RBACElementType
1011
from ai.backend.common.types import ResourceSlot, VFolderHostPermissionMap
1112
from ai.backend.manager.data.permission.id import ScopeId
1213
from ai.backend.manager.data.permission.types import (
@@ -63,9 +64,9 @@ def scope_id(self) -> ScopeId:
6364
def role_name(self) -> str:
6465
return f"project-{str(self.id)[:8]}-admin"
6566

66-
def entity_operations(self) -> Mapping[EntityType, Iterable[OperationType]]:
67+
def entity_operations(self) -> Mapping[RBACElementType, Iterable[OperationType]]:
6768
return {
68-
entity: OperationType.admin_operations()
69+
entity.to_element(): OperationType.admin_operations()
6970
for entity in EntityType.admin_accessible_entity_types_in_project()
7071
}
7172

src/ai/backend/manager/data/user/types.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from sqlalchemy.engine import Row
1111

12+
from ai.backend.common.data.permission.types import RBACElementType
1213
from ai.backend.common.data.user.types import UserRole
1314
from ai.backend.common.types import AccessKey
1415
from ai.backend.manager.data.keypair.types import KeyPairData
@@ -97,13 +98,13 @@ def scope_id(self) -> ScopeId:
9798
def role_name(self) -> str:
9899
return f"user-{str(self.id)[:8]}"
99100

100-
def entity_operations(self) -> Mapping[EntityType, Iterable[OperationType]]:
101+
def entity_operations(self) -> Mapping[RBACElementType, Iterable[OperationType]]:
101102
resource_entity_permissions = {
102-
entity: OperationType.owner_operations()
103+
entity.to_element(): OperationType.owner_operations()
103104
for entity in EntityType.owner_accessible_entity_types_in_user()
104105
}
105106
user_permissions = OperationType.owner_operations() - {OperationType.CREATE}
106-
return {EntityType.USER: user_permissions, **resource_entity_permissions}
107+
return {RBACElementType.USER: user_permissions, **resource_entity_permissions}
107108

108109
@classmethod
109110
def from_row(cls, row: Row[Any]) -> Self:

src/ai/backend/manager/repositories/base/rbac/granter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
from ai.backend.common.data.permission.types import (
1010
OperationType,
11+
RBACElementType,
1112
RelationType,
12-
ScopeType,
1313
)
1414
from ai.backend.manager.data.permission.id import (
1515
ObjectId,
@@ -45,7 +45,7 @@ class RBACGranter:
4545
"""
4646

4747
granted_entity_id: ObjectId
48-
granted_entity_scope_type: ScopeType
48+
granted_entity_scope_type: RBACElementType
4949
target_scope_id: ScopeId
5050
target_role_ids: list[UUID]
5151
operations: list[OperationType]
@@ -97,7 +97,7 @@ async def execute_rbac_granter(
9797
perms = [
9898
PermissionRow(
9999
role_id=role_id,
100-
scope_type=granter.granted_entity_scope_type,
100+
scope_type=granter.granted_entity_scope_type.to_scope_type(),
101101
scope_id=entity_id.entity_id,
102102
entity_type=entity_id.entity_type,
103103
operation=operation,

src/ai/backend/manager/repositories/base/rbac/revoker.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from sqlalchemy.engine import CursorResult
1010
from sqlalchemy.ext.asyncio import AsyncSession as SASession
1111

12-
from ai.backend.common.data.permission.types import OperationType, ScopeType
12+
from ai.backend.common.data.permission.types import OperationType, RBACElementType
1313
from ai.backend.manager.data.permission.id import ObjectId
1414
from ai.backend.manager.models.rbac_models.permission.permission import PermissionRow
1515

@@ -36,7 +36,7 @@ class RBACRevoker:
3636
"""
3737

3838
entity_id: ObjectId
39-
entity_scope_type: ScopeType
39+
entity_scope_type: RBACElementType
4040
target_role_ids: list[UUID]
4141
operations: list[OperationType] | None = None
4242

@@ -50,7 +50,7 @@ async def _delete_permissions(
5050
db_sess: SASession,
5151
role_ids: Collection[UUID],
5252
entity_id: ObjectId,
53-
scope_type: ScopeType,
53+
scope_type: RBACElementType,
5454
operations: list[OperationType] | None,
5555
) -> int:
5656
"""Delete permissions for the given entity-as-scope and roles."""
@@ -59,7 +59,7 @@ async def _delete_permissions(
5959

6060
conditions = [
6161
PermissionRow.role_id.in_(role_ids),
62-
PermissionRow.scope_type == scope_type,
62+
PermissionRow.scope_type == scope_type.to_scope_type(),
6363
PermissionRow.scope_id == entity_id.entity_id,
6464
PermissionRow.entity_type == entity_id.entity_type,
6565
]

src/ai/backend/manager/repositories/permission_controller/role_manager.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import sqlalchemy as sa
77
from sqlalchemy.ext.asyncio import AsyncSession as SASession
88

9+
from ai.backend.common.data.permission.types import RBACElementType
910
from ai.backend.logging import BraceStyleAdapter
1011
from ai.backend.manager.data.permission.id import ObjectId, ScopeId
1112
from ai.backend.manager.data.permission.object_permission import ObjectPermissionData
@@ -15,7 +16,6 @@
1516
)
1617
from ai.backend.manager.data.permission.status import RoleStatus
1718
from ai.backend.manager.data.permission.types import (
18-
EntityType,
1919
OperationType,
2020
RoleSource,
2121
)
@@ -42,7 +42,7 @@ def scope_id(self) -> ScopeId: ...
4242

4343
def role_name(self) -> str: ...
4444

45-
def entity_operations(self) -> Mapping[EntityType, Iterable[OperationType]]:
45+
def entity_operations(self) -> Mapping[RBACElementType, Iterable[OperationType]]:
4646
"""Returns a mapping of entity types to the set of operations that should be granted for each entity type."""
4747
...
4848

@@ -78,13 +78,13 @@ async def _create_permissions(
7878
role_id: uuid.UUID,
7979
) -> list[PermissionData]:
8080
permission_rows: list[PermissionRow] = []
81-
for entity, operations in data.entity_operations().items():
81+
for element_type, operations in data.entity_operations().items():
8282
for operation in operations:
8383
creator = PermissionCreator(
8484
role_id=role_id,
8585
scope_type=data.scope_id().scope_type,
8686
scope_id=data.scope_id().scope_id,
87-
entity_type=entity,
87+
entity_type=element_type.to_entity_type(),
8888
operation=operation,
8989
)
9090
permission_rows.append(PermissionRow.from_input(creator))

src/ai/backend/manager/repositories/vfolder/repository.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ async def create_vfolder_with_permission(
349349
entity_type=EntityType.VFOLDER,
350350
entity_id=str(params.id),
351351
),
352-
granted_entity_scope_type=ScopeType.VFOLDER,
352+
granted_entity_scope_type=RBACElementType.VFOLDER,
353353
target_scope_id=ScopeId(
354354
scope_type=ScopeType.USER,
355355
scope_id=str(params.user),
@@ -538,7 +538,7 @@ async def create_vfolder_permission(
538538
entity_type=EntityType.VFOLDER,
539539
entity_id=str(vfolder_id),
540540
),
541-
granted_entity_scope_type=ScopeType.VFOLDER,
541+
granted_entity_scope_type=RBACElementType.VFOLDER,
542542
target_scope_id=ScopeId(
543543
scope_type=ScopeType.USER,
544544
scope_id=str(user_id),
@@ -577,7 +577,7 @@ async def delete_vfolder_permission(self, vfolder_id: uuid.UUID, user_id: uuid.U
577577
entity_type=EntityType.VFOLDER,
578578
entity_id=str(vfolder_id),
579579
),
580-
entity_scope_type=ScopeType.VFOLDER,
580+
entity_scope_type=RBACElementType.VFOLDER,
581581
target_role_ids=[user_role_id],
582582
operations=None, # Revoke all operations
583583
)

tests/unit/manager/repositories/base/rbac/test_granter.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import pytest
1212
import sqlalchemy as sa
1313

14-
from ai.backend.common.data.permission.types import OperationType, RelationType
14+
from ai.backend.common.data.permission.types import OperationType, RBACElementType, RelationType
1515
from ai.backend.manager.data.permission.id import ObjectId, ScopeId
1616
from ai.backend.manager.data.permission.types import (
1717
EntityType,
@@ -53,7 +53,7 @@
5353
class GranterTestContext:
5454
"""Context data for granter tests."""
5555

56-
entity_scope_type: ScopeType
56+
entity_scope_type: RBACElementType
5757
entity_id: ObjectId
5858
target_scope_id: ScopeId
5959

@@ -116,7 +116,7 @@ async def single_role(
116116
role_id = role.id
117117

118118
yield SingleRoleContext(
119-
entity_scope_type=ScopeType.VFOLDER,
119+
entity_scope_type=RBACElementType.VFOLDER,
120120
entity_id=entity_id,
121121
target_scope_id=target_scope_id,
122122
role_id=role_id,
@@ -133,7 +133,7 @@ async def empty_context(
133133
target_scope_id = ScopeId(scope_type=ScopeType.USER, scope_id=str(uuid.uuid4()))
134134

135135
yield GranterTestContext(
136-
entity_scope_type=ScopeType.VFOLDER,
136+
entity_scope_type=RBACElementType.VFOLDER,
137137
entity_id=entity_id,
138138
target_scope_id=target_scope_id,
139139
)
@@ -232,7 +232,7 @@ async def multi_role_context(
232232
role_ids.append(role.id)
233233

234234
yield MultiRoleContext(
235-
entity_scope_type=ScopeType.VFOLDER,
235+
entity_scope_type=RBACElementType.VFOLDER,
236236
entity_id=entity_id,
237237
target_scope_id=target_scope_id,
238238
role_ids=role_ids,
@@ -296,7 +296,7 @@ async def single_role(
296296
role_id = role.id
297297

298298
yield SingleRoleContext(
299-
entity_scope_type=ScopeType.VFOLDER,
299+
entity_scope_type=RBACElementType.VFOLDER,
300300
entity_id=entity_id,
301301
target_scope_id=target_scope_id,
302302
role_id=role_id,

tests/unit/manager/repositories/base/rbac/test_revoker.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
import pytest
1212
import sqlalchemy as sa
1313

14-
from ai.backend.common.data.permission.types import EntityType, OperationType, ScopeType
14+
from ai.backend.common.data.permission.types import (
15+
EntityType,
16+
OperationType,
17+
RBACElementType,
18+
)
1519
from ai.backend.manager.data.permission.id import ObjectId
1620
from ai.backend.manager.data.permission.types import RoleSource
1721
from ai.backend.manager.models.rbac_models.permission.permission import PermissionRow
@@ -46,7 +50,7 @@ class SingleEntityWithRoleContext:
4650
"""Context with single entity granted to a role."""
4751

4852
entity_id: ObjectId
49-
entity_scope_type: ScopeType
53+
entity_scope_type: RBACElementType
5054
role_id: UUID
5155

5256

@@ -55,7 +59,7 @@ class EntityWithTwoRolesContext:
5559
"""Context with entity granted to two different roles."""
5660

5761
entity_id: ObjectId
58-
entity_scope_type: ScopeType
62+
entity_scope_type: RBACElementType
5963
role_id1: UUID
6064
role_id2: UUID
6165

@@ -90,7 +94,7 @@ async def single_entity_with_role(
9094
) -> AsyncGenerator[SingleEntityWithRoleContext, None]:
9195
"""Create entity with role having permissions."""
9296
entity_id = ObjectId(entity_type=EntityType.VFOLDER, entity_id=str(uuid.uuid4()))
93-
entity_scope_type = ScopeType.VFOLDER
97+
entity_scope_type = RBACElementType.VFOLDER
9498

9599
role_id: UUID
96100

@@ -108,7 +112,7 @@ async def single_entity_with_role(
108112
for op in [OperationType.READ, OperationType.UPDATE]:
109113
perm = PermissionRow(
110114
role_id=role.id,
111-
scope_type=entity_scope_type,
115+
scope_type=entity_scope_type.to_scope_type(),
112116
scope_id=entity_id.entity_id,
113117
entity_type=entity_id.entity_type,
114118
operation=op,
@@ -231,7 +235,7 @@ async def entity_with_two_roles(
231235
) -> AsyncGenerator[EntityWithTwoRolesContext, None]:
232236
"""Create entity granted to two different roles."""
233237
entity_id = ObjectId(entity_type=EntityType.VFOLDER, entity_id=str(uuid.uuid4()))
234-
entity_scope_type = ScopeType.VFOLDER
238+
entity_scope_type = RBACElementType.VFOLDER
235239

236240
role_id1: UUID
237241
role_id2: UUID
@@ -256,7 +260,7 @@ async def entity_with_two_roles(
256260
for role in [role1, role2]:
257261
perm = PermissionRow(
258262
role_id=role.id,
259-
scope_type=entity_scope_type,
263+
scope_type=entity_scope_type.to_scope_type(),
260264
scope_id=entity_id.entity_id,
261265
entity_type=entity_id.entity_type,
262266
operation=OperationType.READ,
@@ -331,7 +335,7 @@ async def single_entity_with_role(
331335
) -> AsyncGenerator[SingleEntityWithRoleContext, None]:
332336
"""Create entity with role having permissions."""
333337
entity_id = ObjectId(entity_type=EntityType.VFOLDER, entity_id=str(uuid.uuid4()))
334-
entity_scope_type = ScopeType.VFOLDER
338+
entity_scope_type = RBACElementType.VFOLDER
335339

336340
role_id: UUID
337341

@@ -346,7 +350,7 @@ async def single_entity_with_role(
346350

347351
perm = PermissionRow(
348352
role_id=role.id,
349-
scope_type=entity_scope_type,
353+
scope_type=entity_scope_type.to_scope_type(),
350354
scope_id=entity_id.entity_id,
351355
entity_type=entity_id.entity_type,
352356
operation=OperationType.READ,

0 commit comments

Comments
 (0)