diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bbd8ffa2c..774b940ffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ Changes are grouped as follows ### Fixed - The new compare methods for capabilities in major version 7, `IAMAPI.verify_capabilities` and `IAMAPI.compare_capabilities` now works correctly for rawAcl with database scope ("all tables"). +### Removed +- Capability scopes no longer have the `is_within` method, and capabilities no longer have `has_capability`. Use the more + general `IAMAPI.compare_capabilities` instead. ## [7.2.0] - 2023-11-16 ### Added diff --git a/cognite/client/data_classes/capabilities.py b/cognite/client/data_classes/capabilities.py index a63f0bcb43..7d75740cb4 100644 --- a/cognite/client/data_classes/capabilities.py +++ b/cognite/client/data_classes/capabilities.py @@ -98,9 +98,6 @@ def as_tuples(self) -> set[tuple]: # Basic implementation for all simple Scopes (e.g. all or currentuser) return {(self._scope_name,)} - def is_within(self, other: Self) -> bool: - raise NotImplementedError - @classmethod def from_tuple(cls, tpl: tuple) -> Self: acl_name, action, scope_name, *scope_params = tpl @@ -115,7 +112,7 @@ def from_tuple(cls, tpl: tuple) -> Self: db, tbl = scope_params scope = scope_cls({db: [tbl] if tbl else []}) # type: ignore [call-arg] else: - raise ValueError(f"tuple not understood as capability ({tpl})") + raise ValueError(f"tuple not understood as capability: {tpl}") return cast(Self, capability_cls(actions=[capability_cls.Action(action)], scope=scope)) @@ -162,13 +159,6 @@ def dump(self, camel_case: bool = True) -> dict[str, Any]: capability_name = self._capability_name return {to_camel_case(capability_name) if camel_case else to_snake_case(capability_name): data} - def has_capability(self, other: Capability) -> bool: - if not isinstance(self, type(other)): - return False - if not other.scope.is_within(self.scope): - return False - return not set(other.actions) - set(self.actions) - def as_tuples(self) -> set[tuple]: return set( (acl, action, *scope_tpl) @@ -262,17 +252,11 @@ def as_tuples(self, project: str | None = None) -> set[tuple]: class AllScope(Capability.Scope): _scope_name = "all" - def is_within(self, other: Self) -> bool: - return isinstance(other, AllScope) - @dataclass(frozen=True) class CurrentUserScope(Capability.Scope): _scope_name = "currentuserscope" - def is_within(self, other: Self) -> bool: - return isinstance(other, (AllScope, CurrentUserScope)) - @dataclass(frozen=True) class IDScope(Capability.Scope): @@ -285,9 +269,6 @@ def __post_init__(self) -> None: def as_tuples(self) -> set[tuple]: return {(self._scope_name, i) for i in self.ids} - def is_within(self, other: Self) -> bool: - return isinstance(other, AllScope) or type(self) is type(other) and set(self.ids).issubset(other.ids) - @dataclass(frozen=True) class IDScopeLowerCase(Capability.Scope): @@ -302,9 +283,6 @@ def __post_init__(self) -> None: def as_tuples(self) -> set[tuple]: return {(self._scope_name, i) for i in self.ids} - def is_within(self, other: Self) -> bool: - return isinstance(other, AllScope) or type(self) is type(other) and set(self.ids).issubset(other.ids) - @dataclass(frozen=True) class ExtractionPipelineScope(Capability.Scope): @@ -317,9 +295,6 @@ def __post_init__(self) -> None: def as_tuples(self) -> set[tuple]: return {(self._scope_name, i) for i in self.ids} - def is_within(self, other: Self) -> bool: - return isinstance(other, AllScope) or type(self) is type(other) and set(self.ids).issubset(other.ids) - @dataclass(frozen=True) class DataSetScope(Capability.Scope): @@ -332,9 +307,6 @@ def __post_init__(self) -> None: def as_tuples(self) -> set[tuple]: return {(self._scope_name, i) for i in self.ids} - def is_within(self, other: Self) -> bool: - return isinstance(other, AllScope) or type(self) is type(other) and set(self.ids).issubset(other.ids) - @dataclass(frozen=True) class TableScope(Capability.Scope): @@ -361,19 +333,6 @@ def as_tuples(self) -> set[tuple]: # character, we represent this internally with the empty string: return {(self._scope_name, db, tbl) for db, tables in self.dbs_to_tables.items() for tbl in tables or [""]} - def is_within(self, other: Self) -> bool: - if isinstance(other, AllScope): - return True - if not isinstance(other, TableScope): - return False - - for db_name, tables in self.dbs_to_tables.items(): - if (other_tables := other.dbs_to_tables.get(db_name)) is None: - return False - if not set(tables).issubset(other_tables): - return False - return True - @dataclass(frozen=True) class AssetRootIDScope(Capability.Scope): @@ -386,9 +345,6 @@ def __post_init__(self) -> None: def as_tuples(self) -> set[tuple]: return {(self._scope_name, i) for i in self.root_ids} - def is_within(self, other: Self) -> bool: - return isinstance(other, AllScope) or type(self) is type(other) and set(self.root_ids).issubset(other.root_ids) - @dataclass(frozen=True) class ExperimentsScope(Capability.Scope): @@ -398,13 +354,6 @@ class ExperimentsScope(Capability.Scope): def as_tuples(self) -> set[tuple]: return {(self._scope_name, s) for s in self.experiments} - def is_within(self, other: Self) -> bool: - return ( - isinstance(other, AllScope) - or type(self) is type(other) - and set(self.experiments).issubset(other.experiments) - ) - @dataclass(frozen=True) class SpaceIDScope(Capability.Scope): @@ -414,11 +363,6 @@ class SpaceIDScope(Capability.Scope): def as_tuples(self) -> set[tuple]: return {(self._scope_name, s) for s in self.space_ids} - def is_within(self, other: Self) -> bool: - return ( - isinstance(other, AllScope) or type(self) is type(other) and set(self.space_ids).issubset(other.space_ids) - ) - @dataclass(frozen=True) class UnknownScope(Capability.Scope): @@ -436,9 +380,6 @@ def __getitem__(self, item: str) -> Any: def as_tuples(self) -> set[tuple]: raise NotImplementedError("Unknown scope cannot be converted to tuples (needed for comparisons)") - def is_within(self, other: Self) -> bool: - raise NotImplementedError("Unknown scope cannot be compared") - _SCOPE_CLASS_BY_NAME: MappingProxyType[str, type[Capability.Scope]] = MappingProxyType( {c._scope_name: c for c in Capability.Scope.__subclasses__() if not issubclass(c, UnknownScope)}