Skip to content
1 change: 1 addition & 0 deletions changes/11456.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `vfolder:data`, `session:app_service`, and `user:email` RBAC element types as sub-entities of vfolder, session, and user, enabling fine-grained permission control over vfolder internal data, session app endpoints, and user email exposure separately from their parent entities.
3 changes: 3 additions & 0 deletions docs/manager/graphql-reference/supergraph.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -14470,6 +14470,9 @@ enum RBACElementType
DEPLOYMENT_REVISION @join__enumValue(graph: STRAWBERRY)
IMAGE_ALIAS @join__enumValue(graph: STRAWBERRY)
ROLE_ASSIGNMENT @join__enumValue(graph: STRAWBERRY)
VFOLDER_DATA @join__enumValue(graph: STRAWBERRY)
SESSION_APP_SERVICE @join__enumValue(graph: STRAWBERRY)
USER_EMAIL @join__enumValue(graph: STRAWBERRY)
ARTIFACT_REVISION @join__enumValue(graph: STRAWBERRY)
}

Expand Down
3 changes: 3 additions & 0 deletions docs/manager/graphql-reference/v2-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -9549,6 +9549,9 @@ enum RBACElementType {
DEPLOYMENT_REVISION
IMAGE_ALIAS
ROLE_ASSIGNMENT
VFOLDER_DATA
SESSION_APP_SERVICE
USER_EMAIL
ARTIFACT_REVISION
}

Expand Down
200 changes: 200 additions & 0 deletions fixtures/manager/example-roles.json
Comment thread
fregataa marked this conversation as resolved.
Comment thread
fregataa marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -5917,6 +5917,206 @@
"scope_id": "dfa9da54-4b28-432f-be29-c0d680c7a412",
"entity_type": "model_card",
"operation": "hard-delete"
},
{
"id": "42928b17-47a8-5104-9d31-777876b73e17",
"role_id": "31f74f6d-04f7-418b-b375-ab0c39fa3058",
"scope_type": "user",
"scope_id": "009fb1a4-487c-4f6e-9b1b-228b94b1d040",
"entity_type": "vfolder:data",
"operation": "create"
},
{
"id": "298d7a45-7241-5b05-8704-4c49085b49c2",
"role_id": "31f74f6d-04f7-418b-b375-ab0c39fa3058",
"scope_type": "user",
"scope_id": "009fb1a4-487c-4f6e-9b1b-228b94b1d040",
"entity_type": "vfolder:data",
"operation": "read"
},
{
"id": "f1c340e5-730d-58e9-af76-30f14db63c70",
"role_id": "31f74f6d-04f7-418b-b375-ab0c39fa3058",
"scope_type": "user",
"scope_id": "009fb1a4-487c-4f6e-9b1b-228b94b1d040",
"entity_type": "vfolder:data",
"operation": "update"
},
{
"id": "258a9bae-2932-52ae-b93a-81240f0ad50b",
"role_id": "31f74f6d-04f7-418b-b375-ab0c39fa3058",
"scope_type": "user",
"scope_id": "009fb1a4-487c-4f6e-9b1b-228b94b1d040",
"entity_type": "vfolder:data",
"operation": "hard-delete"
},
{
"id": "a29a386e-4552-52d5-9f28-d1cf7d2e757b",
"role_id": "5e96b4ee-2296-495b-90b4-0fc845d13c67",
"scope_type": "user",
"scope_id": "2e10157d-20ca-4bd0-9806-3f909cbcd0e6",
"entity_type": "vfolder:data",
"operation": "create"
},
{
"id": "fdb1b976-e998-5767-998a-4889d7b03bb3",
"role_id": "5e96b4ee-2296-495b-90b4-0fc845d13c67",
"scope_type": "user",
"scope_id": "2e10157d-20ca-4bd0-9806-3f909cbcd0e6",
"entity_type": "vfolder:data",
"operation": "read"
},
{
"id": "082685f6-b886-5bfd-8d61-462325ae63b9",
"role_id": "5e96b4ee-2296-495b-90b4-0fc845d13c67",
"scope_type": "user",
"scope_id": "2e10157d-20ca-4bd0-9806-3f909cbcd0e6",
"entity_type": "vfolder:data",
"operation": "update"
},
{
"id": "26f01d75-8ff9-5093-aae4-bd9606d71c37",
"role_id": "5e96b4ee-2296-495b-90b4-0fc845d13c67",
"scope_type": "user",
"scope_id": "2e10157d-20ca-4bd0-9806-3f909cbcd0e6",
"entity_type": "vfolder:data",
"operation": "hard-delete"
},
{
"id": "8a9a1171-99f4-5e6f-9eea-cf475bb63578",
"role_id": "72293d83-1849-4bb5-a555-80e561515428",
"scope_type": "user",
"scope_id": "f38dea23-50fa-42a0-b5ae-338f5f4693f4",
"entity_type": "vfolder:data",
"operation": "create"
},
{
"id": "38e9d60b-b7ab-5237-a098-7b6d1be2bc13",
"role_id": "72293d83-1849-4bb5-a555-80e561515428",
"scope_type": "user",
"scope_id": "f38dea23-50fa-42a0-b5ae-338f5f4693f4",
"entity_type": "vfolder:data",
"operation": "read"
},
{
"id": "4a370c27-02f3-5628-a4a7-03427f60a00d",
"role_id": "72293d83-1849-4bb5-a555-80e561515428",
"scope_type": "user",
"scope_id": "f38dea23-50fa-42a0-b5ae-338f5f4693f4",
"entity_type": "vfolder:data",
"operation": "update"
},
{
"id": "70a25037-e38a-5625-9bdf-f11882848093",
"role_id": "72293d83-1849-4bb5-a555-80e561515428",
"scope_type": "user",
"scope_id": "f38dea23-50fa-42a0-b5ae-338f5f4693f4",
"entity_type": "vfolder:data",
"operation": "hard-delete"
},
{
"id": "48351095-c95f-5d26-a33e-cbe5236660e8",
"role_id": "cb0768f1-3b35-415d-beef-8916a5c3c88b",
"scope_type": "user",
"scope_id": "4f13d193-f646-425a-a340-270c4d2b9860",
"entity_type": "vfolder:data",
"operation": "create"
},
{
"id": "0f38fd3b-138c-5192-8089-40210da1a137",
"role_id": "cb0768f1-3b35-415d-beef-8916a5c3c88b",
"scope_type": "user",
"scope_id": "4f13d193-f646-425a-a340-270c4d2b9860",
"entity_type": "vfolder:data",
"operation": "read"
},
{
"id": "de08c1e4-c29e-5e64-91ce-0f797bf4a0d9",
"role_id": "cb0768f1-3b35-415d-beef-8916a5c3c88b",
"scope_type": "user",
"scope_id": "4f13d193-f646-425a-a340-270c4d2b9860",
"entity_type": "vfolder:data",
"operation": "update"
},
{
"id": "b51c9fd6-77a0-5db3-a011-b005b005bab8",
"role_id": "cb0768f1-3b35-415d-beef-8916a5c3c88b",
"scope_type": "user",
"scope_id": "4f13d193-f646-425a-a340-270c4d2b9860",
"entity_type": "vfolder:data",
"operation": "hard-delete"
},
{
"id": "924a0737-208e-56ee-a408-d5761e0afd05",
"role_id": "fe53e90e-f619-43d8-99c8-574487485bab",
"scope_type": "user",
"scope_id": "dfa9da54-4b28-432f-be29-c0d680c7a412",
"entity_type": "vfolder:data",
"operation": "create"
},
{
"id": "8f24e0d6-f716-5248-8822-e9bd50bc60ed",
"role_id": "fe53e90e-f619-43d8-99c8-574487485bab",
"scope_type": "user",
"scope_id": "dfa9da54-4b28-432f-be29-c0d680c7a412",
"entity_type": "vfolder:data",
"operation": "read"
},
{
"id": "ebae171c-3bdc-5007-944d-9ef3c11b1436",
"role_id": "fe53e90e-f619-43d8-99c8-574487485bab",
"scope_type": "user",
"scope_id": "dfa9da54-4b28-432f-be29-c0d680c7a412",
"entity_type": "vfolder:data",
"operation": "update"
},
{
"id": "e0d7b8de-9335-5efa-951c-3da25007b8dc",
"role_id": "fe53e90e-f619-43d8-99c8-574487485bab",
"scope_type": "user",
"scope_id": "dfa9da54-4b28-432f-be29-c0d680c7a412",
"entity_type": "vfolder:data",
"operation": "hard-delete"
},
{
"id": "444a9916-e4be-5659-b9b8-23229d134236",
"role_id": "31f74f6d-04f7-418b-b375-ab0c39fa3058",
"scope_type": "user",
"scope_id": "009fb1a4-487c-4f6e-9b1b-228b94b1d040",
"entity_type": "session:app_service",
"operation": "read"
},
{
"id": "1a0a057e-2225-54c8-b1e0-2973d025b621",
"role_id": "5e96b4ee-2296-495b-90b4-0fc845d13c67",
"scope_type": "user",
"scope_id": "2e10157d-20ca-4bd0-9806-3f909cbcd0e6",
"entity_type": "session:app_service",
"operation": "read"
},
{
"id": "2505e7eb-95ea-5c29-816f-82fea3eceb54",
"role_id": "72293d83-1849-4bb5-a555-80e561515428",
"scope_type": "user",
"scope_id": "f38dea23-50fa-42a0-b5ae-338f5f4693f4",
"entity_type": "session:app_service",
"operation": "read"
},
{
"id": "a1a9a02f-3a48-5e88-8765-ad778a02ba3d",
"role_id": "cb0768f1-3b35-415d-beef-8916a5c3c88b",
"scope_type": "user",
"scope_id": "4f13d193-f646-425a-a340-270c4d2b9860",
"entity_type": "session:app_service",
"operation": "read"
},
{
"id": "8daeb1ab-977d-5612-86f9-c43607379f3b",
"role_id": "fe53e90e-f619-43d8-99c8-574487485bab",
"scope_type": "user",
"scope_id": "dfa9da54-4b28-432f-be29-c0d680c7a412",
"entity_type": "session:app_service",
"operation": "read"
}
],
"association_scopes_entities": [
Expand Down
34 changes: 32 additions & 2 deletions src/ai/backend/common/data/permission/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class EntityType(enum.StrEnum):
VFOLDER_FILE = "vfolder:file"
VFOLDER_DIRECTORY = "vfolder:directory"
VFOLDER_INVITATION = "vfolder:invitation"
VFOLDER_DATA = "vfolder:data"
# Resource group sub
RESOURCE_GROUP_DOMAIN = "resource_group:domain"
RESOURCE_GROUP_KEYPAIR = "resource_group:keypair"
Expand Down Expand Up @@ -227,6 +228,7 @@ class EntityType(enum.StrEnum):
GROUP_USAGE = "group:usage"
# User sub
USER_STATS = "user:stats"
USER_EMAIL = "user:email"
# Agent sub
AGENT_WATCHER = "agent:watcher"
AGENT_REGISTRY = "agent:registry"
Expand Down Expand Up @@ -417,6 +419,14 @@ class RBACElementType(enum.StrEnum):
IMAGE_ALIAS = "image:alias"
ROLE_ASSIGNMENT = "role:assignment"

# === Sub-entity permissions split from parent metadata access ===
# These split permission control of a parent entity into sub-aspects so that
# access to listings/detail (parent) and access to internal data or
# sub-operations (child) can be granted independently.
VFOLDER_DATA = "vfolder:data"
SESSION_APP_SERVICE = "session:app_service"
USER_EMAIL = "user:email"

# === Entity-level scopes (for entity-scope permissions) ===
ARTIFACT_REVISION = "artifact_revision"

Expand Down Expand Up @@ -478,8 +488,25 @@ class RelationType(enum.StrEnum):
_DEFAULT_OWNER_OPS: frozenset[OperationType] = _STANDARD_OPS
_DEFAULT_MEMBER_OPS: frozenset[OperationType] = _READ_ONLY_OPS

_ADMIN_OPS_OVERRIDES: Mapping[RBACElementType, frozenset[OperationType]] = {}
_OWNER_OPS_OVERRIDES: Mapping[RBACElementType, frozenset[OperationType]] = {}
# vfolder:data CRUD on internal files/directories — soft-delete is intentionally
# omitted because there is no two-stage delete for vfolder data.
_VFOLDER_DATA_OWNER_OPS: frozenset[OperationType] = frozenset({
OperationType.CREATE,
OperationType.READ,
OperationType.UPDATE,
OperationType.HARD_DELETE,
})

_ADMIN_OPS_OVERRIDES: Mapping[RBACElementType, frozenset[OperationType]] = {
# vfolder:data and session:app_service are owner-only — admins of the parent scope
# have access to listings/metadata but not to internal data or app endpoints.
RBACElementType.VFOLDER_DATA: frozenset(),
RBACElementType.SESSION_APP_SERVICE: frozenset(),
}
_OWNER_OPS_OVERRIDES: Mapping[RBACElementType, frozenset[OperationType]] = {
RBACElementType.VFOLDER_DATA: _VFOLDER_DATA_OWNER_OPS,
RBACElementType.SESSION_APP_SERVICE: _READ_ONLY_OPS,
}
_MEMBER_OPS_OVERRIDES: Mapping[RBACElementType, frozenset[OperationType]] = {
# Members of a project may create their own sessions, vfolders,
# and model deployments (a.k.a. model services).
Expand All @@ -489,6 +516,9 @@ class RelationType(enum.StrEnum):
OperationType.READ,
OperationType.CREATE,
}),
# Owner-only sub-entities — members of the parent scope have no access.
RBACElementType.VFOLDER_DATA: frozenset(),
RBACElementType.SESSION_APP_SERVICE: frozenset(),
}


Expand Down
5 changes: 5 additions & 0 deletions src/ai/backend/common/dto/manager/v2/rbac/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ class RBACElementTypeDTO(StrEnum):
IMAGE_ALIAS = "image:alias"
ROLE_ASSIGNMENT = "role:assignment"

# Sub-entity permissions split from parent metadata access
VFOLDER_DATA = "vfolder:data"
SESSION_APP_SERVICE = "session:app_service"
USER_EMAIL = "user:email"

# Entity-level scopes
ARTIFACT_REVISION = "artifact_revision"

Expand Down
3 changes: 3 additions & 0 deletions src/ai/backend/manager/api/gql/rbac/types/permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ async def scope(
| RBACElementType.PROJECT_ADMIN_PAGE
| RBACElementType.DOMAIN_ADMIN_PAGE
| RBACElementType.ROLE_ASSIGNMENT
| RBACElementType.VFOLDER_DATA
| RBACElementType.SESSION_APP_SERVICE
| RBACElementType.USER_EMAIL
):
return None

Expand Down
Loading
Loading