clear-skies-cortex 2.0.3__tar.gz → 2.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.copier-answers.yml +1 -1
  2. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.github/workflows/docs.yaml +2 -0
  3. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/CHANGELOG.md +11 -0
  4. clear_skies_cortex-2.0.4/LATEST_CHANGELOG.md +9 -0
  5. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/PKG-INFO +1 -1
  6. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/pyproject.toml +4 -1
  7. clear_skies_cortex-2.0.4/src/clearskies_cortex/backends/cortex_backend.py +236 -0
  8. clear_skies_cortex-2.0.4/src/clearskies_cortex/columns/string_list.py +69 -0
  9. clear_skies_cortex-2.0.4/src/clearskies_cortex/dataclasses.py +243 -0
  10. clear_skies_cortex-2.0.4/src/clearskies_cortex/defaults/default_cortex_auth.py +55 -0
  11. clear_skies_cortex-2.0.4/src/clearskies_cortex/defaults/default_cortex_url.py +45 -0
  12. clear_skies_cortex-2.0.4/src/clearskies_cortex/models/cortex_catalog_entity.py +247 -0
  13. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/models/cortex_catalog_entity_domain.py +29 -1
  14. clear_skies_cortex-2.0.4/src/clearskies_cortex/models/cortex_catalog_entity_group.py +47 -0
  15. clear_skies_cortex-2.0.4/src/clearskies_cortex/models/cortex_catalog_entity_scorecard.py +82 -0
  16. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/models/cortex_catalog_entity_service.py +35 -1
  17. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/models/cortex_catalog_entity_team.py +30 -1
  18. clear_skies_cortex-2.0.4/src/clearskies_cortex/models/cortex_catalog_entity_types.py +62 -0
  19. clear_skies_cortex-2.0.4/src/clearskies_cortex/models/cortex_entity_relationships.py +64 -0
  20. clear_skies_cortex-2.0.4/src/clearskies_cortex/models/cortex_model.py +32 -0
  21. clear_skies_cortex-2.0.4/src/clearskies_cortex/models/cortex_scorecard.py +68 -0
  22. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/models/cortex_team.py +98 -1
  23. clear_skies_cortex-2.0.4/src/clearskies_cortex/models/cortex_team_category_tree.py +67 -0
  24. clear_skies_cortex-2.0.4/src/clearskies_cortex/models/cortex_team_department.py +61 -0
  25. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/uv.lock +17 -1
  26. clear_skies_cortex-2.0.3/LATEST_CHANGELOG.md +0 -6
  27. clear_skies_cortex-2.0.3/src/clearskies_cortex/backends/cortex_backend.py +0 -101
  28. clear_skies_cortex-2.0.3/src/clearskies_cortex/columns/string_list.py +0 -25
  29. clear_skies_cortex-2.0.3/src/clearskies_cortex/dataclasses.py +0 -73
  30. clear_skies_cortex-2.0.3/src/clearskies_cortex/defaults/default_cortex_auth.py +0 -9
  31. clear_skies_cortex-2.0.3/src/clearskies_cortex/defaults/default_cortex_url.py +0 -7
  32. clear_skies_cortex-2.0.3/src/clearskies_cortex/models/cortex_catalog_entity.py +0 -90
  33. clear_skies_cortex-2.0.3/src/clearskies_cortex/models/cortex_catalog_entity_group.py +0 -22
  34. clear_skies_cortex-2.0.3/src/clearskies_cortex/models/cortex_catalog_entity_scorecard.py +0 -33
  35. clear_skies_cortex-2.0.3/src/clearskies_cortex/models/cortex_catalog_entity_types.py +0 -25
  36. clear_skies_cortex-2.0.3/src/clearskies_cortex/models/cortex_entity_relationships.py +0 -25
  37. clear_skies_cortex-2.0.3/src/clearskies_cortex/models/cortex_model.py +0 -9
  38. clear_skies_cortex-2.0.3/src/clearskies_cortex/models/cortex_scorecard.py +0 -27
  39. clear_skies_cortex-2.0.3/src/clearskies_cortex/models/cortex_team_category_tree.py +0 -27
  40. clear_skies_cortex-2.0.3/src/clearskies_cortex/models/cortex_team_department.py +0 -25
  41. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.editorconfig +0 -0
  42. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.github/workflows/create-version.yaml +0 -0
  43. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.github/workflows/run-tests.yml +0 -0
  44. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.github/workflows/tests-matrix.yaml +0 -0
  45. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.github/workflows/tests.yaml +0 -0
  46. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.gitignore +0 -0
  47. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.pre-commit-config.yaml +0 -0
  48. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.python-version +0 -0
  49. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/.vscode/settings.json +0 -0
  50. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/LICENSE +0 -0
  51. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/README.md +0 -0
  52. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/cliff.toml +0 -0
  53. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/ruff.toml +0 -0
  54. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/__init__.py +0 -0
  55. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/backends/__init__.py +0 -0
  56. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/backends/cortex_team_relationship_backend.py +0 -0
  57. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/columns/__init__.py +0 -0
  58. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/defaults/__init__.py +0 -0
  59. {clear_skies_cortex-2.0.3 → clear_skies_cortex-2.0.4}/src/clearskies_cortex/models/__init__.py +0 -0
@@ -1,5 +1,5 @@
1
1
  # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
2
- _commit: v0.0.45
2
+ _commit: v0.0.46
3
3
  _src_path: gh:clearskies-py/clearskies-module-template
4
4
  author_email: tom.nijboer@cimpress.com
5
5
  author_name: Tom Nijboer
@@ -33,6 +33,8 @@ jobs:
33
33
  enable-cache: true
34
34
  - name: Publish
35
35
  run: |
36
+ uv sync --all-groups --all-extras
37
+ uv add clear-skies-doc-builder --group doc
36
38
  cd docs/python
37
39
  uv run build.py
38
40
  sudo apt update
@@ -5,9 +5,19 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.4] - 2026-01-28
9
+
10
+ ### Changed
11
+ - Update to v0.0.46
12
+ - Document all the files
13
+
14
+ ### Fixed
15
+ - Set the count data correctly
16
+
8
17
  ## [2.0.3] - 2026-01-27
9
18
 
10
19
  ### Changed
20
+ - Bump version to v2.0.3 by @github-actions[bot]
11
21
  - Udpate to QueryResult
12
22
  - Update to latest copier version
13
23
 
@@ -41,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
41
51
  * @tnijboer made their first contribution in [#1](https://github.com/clearskies-py/cortex/pull/1)
42
52
  * @cmancone made their first contribution
43
53
  * @ made their first contribution
54
+ [2.0.4]: https://github.com/clearskies-py/cortex/compare/v2.0.3..v2.0.4
44
55
  [2.0.3]: https://github.com/clearskies-py/cortex/compare/v2.0.2..v2.0.3
45
56
  [2.0.2]: https://github.com/clearskies-py/cortex/compare/v2.0.1..v2.0.2
46
57
 
@@ -0,0 +1,9 @@
1
+ ## [2.0.4] - 2026-01-28
2
+
3
+ ### Changed
4
+ - Update to v0.0.46
5
+ - Document all the files
6
+
7
+ ### Fixed
8
+ - Set the count data correctly
9
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clear-skies-cortex
3
- Version: 2.0.3
3
+ Version: 2.0.4
4
4
  Summary: Cortex module for Clearskies
5
5
  Project-URL: Docs, https://https://clearskies.info/modules/clear-skies-cortex
6
6
  Project-URL: Repository, https://github.com/clearskies-py/cortex
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "clear-skies-cortex"
3
3
  description = "Cortex module for Clearskies"
4
- version = "2.0.3"
4
+ version = "2.0.4"
5
5
  license = "MIT"
6
6
  readme = "./README.md"
7
7
  authors = [{name = "Tom Nijboer", email = "tom.nijboer@cimpress.com"}]
@@ -65,3 +65,6 @@ dev = [
65
65
  "pytest-cov>=6.2.1",
66
66
  "ruff>=0.12.10",
67
67
  ]
68
+ doc = [
69
+ "clear-skies-doc-builder>=2.0.11",
70
+ ]
@@ -0,0 +1,236 @@
1
+ from typing import Any
2
+
3
+ import clearskies
4
+ import requests
5
+ from clearskies import configs
6
+ from clearskies.authentication import Authentication
7
+ from clearskies.decorators import parameters_to_properties
8
+ from clearskies.di import inject
9
+ from clearskies.query import Query
10
+
11
+
12
+ class CortexBackend(clearskies.backends.ApiBackend):
13
+ """
14
+ Backend for interacting with the Cortex.io API.
15
+
16
+ This backend extends the ApiBackend to provide seamless integration with the Cortex.io platform.
17
+ It handles the specific pagination and response format used by Cortex APIs, where pagination
18
+ information (`page`, `totalPages`, `total`) is returned in the response body rather than headers.
19
+
20
+ ## Usage
21
+
22
+ The CortexBackend is typically used with models that represent Cortex entities:
23
+
24
+ ```python
25
+ import clearskies
26
+ from clearskies_cortex.backends import CortexBackend
27
+
28
+
29
+ class CortexService(clearskies.Model):
30
+ backend = CortexBackend()
31
+
32
+ @classmethod
33
+ def destination_name(cls) -> str:
34
+ return "catalog/services"
35
+
36
+ tag = clearskies.columns.String()
37
+ name = clearskies.columns.String()
38
+ description = clearskies.columns.String()
39
+ ```
40
+
41
+ ## Authentication
42
+
43
+ By default, the backend uses the `cortex_auth` binding for authentication, which should be
44
+ configured in your application's dependency injection container. You can also provide a custom
45
+ authentication instance:
46
+
47
+ ```python
48
+ backend = CortexBackend(
49
+ authentication=clearskies.authentication.SecretBearer(
50
+ environment_key="CORTEX_API_KEY",
51
+ )
52
+ )
53
+ ```
54
+
55
+ ## Pagination
56
+
57
+ The Cortex API uses page-based pagination with the following response format:
58
+
59
+ ```json
60
+ {
61
+ "entities": [...],
62
+ "page": 1,
63
+ "totalPages": 5,
64
+ "total": 100
65
+ }
66
+ ```
67
+
68
+ The backend automatically handles extracting pagination data and provides the next page
69
+ information to clearskies for seamless iteration through results.
70
+ """
71
+
72
+ """
73
+ The base URL for the Cortex API.
74
+ """
75
+ base_url = configs.String(default="https://api.getcortexapp.com/api/v1/")
76
+
77
+ """
78
+ The authentication instance to use for API requests.
79
+
80
+ By default, this uses the `cortex_auth` binding from the dependency injection container.
81
+ """
82
+ authentication = inject.ByName("cortex_auth") # type: ignore[assignment]
83
+
84
+ """
85
+ The requests instance for making HTTP calls.
86
+ """
87
+ requests = inject.Requests()
88
+
89
+ """
90
+ The casing style used by the Cortex API (camelCase by default).
91
+ """
92
+ api_casing = configs.Select(["snake_case", "camelCase", "TitleCase"], default="camelCase")
93
+
94
+ _auth_headers: dict[str, str] = {}
95
+
96
+ """
97
+ A mapping from API response keys to model column names.
98
+ """
99
+ api_to_model_map = configs.AnyDict(default={})
100
+
101
+ """
102
+ The name of the pagination parameter used in requests.
103
+ """
104
+ pagination_parameter_name = configs.String(default="page")
105
+
106
+ """
107
+ The name of the limit parameter used in requests.
108
+ """
109
+ limit_parameter_name = configs.String(default="pageSize")
110
+
111
+ can_count = False
112
+
113
+ @parameters_to_properties
114
+ def __init__(
115
+ self,
116
+ base_url: str | None = "https://api.getcortexapp.com/api/v1/",
117
+ authentication: Authentication | None = None,
118
+ model_casing: str = "snake_case",
119
+ api_casing: str = "camelCase",
120
+ api_to_model_map: dict[str, str | list[str]] = {},
121
+ pagination_parameter_name: str = "page",
122
+ pagination_parameter_type: str = "int",
123
+ limit_parameter_name: str = "pageSize",
124
+ ):
125
+ self.finalize_and_validate_configuration()
126
+
127
+ def map_records_response(
128
+ self, response_data: Any, query: Query, query_data: dict[str, Any] | None = None
129
+ ) -> list[dict[str, Any]]:
130
+ """
131
+ Map the Cortex API response to model fields.
132
+
133
+ The Cortex API returns responses in a specific format where the actual records are nested
134
+ within a dictionary alongside pagination metadata. This method extracts the records and
135
+ removes the pagination fields before passing to the parent implementation.
136
+
137
+ Example Cortex API response:
138
+
139
+ ```json
140
+ {
141
+ "entities": [{"tag": "service-1", "name": "My Service"}, ...],
142
+ "page": 1,
143
+ "totalPages": 5,
144
+ "total": 100
145
+ }
146
+ ```
147
+
148
+ This method will extract the `entities` list and pass it to the parent for further processing.
149
+ """
150
+ if isinstance(response_data, dict):
151
+ if "page" in response_data:
152
+ del response_data["page"]
153
+ del response_data["totalPages"]
154
+ del response_data["total"]
155
+ first_item = next(iter(response_data))
156
+ if isinstance(response_data[first_item], list) and all(
157
+ isinstance(item, dict) for item in response_data[first_item]
158
+ ):
159
+ return super().map_records_response(response_data[first_item], query, query_data)
160
+ return super().map_records_response(response_data, query, query_data)
161
+
162
+ def get_next_page_data_from_response(
163
+ self,
164
+ query: Query,
165
+ response: "requests.Response", # type: ignore
166
+ ) -> dict[str, Any]:
167
+ """
168
+ Extract pagination data from the Cortex API response.
169
+
170
+ The Cortex API includes pagination information in the response body:
171
+
172
+ - `page`: The current page number
173
+ - `totalPages`: The total number of pages available
174
+ - `total`: The total number of records
175
+
176
+ This method checks if there are more pages available and returns the next page number
177
+ if so. It also extracts total count information for use in RecordsQueryResult.
178
+ The returned dictionary is used by clearskies to fetch subsequent pages and
179
+ populate count metadata.
180
+
181
+ Returns:
182
+ A dictionary containing:
183
+ - The next page number if more pages exist
184
+ - total_count: The total number of records (if available)
185
+ - total_pages: The total number of pages (if available)
186
+ """
187
+ next_page_data: dict[str, Any] = {}
188
+
189
+ response_data = response.json() if response.content else {}
190
+
191
+ if isinstance(response_data, dict):
192
+ # Extract count information from response body
193
+ count_info = self.extract_count_from_response(None, response_data)
194
+ if count_info:
195
+ total_count, total_pages = count_info
196
+ if total_count is not None:
197
+ next_page_data["total_count"] = total_count
198
+ if total_pages is not None:
199
+ next_page_data["total_pages"] = total_pages
200
+
201
+ # Check if there are more pages
202
+ page = response_data.get("page", None)
203
+ total_pages_from_response = response_data.get("totalPages", None)
204
+ if page is not None and total_pages_from_response is not None and page < total_pages_from_response:
205
+ next_page_data[self.pagination_parameter_name] = page + 1
206
+
207
+ return next_page_data
208
+
209
+ def extract_count_from_response(
210
+ self,
211
+ response_headers: dict[str, str] | None = None,
212
+ response_data: Any = None,
213
+ ) -> tuple[int | None, int | None]:
214
+ """
215
+ Extract count information from the Cortex API response body.
216
+
217
+ Unlike many APIs that return count information in headers, the Cortex API includes
218
+ this data in the response body:
219
+
220
+ - `total`: The total number of records matching the query
221
+ - `totalPages`: The total number of pages available
222
+
223
+ This method extracts these values and returns them as a tuple for use in
224
+ `RecordsQueryResult`.
225
+
226
+ Returns:
227
+ A tuple of (total_count, total_pages) where either value may be None
228
+ if not present in the response.
229
+ """
230
+ if not isinstance(response_data, dict):
231
+ return (None, None)
232
+
233
+ total_count = response_data.get("total", None)
234
+ total_pages = response_data.get("totalPages", None)
235
+
236
+ return (total_count, total_pages)
@@ -0,0 +1,69 @@
1
+ from typing import Any
2
+
3
+ from clearskies.columns import String
4
+
5
+
6
+ class StringList(String):
7
+ """
8
+ Column type for comma-delimited string lists.
9
+
10
+ This column type extends the String column to handle values that are stored as
11
+ comma-delimited strings but should be represented as Python lists. It automatically
12
+ converts between the two formats when reading from and writing to the backend.
13
+
14
+ Use this column type when the API returns or expects comma-separated values that
15
+ you want to work with as lists in your application code.
16
+
17
+ ```python
18
+ from clearskies import Model
19
+ from clearskies_cortex.columns import StringList
20
+
21
+
22
+ class MyModel(Model):
23
+ # Define a column that stores ["tag1", "tag2"] as "tag1,tag2"
24
+ tags = StringList()
25
+
26
+
27
+ # When reading from the backend:
28
+ # API returns: {"tags": "tag1,tag2,tag3"}
29
+ # Model provides: model.tags = ["tag1", "tag2", "tag3"]
30
+
31
+ # When writing to the backend:
32
+ # Model has: model.tags = ["tag1", "tag2", "tag3"]
33
+ # API receives: {"tags": "tag1,tag2,tag3"}
34
+ ```
35
+ """
36
+
37
+ def from_backend(self, value: str | list[str]) -> list[str]:
38
+ """
39
+ Convert backend value to a Python list.
40
+
41
+ Handles both string (comma-delimited) and list inputs for flexibility.
42
+
43
+ Args:
44
+ value: Either a comma-delimited string or a list of strings.
45
+
46
+ Returns:
47
+ A list of strings.
48
+ """
49
+ if isinstance(value, list):
50
+ return value
51
+ return value.split(",")
52
+
53
+ def to_backend(self, data: dict[str, Any]) -> dict[str, Any]:
54
+ """
55
+ Convert Python list to comma-delimited string for backend storage.
56
+
57
+ Transforms the list value back into a comma-separated string format
58
+ expected by the backend API.
59
+
60
+ Args:
61
+ data: Dictionary containing the column data.
62
+
63
+ Returns:
64
+ Dictionary with the column value converted to a comma-delimited string.
65
+ """
66
+ if self.name not in data:
67
+ return data
68
+
69
+ return {**data, self.name: str(",".join(data[self.name]))}
@@ -0,0 +1,243 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any
3
+
4
+
5
+ @dataclass
6
+ class ServiceEntityHierarchy:
7
+ """
8
+ Dataclass representing the hierarchy structure of a service entity.
9
+
10
+ This dataclass is used to parse the hierarchy JSON data from Cortex catalog entities.
11
+ It contains both parent and child relationships for navigating the entity hierarchy.
12
+
13
+ ```python
14
+ from clearskies_cortex.models import CortexCatalogEntity
15
+
16
+ entity = CortexCatalogEntity().find("tag=my-service")
17
+ hierarchy = entity.parse_hierarchy()
18
+
19
+ # Access parents
20
+ for parent in hierarchy.parents:
21
+ print(f"Parent: {parent.name} ({parent.type})")
22
+
23
+ # Access children
24
+ for child in hierarchy.children:
25
+ print(f"Child: {child.name} ({child.type})")
26
+ ```
27
+ """
28
+
29
+ """
30
+ List of parent entities in the hierarchy (from immediate parent to root).
31
+ """
32
+ parents: list["ServiceEntityHierarchyParent"]
33
+
34
+ """
35
+ List of child entities in the hierarchy.
36
+ """
37
+ children: list["ServiceEntityHierarchyChild"]
38
+
39
+
40
+ @dataclass
41
+ class ServiceEntityHierarchyParent:
42
+ """
43
+ Dataclass representing a parent entity in the hierarchy.
44
+
45
+ Contains information about a parent entity including its tag, type, name,
46
+ and recursively its own parents for traversing up the hierarchy tree.
47
+ """
48
+
49
+ """
50
+ The unique tag identifier of the parent entity.
51
+ """
52
+ tag: str
53
+
54
+ """
55
+ The type of the parent entity (e.g., "domain", "team").
56
+ """
57
+ type: str
58
+
59
+ """
60
+ The human-readable name of the parent entity.
61
+ """
62
+ name: str
63
+
64
+ """
65
+ Optional description of the parent entity.
66
+ """
67
+ description: str | None
68
+
69
+ """
70
+ Optional definition data for the parent entity.
71
+ """
72
+ definition: None | dict[str, Any]
73
+
74
+ """
75
+ List of grandparent entities (recursive parent structure).
76
+ """
77
+ parents: list["ServiceEntityHierarchyParent"]
78
+
79
+ """
80
+ Optional list of groups the parent entity belongs to.
81
+ """
82
+ groups: list[str] | None
83
+
84
+
85
+ @dataclass
86
+ class ServiceEntityHierarchyChild:
87
+ """
88
+ Dataclass representing a child entity in the hierarchy.
89
+
90
+ Contains information about a child entity including its tag, type, name,
91
+ and recursively its own children for traversing down the hierarchy tree.
92
+ """
93
+
94
+ """
95
+ The unique tag identifier of the child entity.
96
+ """
97
+ tag: str
98
+
99
+ """
100
+ The type of the child entity (e.g., "service", "domain").
101
+ """
102
+ type: str
103
+
104
+ """
105
+ The human-readable name of the child entity.
106
+ """
107
+ name: str
108
+
109
+ """
110
+ Optional description of the child entity.
111
+ """
112
+ description: str | None
113
+
114
+ """
115
+ Optional definition data for the child entity.
116
+ """
117
+ definition: None | dict[str, Any]
118
+
119
+ """
120
+ List of grandchild entities (recursive child structure).
121
+ """
122
+ children: list["ServiceEntityHierarchyChild"]
123
+
124
+ """
125
+ Optional list of groups the child entity belongs to.
126
+ """
127
+ groups: list[str] | None
128
+
129
+
130
+ @dataclass
131
+ class TeamCategory:
132
+ """
133
+ Dataclass representing a team category in the category tree.
134
+
135
+ Used for organizing teams into hierarchical categories with parent-child relationships.
136
+ """
137
+
138
+ """
139
+ The name of the category.
140
+ """
141
+ name: str
142
+
143
+ """
144
+ The depth level in the category hierarchy (0 for root).
145
+ """
146
+ level: int
147
+
148
+ """
149
+ The name of the parent category.
150
+ """
151
+ parent_name: str
152
+
153
+
154
+ @dataclass
155
+ class EntityTeam:
156
+ """
157
+ Dataclass representing a team associated with a catalog entity.
158
+
159
+ Contains team information including ownership inheritance and provider details.
160
+ """
161
+
162
+ """
163
+ Optional description of the team.
164
+ """
165
+ description: str | None
166
+
167
+ """
168
+ The inheritance type for ownership (e.g., "direct", "inherited").
169
+ """
170
+ inheritance: str
171
+
172
+ """
173
+ Whether the team is archived.
174
+ """
175
+ isArchived: bool # noqa: N815
176
+
177
+ """
178
+ The human-readable name of the team.
179
+ """
180
+ name: str
181
+
182
+ """
183
+ The provider of the team data (e.g., "cortex", "external").
184
+ """
185
+ provider: str
186
+
187
+ """
188
+ The unique tag identifier of the team.
189
+ """
190
+ tag: str
191
+
192
+
193
+ @dataclass
194
+ class EntityIndividual:
195
+ """
196
+ Dataclass representing an individual owner of a catalog entity.
197
+
198
+ Contains information about individual (non-team) owners.
199
+ """
200
+
201
+ """
202
+ Optional description of the individual.
203
+ """
204
+ description: str | None
205
+
206
+ """
207
+ The email address of the individual.
208
+ """
209
+ email: str
210
+
211
+
212
+ @dataclass
213
+ class EntityTeamOwner:
214
+ """
215
+ Dataclass representing the ownership information for a catalog entity.
216
+
217
+ Contains both team and individual owners. Used by `CortexCatalogEntity.parse_owners()`.
218
+
219
+ ```python
220
+ from clearskies_cortex.models import CortexCatalogEntity
221
+
222
+ entity = CortexCatalogEntity().find("tag=my-service")
223
+ owners = entity.parse_owners()
224
+
225
+ # Access team owners
226
+ for team in owners.teams:
227
+ print(f"Team owner: {team.name} ({team.tag})")
228
+
229
+ # Access individual owners
230
+ for individual in owners.individuals:
231
+ print(f"Individual owner: {individual.email}")
232
+ ```
233
+ """
234
+
235
+ """
236
+ List of teams that own the entity.
237
+ """
238
+ teams: list[EntityTeam]
239
+
240
+ """
241
+ List of individuals that own the entity.
242
+ """
243
+ individuals: list[EntityIndividual]
@@ -0,0 +1,55 @@
1
+ import clearskies
2
+
3
+
4
+ class DefaultCortexAuth(clearskies.di.AdditionalConfigAutoImport):
5
+ """
6
+ Default authentication provider for Cortex API.
7
+
8
+ This class provides automatic configuration for Cortex API authentication using
9
+ the clearskies dependency injection system. It is auto-imported when the clearskies_cortex
10
+ package is used, making authentication configuration seamless.
11
+
12
+ The authentication can be configured in two ways:
13
+
14
+ 1. **Secret Path (recommended for production)**: Set the `CORTEX_AUTH_SECRET_PATH` environment
15
+ variable to point to a secret manager path containing the API key.
16
+
17
+ 2. **Direct Environment Key**: Set the `CORTEX_AUTH_KEY` environment variable directly
18
+ with the Cortex API key.
19
+
20
+ ```python
21
+ import clearskies
22
+ from clearskies_cortex.models import CortexTeam
23
+
24
+ # The authentication is automatically configured via environment variables
25
+ # Option 1: Using secret path
26
+ # export CORTEX_AUTH_SECRET_PATH=/path/to/secret
27
+
28
+ # Option 2: Using direct key
29
+ # export CORTEX_AUTH_KEY=your-api-key
30
+
31
+ # Then use models normally - auth is handled automatically
32
+ teams = CortexTeam()
33
+ for team in teams:
34
+ print(team.get_name())
35
+ ```
36
+ """
37
+
38
+ def provide_cortex_auth(self, environment: clearskies.Environment):
39
+ """
40
+ Provide the Cortex authentication configuration.
41
+
42
+ Checks for `CORTEX_AUTH_SECRET_PATH` first, falling back to `CORTEX_AUTH_KEY`
43
+ if not set. Returns a SecretBearer authentication instance configured for
44
+ the Cortex API.
45
+
46
+ Args:
47
+ environment: The clearskies Environment instance for accessing env variables.
48
+
49
+ Returns:
50
+ A SecretBearer authentication instance configured for Cortex API.
51
+ """
52
+ if environment.get("CORTEX_AUTH_SECRET_PATH", True):
53
+ secret_key = environment.get("CORTEX_AUTH_SECRET_PATH")
54
+ return clearskies.authentication.SecretBearer(secret_key=secret_key, header_prefix="Bearer ")
55
+ return clearskies.authentication.SecretBearer(environment_key="CORTEX_AUTH_KEY", header_prefix="Bearer ")