Skip to content

Commit

Permalink
rename all
Browse files Browse the repository at this point in the history
  • Loading branch information
fregataa committed Jun 28, 2024
1 parent 0cfd3f5 commit c1c79fb
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 137 deletions.
1 change: 1 addition & 0 deletions src/ai/backend/manager/models/rbac/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python_sources()
92 changes: 45 additions & 47 deletions src/ai/backend/manager/models/rbac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,24 @@


__all__: Sequence[str] = (
"BaseACLPermission",
"BasePermission",
"ClientContext",
"DomainScope",
"ProjectScope",
"UserScope",
"StorageHost",
"ImageRegistry",
"ScalingGroup",
"AbstractACLPermissionContext",
"AbstractACLPermissionContextBuilder",
"AbstractPermissionContext",
"AbstractPermissionContextBuilder",
)


class BaseACLPermission(enum.StrEnum):
class BasePermission(enum.StrEnum):
pass


ACLPermissionType = TypeVar("ACLPermissionType", bound=BaseACLPermission)
PermissionType = TypeVar("PermissionType", bound=BasePermission)


class Bypass(enum.Enum):
Expand Down Expand Up @@ -127,97 +127,97 @@ async def _get_or_init_project_ctx(self, db_session: AsyncSession) -> ProjectCon
return self._project_ctx


class BaseACLScope(metaclass=ABCMeta):
class BaseScope(metaclass=ABCMeta):
@abstractmethod
def __str__(self) -> str:
pass


@dataclass(frozen=True)
class DomainScope(BaseACLScope):
class DomainScope(BaseScope):
domain_name: str

def __str__(self) -> str:
return f"Domain(name: {self.domain_name})"


@dataclass(frozen=True)
class ProjectScope(BaseACLScope):
class ProjectScope(BaseScope):
project_id: uuid.UUID

def __str__(self) -> str:
return f"Project(id: {self.project_id})"


@dataclass(frozen=True)
class UserScope(BaseACLScope):
class UserScope(BaseScope):
user_id: uuid.UUID

def __str__(self) -> str:
return f"User(id: {self.user_id})"


# Extra ACL scope is to address some scopes that contain specific object types
# Extra scope is to address some scopes that contain specific object types
# such as registries for images, scaling groups for agents, storage hosts for vfolders etc.
class ExtraACLScope:
class ExtraScope:
pass


@dataclass(frozen=True)
class StorageHost(ExtraACLScope):
class StorageHost(ExtraScope):
name: str


@dataclass(frozen=True)
class ImageRegistry(ExtraACLScope):
class ImageRegistry(ExtraScope):
name: str


@dataclass(frozen=True)
class ScalingGroup(ExtraACLScope):
class ScalingGroup(ExtraScope):
name: str


ACLObjectType = TypeVar("ACLObjectType")
ACLObjectIDType = TypeVar("ACLObjectIDType")
ObjectType = TypeVar("ObjectType")
ObjectIDType = TypeVar("ObjectIDType")


@dataclass
class AbstractACLPermissionContext(
Generic[ACLPermissionType, ACLObjectType, ACLObjectIDType], metaclass=ABCMeta
class AbstractPermissionContext(
Generic[PermissionType, ObjectType, ObjectIDType], metaclass=ABCMeta
):
"""
Define ACL permissions under given User, Project or Domain scopes.
Define permissions under given User, Project or Domain scopes.
Each field of this class represents a mapping of ["accessible scope id", "permissions under the scope"].
For example, `project` field has a mapping of ["accessible project id", "permissions under the project"].
{
"PROJECT_A_ID": {"READ", "WRITE", "DELETE"}
"PROJECT_B_ID": {"READ"}
}
`additional` and `overriding` fields have a mapping of ["ACL object id", "permissions applied to the object"].
`additional` field is used to add permissions to specific ACL objects. It can be used for admins.
`additional` and `overriding` fields have a mapping of ["object id", "permissions applied to the object"].
`additional` field is used to add permissions to specific objects. It can be used for admins.
`overriding` field is used to address exceptional cases such as permission overriding or cover other scopes(scaling groups or storage hosts etc).
"""

user_id_to_permission_map: Mapping[uuid.UUID, frozenset[ACLPermissionType]] = field(
user_id_to_permission_map: Mapping[uuid.UUID, frozenset[PermissionType]] = field(
default_factory=dict
)
project_id_to_permission_map: Mapping[uuid.UUID, frozenset[ACLPermissionType]] = field(
project_id_to_permission_map: Mapping[uuid.UUID, frozenset[PermissionType]] = field(
default_factory=dict
)
domain_name_to_permission_map: Mapping[str, frozenset[ACLPermissionType]] = field(
domain_name_to_permission_map: Mapping[str, frozenset[PermissionType]] = field(
default_factory=dict
)

object_id_to_additional_permission_map: Mapping[
ACLObjectIDType, frozenset[ACLPermissionType]
] = field(default_factory=dict)
object_id_to_overriding_permission_map: Mapping[
ACLObjectIDType, frozenset[ACLPermissionType]
] = field(default_factory=dict)
object_id_to_additional_permission_map: Mapping[ObjectIDType, frozenset[PermissionType]] = (
field(default_factory=dict)
)
object_id_to_overriding_permission_map: Mapping[ObjectIDType, frozenset[PermissionType]] = (
field(default_factory=dict)
)

def filter_by_permission(self, permission_to_include: ACLPermissionType) -> None:
def filter_by_permission(self, permission_to_include: PermissionType) -> None:
self.user_id_to_permission_map = {
uid: permissions
for uid, permissions in self.user_id_to_permission_map.items()
Expand Down Expand Up @@ -249,30 +249,28 @@ async def build_query(self) -> sa.sql.Select | None:
pass

@abstractmethod
async def calculate_final_permission(
self, acl_obj: ACLObjectType
) -> frozenset[ACLPermissionType]:
async def calculate_final_permission(self, acl_obj: ObjectType) -> frozenset[PermissionType]:
"""
Calculate the final permissions applied to the given ACL object based on the fields in this class.
Calculate the final permissions applied to the given object based on the fields in this class.
"""
pass


ACLPermissionContextType = TypeVar("ACLPermissionContextType", bound=AbstractACLPermissionContext)
PermissionContextType = TypeVar("PermissionContextType", bound=AbstractPermissionContext)


class AbstractACLPermissionContextBuilder(
Generic[ACLPermissionType, ACLPermissionContextType], metaclass=ABCMeta
class AbstractPermissionContextBuilder(
Generic[PermissionType, PermissionContextType], metaclass=ABCMeta
):
@classmethod
async def build(
cls,
db_session: AsyncSession,
ctx: ClientContext,
target_scope: BaseACLScope,
target_scope: BaseScope,
*,
permission: ACLPermissionType | None = None,
) -> ACLPermissionContextType:
permission: PermissionType | None = None,
) -> PermissionContextType:
match target_scope:
case UserScope(user_id=user_id):
result = await cls._build_in_user_scope(db_session, ctx, user_id)
Expand All @@ -281,7 +279,7 @@ async def build(
case DomainScope(domain_name=domain_name):
result = await cls._build_in_domain_scope(db_session, ctx, domain_name)
case _:
raise RuntimeError(f"invalid ACL scope `{target_scope}`")
raise RuntimeError(f"invalid scope `{target_scope}`")
if permission is not None:
result.filter_by_permission(permission)
return result
Expand All @@ -293,7 +291,7 @@ async def _build_in_user_scope(
db_session: AsyncSession,
ctx: ClientContext,
user_id: uuid.UUID,
) -> ACLPermissionContextType:
) -> PermissionContextType:
pass

@classmethod
Expand All @@ -303,7 +301,7 @@ async def _build_in_project_scope(
db_session: AsyncSession,
ctx: ClientContext,
project_id: uuid.UUID,
) -> ACLPermissionContextType:
) -> PermissionContextType:
pass

@classmethod
Expand All @@ -313,5 +311,5 @@ async def _build_in_domain_scope(
db_session: AsyncSession,
ctx: ClientContext,
domain_name: str,
) -> ACLPermissionContextType:
) -> PermissionContextType:
pass
1 change: 0 additions & 1 deletion src/ai/backend/manager/models/rbac/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

class RBACException(Exception):
pass

Expand Down
Loading

0 comments on commit c1c79fb

Please sign in to comment.