Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions cognite/client/data_classes/capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,15 @@ def as_tuples(self) -> set[tuple[str, str]]:
return {(self._scope_name, s) for s in self.external_ids}


@dataclass(frozen=True)
class AppExternalIdScope(Capability.Scope):
_scope_name = "appExternalIdScope"
external_ids: list[str]

def as_tuples(self) -> set[tuple[str, str]]:
return {(self._scope_name, s) for s in self.external_ids}
Comment on lines +545 to +551

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

To ensure type safety and prevent comparison failures in compare_capabilities (e.g., if external IDs are parsed as integers or other types), convert external_ids to strings in a __post_init__ method. This is consistent with other scopes like PostgresGatewayUsersScope and DataSetScope.

Suggested change
@dataclass(frozen=True)
class AppExternalIdScope(Capability.Scope):
_scope_name = "appExternalIdScope"
external_ids: list[str]
def as_tuples(self) -> set[tuple[str, str]]:
return {(self._scope_name, s) for s in self.external_ids}
@dataclass(frozen=True)
class AppExternalIdScope(Capability.Scope):
_scope_name = "appExternalIdScope"
external_ids: list[str]
def __post_init__(self) -> None:
object.__setattr__(self, "external_ids", [str(i) for i in self.external_ids])
def as_tuples(self) -> set[tuple[str, str]]:
return {(self._scope_name, s) for s in self.external_ids}
References
  1. Consistency: Follow established patterns across the codebase (e.g., converting list elements to their expected type in post_init as done in other scopes like PostgresGatewayUsersScope and DataSetScope). (link)



@dataclass(frozen=True)
class UnknownScope(Capability.Scope):
"""
Expand Down Expand Up @@ -1443,6 +1452,68 @@ class Scope:
All = AllScope


@dataclass
class AppHostingAcl(Capability):
_capability_name = "appHostingAcl"
actions: Sequence[Action]
scope: AllScope | AppExternalIdScope

class Action(Capability.Action): # type: ignore [misc]
Read = "READ"
Write = "WRITE"
Run = "RUN"

class Scope:
All = AllScope
AppExternalId = AppExternalIdScope


@dataclass
class ChartsAdminAcl(Capability):
_capability_name = "chartsAdminAcl"
actions: Sequence[Action]
scope: AllScope = field(default_factory=AllScope)

class Action(Capability.Action): # type: ignore [misc]
Read = "READ"
Update = "UPDATE"
Delete = "DELETE"

class Scope:
All = AllScope


@dataclass
class CogUnitsAcl(Capability):
_capability_name = "cogUnitsAcl"
actions: Sequence[Action]
scope: AllScope = field(default_factory=AllScope)

class Action(Capability.Action): # type: ignore [misc]
Read = "READ"

class Scope:
All = AllScope


@dataclass
class SimulatorsAcl(Capability):
_capability_name = "simulatorsAcl"
actions: Sequence[Action]
scope: AllScope | DataSetScope

class Action(Capability.Action): # type: ignore [misc]
Read = "READ"
Write = "WRITE"
Delete = "DELETE"
Run = "RUN"
Manage = "MANAGE"

class Scope:
All = AllScope
DataSet = DataSetScope


@dataclass
class LegacyModelHostingAcl(LegacyCapability):
_capability_name = "modelHostingAcl"
Expand Down
17 changes: 17 additions & 0 deletions tests/tests_unit/test_data_classes/test_capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,16 @@ def all_acls() -> Iterator[dict[str, Any]]:
{"assetsAcl": {"actions": ["READ", "WRITE"], "scope": {"datasetScope": {"ids": ["372"]}}}},
{"appConfigAcl": {"actions": ["READ", "WRITE"], "scope": {"all": {}}}},
{"appConfigAcl": {"actions": ["READ", "WRITE"], "scope": {"appScope": {"apps": ["SEARCH"]}}}},
{"appHostingAcl": {"actions": ["READ", "WRITE", "RUN"], "scope": {"all": {}}}},
{
"appHostingAcl": {
"actions": ["READ"],
"scope": {"appExternalIdScope": {"externalIds": ["my-app", "other-app"]}},
}
},
{"auditlogAcl": {"actions": ["READ"], "scope": {"all": {}}}},
{"chartsAdminAcl": {"actions": ["READ", "UPDATE", "DELETE"], "scope": {"all": {}}}},
{"cogUnitsAcl": {"actions": ["READ"], "scope": {"all": {}}}},
{"dataModelInstancesAcl": {"actions": ["READ", "WRITE"], "scope": {"all": {}}}},
{"dataModelInstancesAcl": {"actions": ["READ"], "scope": {"spaceScope": {"externalIds": ["maintain"]}}}},
{
Expand Down Expand Up @@ -141,6 +150,8 @@ def all_acls() -> Iterator[dict[str, Any]]:
{"sequencesAcl": {"actions": ["READ"], "scope": {"all": {}}}},
{"sequencesAcl": {"actions": ["WRITE"], "scope": {"datasetScope": {"ids": ["2332579", "372"]}}}},
{"sessionsAcl": {"actions": ["LIST", "CREATE", "DELETE"], "scope": {"all": {}}}},
{"simulatorsAcl": {"actions": ["READ", "WRITE", "DELETE", "RUN", "MANAGE"], "scope": {"all": {}}}},
{"simulatorsAcl": {"actions": ["READ", "WRITE"], "scope": {"datasetScope": {"ids": ["123", "456"]}}}},
{"streamsAcl": {"actions": ["READ"], "scope": {"all": {}}}},
{"streamsAcl": {"actions": ["CREATE", "DELETE"], "scope": {"all": {}}}},
{"streamRecordsAcl": {"actions": ["READ", "WRITE"], "scope": {"all": {}}}},
Expand Down Expand Up @@ -248,6 +259,12 @@ def test_loads_to_known(self, access_control: dict[str, Any]) -> None:
"scope": {"spaceIdScope": {"spaceIds": ["analytics-space", "prod-space"]}},
}
},
{
"appHostingAcl": {
"actions": ["READ", "RUN"],
"scope": {"appExternalIdScope": {"externalIds": ["my-app", "other-app"]}},
}
},
],
)
def test_load_dump(self, raw: dict[str, Any]) -> None:
Expand Down
Loading