-
Notifications
You must be signed in to change notification settings - Fork 175
Expand file tree
/
Copy pathgranter.py
More file actions
109 lines (90 loc) · 3.71 KB
/
granter.py
File metadata and controls
109 lines (90 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
from __future__ import annotations
from dataclasses import dataclass
from uuid import UUID
from sqlalchemy.dialects.postgresql import insert as pg_insert
from sqlalchemy.ext.asyncio import AsyncSession as SASession
from ai.backend.common.data.permission.types import (
OperationType,
RBACElementType,
RelationType,
)
from ai.backend.manager.data.permission.id import (
ObjectId,
ScopeId,
)
from ai.backend.manager.models.rbac_models.association_scopes_entities import (
AssociationScopesEntitiesRow,
)
from ai.backend.manager.models.rbac_models.permission.permission import PermissionRow
# =============================================================================
# Data Classes
# =============================================================================
@dataclass
class RBACGranter:
"""
Data class for granting permissions to specific role(s) using entity-as-scope pattern.
This performs two operations:
1. Insert a ref edge in association_scopes_entities (visibility).
2. Insert entity-scope permissions in the permissions table (access control).
Note: Only entity-level granting is supported. Field-level granting is not supported.
Attributes:
granted_entity_id: The entity to grant access to (must be entity, not field).
granted_entity_scope_type: The scope_type for entity-as-scope in permissions table.
target_scope_id: The scope to associate the entity with (e.g., invitee's User scope).
target_role_ids: The role ID(s) to grant permissions to.
operations: The operations to grant on the entity.
"""
granted_entity_id: ObjectId
granted_entity_scope_type: RBACElementType
target_scope_id: ScopeId
target_role_ids: list[UUID]
operations: list[OperationType]
# =============================================================================
# Public API
# =============================================================================
async def execute_rbac_granter(
db_sess: SASession,
granter: RBACGranter,
) -> None:
"""
Grant permissions to specified roles using entity-as-scope pattern.
This is used when sharing an existing entity with specific roles.
For example, when user A invites user B to a VFolder:
- User B's role (provided by caller) gets permissions for that VFolder.
Args:
db_sess: Async SQLAlchemy session (must be writable).
granter: Granter instance containing granted_entity_id, target_role_ids, and operations.
"""
role_ids = granter.target_role_ids
entity_id = granter.granted_entity_id
if not role_ids or not granter.operations:
return
# 1. Insert ref edge in association_scopes_entities (visibility)
# Use ON CONFLICT DO NOTHING to safely handle repeated grants for the
# same (scope_type, scope_id, entity_id) triple.
ref_edge_stmt = (
pg_insert(AssociationScopesEntitiesRow)
.values(
scope_type=granter.target_scope_id.scope_type,
scope_id=granter.target_scope_id.scope_id,
entity_type=entity_id.entity_type,
entity_id=entity_id.entity_id,
relation_type=RelationType.REF,
)
.on_conflict_do_nothing(constraint="uq_scope_id_entity_id")
)
await db_sess.execute(ref_edge_stmt)
# 2. Insert entity-scope permissions (access control)
perms = [
PermissionRow(
role_id=role_id,
scope_type=granter.granted_entity_scope_type.to_scope_type(),
scope_id=entity_id.entity_id,
entity_type=entity_id.entity_type,
operation=operation,
)
for role_id in role_ids
for operation in granter.operations
]
db_sess.add_all(perms)
await db_sess.flush()