Skip to content

Commit 95992c9

Browse files
fregataaclaude
andauthored
feat(BA-2476): apply RBAC validator for Project actions (#10029)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent af772e7 commit 95992c9

4 files changed

Lines changed: 53 additions & 14 deletions

File tree

changes/10029.feature.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Apply RBAC validators to project (group) action processors for proper permission enforcement

src/ai/backend/manager/services/group/actions/base.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,29 @@ def field_data(self) -> FieldData | None:
4141

4242
class GroupSingleEntityActionResult(BaseSingleEntityActionResult):
4343
pass
44+
45+
46+
class ProjectScopeAction(BaseScopeAction):
47+
@override
48+
@classmethod
49+
def entity_type(cls) -> EntityType:
50+
return EntityType.PROJECT
51+
52+
53+
class ProjectScopeActionResult(BaseScopeActionResult):
54+
pass
55+
56+
57+
class ProjectSingleEntityAction(BaseSingleEntityAction):
58+
@override
59+
@classmethod
60+
def entity_type(cls) -> EntityType:
61+
return EntityType.PROJECT
62+
63+
@override
64+
def field_data(self) -> FieldData | None:
65+
return None
66+
67+
68+
class ProjectSingleEntityActionResult(BaseSingleEntityActionResult):
69+
pass

src/ai/backend/manager/services/group/actions/search_projects.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
)
1919
from ai.backend.manager.services.group.actions.base import (
2020
GroupAction,
21-
GroupScopeAction,
22-
GroupScopeActionResult,
23-
GroupSingleEntityAction,
24-
GroupSingleEntityActionResult,
21+
ProjectScopeAction,
22+
ProjectScopeActionResult,
23+
ProjectSingleEntityAction,
24+
ProjectSingleEntityActionResult,
2525
)
2626

2727

@@ -42,7 +42,7 @@ def operation_type(cls) -> ActionOperationType:
4242

4343

4444
@dataclass
45-
class SearchProjectsByDomainAction(GroupScopeAction):
45+
class SearchProjectsByDomainAction(ProjectScopeAction):
4646
"""Search projects within a domain."""
4747

4848
scope: DomainProjectSearchScope
@@ -67,7 +67,7 @@ def target_element(self) -> RBACElementRef:
6767

6868

6969
@dataclass
70-
class SearchProjectsByUserAction(GroupScopeAction):
70+
class SearchProjectsByUserAction(ProjectScopeAction):
7171
"""Search projects a user is member of."""
7272

7373
scope: UserProjectSearchScope
@@ -92,7 +92,7 @@ def target_element(self) -> RBACElementRef:
9292

9393

9494
@dataclass
95-
class GetProjectAction(GroupSingleEntityAction):
95+
class GetProjectAction(ProjectSingleEntityAction):
9696
"""Get a single project by UUID."""
9797

9898
project_id: UUID
@@ -129,7 +129,7 @@ def entity_id(self) -> str | None:
129129

130130

131131
@dataclass
132-
class ScopedSearchProjectsActionResult(GroupScopeActionResult):
132+
class ScopedSearchProjectsActionResult(ProjectScopeActionResult):
133133
"""Result from searching projects within a scope."""
134134

135135
items: list[GroupData]
@@ -149,7 +149,7 @@ def scope_id(self) -> str:
149149

150150

151151
@dataclass
152-
class GetProjectActionResult(GroupSingleEntityActionResult):
152+
class GetProjectActionResult(ProjectSingleEntityActionResult):
153153
"""Result from getting a single project."""
154154

155155
data: GroupData

src/ai/backend/manager/services/group/processors.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,20 @@ def __init__(
6464
action_monitors: list[ActionMonitor],
6565
validators: ActionValidators,
6666
) -> None:
67-
self.create_group = ScopeActionProcessor(group_service.create_group, action_monitors)
68-
self.modify_group = SingleEntityActionProcessor(group_service.modify_group, action_monitors)
69-
self.delete_group = SingleEntityActionProcessor(group_service.delete_group, action_monitors)
70-
self.purge_group = SingleEntityActionProcessor(group_service.purge_group, action_monitors)
67+
rbac_scope_validators = [validators.rbac.scope]
68+
rbac_single_entity_validators = [validators.rbac.single_entity]
69+
self.create_group = ScopeActionProcessor(
70+
group_service.create_group, action_monitors, validators=rbac_scope_validators
71+
)
72+
self.modify_group = SingleEntityActionProcessor(
73+
group_service.modify_group, action_monitors, validators=rbac_single_entity_validators
74+
)
75+
self.delete_group = SingleEntityActionProcessor(
76+
group_service.delete_group, action_monitors, validators=rbac_single_entity_validators
77+
)
78+
self.purge_group = SingleEntityActionProcessor(
79+
group_service.purge_group, action_monitors, validators=rbac_single_entity_validators
80+
)
7181
self.usage_per_month = ActionProcessor(group_service.usage_per_month, action_monitors)
7282
self.usage_per_period = ActionProcessor(group_service.usage_per_period, action_monitors)
7383
self.search_projects = ActionProcessor(group_service.search_projects, action_monitors)
@@ -77,7 +87,9 @@ def __init__(
7787
self.search_projects_by_user = ScopeActionProcessor(
7888
group_service.search_projects_by_user, action_monitors
7989
)
80-
self.get_project = SingleEntityActionProcessor(group_service.get_project, action_monitors)
90+
self.get_project = SingleEntityActionProcessor(
91+
group_service.get_project, action_monitors, validators=rbac_single_entity_validators
92+
)
8193

8294
@override
8395
def supported_actions(self) -> list[ActionSpec]:

0 commit comments

Comments
 (0)