cartography 0.103.0__py3-none-any.whl → 0.104.0rc1__py3-none-any.whl
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.
Potentially problematic release.
This version of cartography might be problematic. Click here for more details.
- cartography/_version.py +2 -2
- cartography/cli.py +21 -3
- cartography/config.py +4 -0
- cartography/intel/anthropic/__init__.py +62 -0
- cartography/intel/anthropic/apikeys.py +72 -0
- cartography/intel/anthropic/users.py +75 -0
- cartography/intel/anthropic/util.py +51 -0
- cartography/intel/anthropic/workspaces.py +95 -0
- cartography/intel/aws/ec2/load_balancer_v2s.py +4 -1
- cartography/intel/aws/secretsmanager.py +136 -3
- cartography/intel/aws/ssm.py +71 -0
- cartography/intel/openai/adminapikeys.py +1 -2
- cartography/intel/openai/apikeys.py +1 -1
- cartography/intel/openai/projects.py +4 -1
- cartography/intel/openai/serviceaccounts.py +1 -1
- cartography/intel/openai/users.py +0 -3
- cartography/intel/openai/util.py +17 -1
- cartography/models/anthropic/__init__.py +0 -0
- cartography/models/anthropic/apikey.py +90 -0
- cartography/models/anthropic/organization.py +19 -0
- cartography/models/anthropic/user.py +48 -0
- cartography/models/anthropic/workspace.py +90 -0
- cartography/models/aws/secretsmanager/__init__.py +0 -0
- cartography/models/aws/secretsmanager/secret_version.py +116 -0
- cartography/models/aws/ssm/parameters.py +84 -0
- cartography/models/openai/project.py +20 -1
- cartography/sync.py +2 -0
- {cartography-0.103.0.dist-info → cartography-0.104.0rc1.dist-info}/METADATA +4 -4
- {cartography-0.103.0.dist-info → cartography-0.104.0rc1.dist-info}/RECORD +33 -20
- {cartography-0.103.0.dist-info → cartography-0.104.0rc1.dist-info}/WHEEL +1 -1
- {cartography-0.103.0.dist-info → cartography-0.104.0rc1.dist-info}/entry_points.txt +0 -0
- {cartography-0.103.0.dist-info → cartography-0.104.0rc1.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.103.0.dist-info → cartography-0.104.0rc1.dist-info}/top_level.txt +0 -0
cartography/intel/aws/ssm.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
3
|
+
import re
|
|
2
4
|
from typing import Any
|
|
3
5
|
from typing import Dict
|
|
4
6
|
from typing import List
|
|
@@ -10,6 +12,7 @@ from cartography.client.core.tx import load
|
|
|
10
12
|
from cartography.graph.job import GraphJob
|
|
11
13
|
from cartography.models.aws.ssm.instance_information import SSMInstanceInformationSchema
|
|
12
14
|
from cartography.models.aws.ssm.instance_patch import SSMInstancePatchSchema
|
|
15
|
+
from cartography.models.aws.ssm.parameters import SSMParameterSchema
|
|
13
16
|
from cartography.util import aws_handle_regions
|
|
14
17
|
from cartography.util import dict_date_to_epoch
|
|
15
18
|
from cartography.util import timeit
|
|
@@ -107,6 +110,42 @@ def transform_instance_patches(data_list: List[Dict[str, Any]]) -> List[Dict[str
|
|
|
107
110
|
return data_list
|
|
108
111
|
|
|
109
112
|
|
|
113
|
+
@timeit
|
|
114
|
+
@aws_handle_regions
|
|
115
|
+
def get_ssm_parameters(
|
|
116
|
+
boto3_session: boto3.session.Session,
|
|
117
|
+
region: str,
|
|
118
|
+
) -> List[Dict[str, Any]]:
|
|
119
|
+
client = boto3_session.client("ssm", region_name=region)
|
|
120
|
+
paginator = client.get_paginator("describe_parameters")
|
|
121
|
+
ssm_parameters_data: List[Dict[str, Any]] = []
|
|
122
|
+
for page in paginator.paginate(PaginationConfig={"PageSize": 50}):
|
|
123
|
+
ssm_parameters_data.extend(page.get("Parameters", []))
|
|
124
|
+
return ssm_parameters_data
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def transform_ssm_parameters(
|
|
128
|
+
raw_parameters_data: List[Dict[str, Any]],
|
|
129
|
+
) -> List[Dict[str, Any]]:
|
|
130
|
+
transformed_list: List[Dict[str, Any]] = []
|
|
131
|
+
for param in raw_parameters_data:
|
|
132
|
+
param["LastModifiedDate"] = dict_date_to_epoch(param, "LastModifiedDate")
|
|
133
|
+
param["PoliciesJson"] = json.dumps(param.get("Policies", []))
|
|
134
|
+
# KMSKey uses shorter UUID as their primary id
|
|
135
|
+
# SSM Parameters, when encrypted, reference KMS keys using their full ARNs in the KeyId field
|
|
136
|
+
# Adding a param to match on the id property of the target node
|
|
137
|
+
if param.get("Type") == "SecureString" and param.get("KeyId") is not None:
|
|
138
|
+
match = re.match(r".*key/(.*)$", param["KeyId"])
|
|
139
|
+
if match:
|
|
140
|
+
param["KMSKeyIdShort"] = match.group(1)
|
|
141
|
+
else:
|
|
142
|
+
param["KMSKeyIdShort"] = None
|
|
143
|
+
else:
|
|
144
|
+
param["KMSKeyIdShort"] = None
|
|
145
|
+
transformed_list.append(param)
|
|
146
|
+
return transformed_list
|
|
147
|
+
|
|
148
|
+
|
|
110
149
|
@timeit
|
|
111
150
|
def load_instance_information(
|
|
112
151
|
neo4j_session: neo4j.Session,
|
|
@@ -143,6 +182,24 @@ def load_instance_patches(
|
|
|
143
182
|
)
|
|
144
183
|
|
|
145
184
|
|
|
185
|
+
@timeit
|
|
186
|
+
def load_ssm_parameters(
|
|
187
|
+
neo4j_session: neo4j.Session,
|
|
188
|
+
data: List[Dict[str, Any]],
|
|
189
|
+
region: str,
|
|
190
|
+
current_aws_account_id: str,
|
|
191
|
+
aws_update_tag: int,
|
|
192
|
+
) -> None:
|
|
193
|
+
load(
|
|
194
|
+
neo4j_session,
|
|
195
|
+
SSMParameterSchema(),
|
|
196
|
+
data,
|
|
197
|
+
lastupdated=aws_update_tag,
|
|
198
|
+
Region=region,
|
|
199
|
+
AWS_ID=current_aws_account_id,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
146
203
|
@timeit
|
|
147
204
|
def cleanup_ssm(
|
|
148
205
|
neo4j_session: neo4j.Session,
|
|
@@ -156,6 +213,9 @@ def cleanup_ssm(
|
|
|
156
213
|
GraphJob.from_node_schema(SSMInstancePatchSchema(), common_job_parameters).run(
|
|
157
214
|
neo4j_session,
|
|
158
215
|
)
|
|
216
|
+
GraphJob.from_node_schema(SSMParameterSchema(), common_job_parameters).run(
|
|
217
|
+
neo4j_session,
|
|
218
|
+
)
|
|
159
219
|
|
|
160
220
|
|
|
161
221
|
@timeit
|
|
@@ -193,4 +253,15 @@ def sync(
|
|
|
193
253
|
current_aws_account_id,
|
|
194
254
|
update_tag,
|
|
195
255
|
)
|
|
256
|
+
|
|
257
|
+
data = get_ssm_parameters(boto3_session, region)
|
|
258
|
+
data = transform_ssm_parameters(data)
|
|
259
|
+
load_ssm_parameters(
|
|
260
|
+
neo4j_session,
|
|
261
|
+
data,
|
|
262
|
+
region,
|
|
263
|
+
current_aws_account_id,
|
|
264
|
+
update_tag,
|
|
265
|
+
)
|
|
266
|
+
|
|
196
267
|
cleanup_ssm(neo4j_session, common_job_parameters)
|
|
@@ -23,7 +23,7 @@ def sync(
|
|
|
23
23
|
api_session: requests.Session,
|
|
24
24
|
common_job_parameters: Dict[str, Any],
|
|
25
25
|
ORG_ID: str,
|
|
26
|
-
) ->
|
|
26
|
+
) -> None:
|
|
27
27
|
adminapikeys = get(
|
|
28
28
|
api_session,
|
|
29
29
|
common_job_parameters["BASE_URL"],
|
|
@@ -36,7 +36,6 @@ def sync(
|
|
|
36
36
|
common_job_parameters["UPDATE_TAG"],
|
|
37
37
|
)
|
|
38
38
|
cleanup(neo4j_session, common_job_parameters)
|
|
39
|
-
return adminapikeys
|
|
40
39
|
|
|
41
40
|
|
|
42
41
|
@timeit
|
|
@@ -77,7 +77,7 @@ def load_apikeys(
|
|
|
77
77
|
project_id: str,
|
|
78
78
|
update_tag: int,
|
|
79
79
|
) -> None:
|
|
80
|
-
logger.info("Loading %d OpenAI
|
|
80
|
+
logger.info("Loading %d OpenAI APIKey into Neo4j.", len(data))
|
|
81
81
|
load(
|
|
82
82
|
neo4j_session,
|
|
83
83
|
OpenAIApiKeySchema(),
|
|
@@ -30,12 +30,15 @@ def sync(
|
|
|
30
30
|
)
|
|
31
31
|
for project in projects:
|
|
32
32
|
project["users"] = []
|
|
33
|
+
project["admins"] = []
|
|
33
34
|
for user in get_project_users(
|
|
34
35
|
api_session,
|
|
35
36
|
common_job_parameters["BASE_URL"],
|
|
36
37
|
project["id"],
|
|
37
38
|
):
|
|
38
39
|
project["users"].append(user["id"])
|
|
40
|
+
if user["role"] == "owner":
|
|
41
|
+
project["admins"].append(user["id"])
|
|
39
42
|
load_projects(neo4j_session, projects, ORG_ID, common_job_parameters["UPDATE_TAG"])
|
|
40
43
|
cleanup(neo4j_session, common_job_parameters)
|
|
41
44
|
return projects
|
|
@@ -75,7 +78,7 @@ def load_projects(
|
|
|
75
78
|
ORG_ID: str,
|
|
76
79
|
update_tag: int,
|
|
77
80
|
) -> None:
|
|
78
|
-
logger.info("Loading %d
|
|
81
|
+
logger.info("Loading %d OpenAI Projects into Neo4j.", len(data))
|
|
79
82
|
load(
|
|
80
83
|
neo4j_session,
|
|
81
84
|
OpenAIProjectSchema(),
|
|
@@ -63,7 +63,7 @@ def load_serviceaccounts(
|
|
|
63
63
|
project_id: str,
|
|
64
64
|
update_tag: int,
|
|
65
65
|
) -> None:
|
|
66
|
-
logger.info("Loading %d OpenAI
|
|
66
|
+
logger.info("Loading %d OpenAI ServiceAccount into Neo4j.", len(data))
|
|
67
67
|
load(
|
|
68
68
|
neo4j_session,
|
|
69
69
|
OpenAIServiceAccountSchema(),
|
|
@@ -70,9 +70,6 @@ def load_users(
|
|
|
70
70
|
def cleanup(
|
|
71
71
|
neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]
|
|
72
72
|
) -> None:
|
|
73
|
-
GraphJob.from_node_schema(OpenAIOrganizationSchema(), common_job_parameters).run(
|
|
74
|
-
neo4j_session
|
|
75
|
-
)
|
|
76
73
|
GraphJob.from_node_schema(OpenAIUserSchema(), common_job_parameters).run(
|
|
77
74
|
neo4j_session
|
|
78
75
|
)
|
cartography/intel/openai/util.py
CHANGED
|
@@ -10,7 +10,23 @@ def paginated_get(
|
|
|
10
10
|
timeout: tuple[int, int],
|
|
11
11
|
after: str | None = None,
|
|
12
12
|
) -> Generator[dict[str, Any], None, None]:
|
|
13
|
-
|
|
13
|
+
"""Helper function to get paginated data from the OpenAI API.
|
|
14
|
+
|
|
15
|
+
This function handles the pagination of the API requests and returns
|
|
16
|
+
the results as a generator. It will continue to make requests until
|
|
17
|
+
all pages of data have been retrieved. The results are returned as a
|
|
18
|
+
list of dictionaries, where each dictionary represents a single
|
|
19
|
+
entity.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
api_session (requests.Session): The requests session to use for making API calls.
|
|
23
|
+
url (str): The URL to make the API call to.
|
|
24
|
+
timeout (tuple[int, int]): The timeout for the API call.
|
|
25
|
+
after (str | None): The ID of the last item retrieved in the previous request.
|
|
26
|
+
If None, the first page of results will be retrieved.
|
|
27
|
+
Returns:
|
|
28
|
+
Generator[dict[str, Any], None, None]: A generator yielding dictionaries representing the results.
|
|
29
|
+
"""
|
|
14
30
|
params = {"after": after} if after else {}
|
|
15
31
|
req = api_session.get(
|
|
16
32
|
url,
|
|
File without changes
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from cartography.models.core.common import PropertyRef
|
|
4
|
+
from cartography.models.core.nodes import CartographyNodeProperties
|
|
5
|
+
from cartography.models.core.nodes import CartographyNodeSchema
|
|
6
|
+
from cartography.models.core.relationships import CartographyRelProperties
|
|
7
|
+
from cartography.models.core.relationships import CartographyRelSchema
|
|
8
|
+
from cartography.models.core.relationships import LinkDirection
|
|
9
|
+
from cartography.models.core.relationships import make_target_node_matcher
|
|
10
|
+
from cartography.models.core.relationships import OtherRelationships
|
|
11
|
+
from cartography.models.core.relationships import TargetNodeMatcher
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class AnthropicApiKeyNodeProperties(CartographyNodeProperties):
|
|
16
|
+
id: PropertyRef = PropertyRef("id")
|
|
17
|
+
name: PropertyRef = PropertyRef("name")
|
|
18
|
+
status: PropertyRef = PropertyRef("status")
|
|
19
|
+
created_at: PropertyRef = PropertyRef("created_at")
|
|
20
|
+
last_used_at: PropertyRef = PropertyRef("last_used_at")
|
|
21
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class AnthropicApiKeyToOrganizationRelProperties(CartographyRelProperties):
|
|
26
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
# (:AnthropicOrganization)-[:RESOURCE]->(:AnthropicApiKey)
|
|
31
|
+
class AnthropicApiKeyToOrganizationRel(CartographyRelSchema):
|
|
32
|
+
target_node_label: str = "AnthropicOrganization"
|
|
33
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
34
|
+
{"id": PropertyRef("ORG_ID", set_in_kwargs=True)},
|
|
35
|
+
)
|
|
36
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
37
|
+
rel_label: str = "RESOURCE"
|
|
38
|
+
properties: AnthropicApiKeyToOrganizationRelProperties = (
|
|
39
|
+
AnthropicApiKeyToOrganizationRelProperties()
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class AnthropicApiKeyToUserRelProperties(CartographyRelProperties):
|
|
45
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass(frozen=True)
|
|
49
|
+
# (:AnthropicUser)-[:OWNS]->(:AnthropicApiKey)
|
|
50
|
+
class AnthropicApiKeyToUserRel(CartographyRelSchema):
|
|
51
|
+
target_node_label: str = "AnthropicUser"
|
|
52
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
53
|
+
{"id": PropertyRef("created_by.id")},
|
|
54
|
+
)
|
|
55
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
56
|
+
rel_label: str = "OWNS"
|
|
57
|
+
properties: AnthropicApiKeyToUserRelProperties = (
|
|
58
|
+
AnthropicApiKeyToUserRelProperties()
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(frozen=True)
|
|
63
|
+
class AnthropicApiKeyToWorkspaceRelProperties(CartographyRelProperties):
|
|
64
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(frozen=True)
|
|
68
|
+
# (:AnthropicWorkspace)-[:CONTAINS]->(:AnthropicApiKey)
|
|
69
|
+
class AnthropicApiKeyToWorkspaceRel(CartographyRelSchema):
|
|
70
|
+
target_node_label: str = "AnthropicWorkspace"
|
|
71
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
72
|
+
{"id": PropertyRef("workspace_id")},
|
|
73
|
+
)
|
|
74
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
75
|
+
rel_label: str = "CONTAINS"
|
|
76
|
+
properties: AnthropicApiKeyToWorkspaceRelProperties = (
|
|
77
|
+
AnthropicApiKeyToWorkspaceRelProperties()
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass(frozen=True)
|
|
82
|
+
class AnthropicApiKeySchema(CartographyNodeSchema):
|
|
83
|
+
label: str = "AnthropicApiKey"
|
|
84
|
+
properties: AnthropicApiKeyNodeProperties = AnthropicApiKeyNodeProperties()
|
|
85
|
+
sub_resource_relationship: AnthropicApiKeyToOrganizationRel = (
|
|
86
|
+
AnthropicApiKeyToOrganizationRel()
|
|
87
|
+
)
|
|
88
|
+
other_relationships: OtherRelationships = OtherRelationships(
|
|
89
|
+
[AnthropicApiKeyToUserRel(), AnthropicApiKeyToWorkspaceRel()],
|
|
90
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from cartography.models.core.common import PropertyRef
|
|
4
|
+
from cartography.models.core.nodes import CartographyNodeProperties
|
|
5
|
+
from cartography.models.core.nodes import CartographyNodeSchema
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class AnthropicOrganizationNodeProperties(CartographyNodeProperties):
|
|
10
|
+
id: PropertyRef = PropertyRef("id")
|
|
11
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class AnthropicOrganizationSchema(CartographyNodeSchema):
|
|
16
|
+
label: str = "AnthropicOrganization"
|
|
17
|
+
properties: AnthropicOrganizationNodeProperties = (
|
|
18
|
+
AnthropicOrganizationNodeProperties()
|
|
19
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from cartography.models.core.common import PropertyRef
|
|
4
|
+
from cartography.models.core.nodes import CartographyNodeProperties
|
|
5
|
+
from cartography.models.core.nodes import CartographyNodeSchema
|
|
6
|
+
from cartography.models.core.relationships import CartographyRelProperties
|
|
7
|
+
from cartography.models.core.relationships import CartographyRelSchema
|
|
8
|
+
from cartography.models.core.relationships import LinkDirection
|
|
9
|
+
from cartography.models.core.relationships import make_target_node_matcher
|
|
10
|
+
from cartography.models.core.relationships import TargetNodeMatcher
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class AnthropicUserNodeProperties(CartographyNodeProperties):
|
|
15
|
+
id: PropertyRef = PropertyRef("id")
|
|
16
|
+
name: PropertyRef = PropertyRef("name")
|
|
17
|
+
email: PropertyRef = PropertyRef("email", extra_index=True)
|
|
18
|
+
role: PropertyRef = PropertyRef("role")
|
|
19
|
+
added_at: PropertyRef = PropertyRef("added_at")
|
|
20
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True)
|
|
24
|
+
class AnthropicUserToOrganizationRelProperties(CartographyRelProperties):
|
|
25
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
# (:AnthropicOrganization)-[:RESOURCE]->(:AnthropicUser)
|
|
30
|
+
class AnthropicUserToOrganizationRel(CartographyRelSchema):
|
|
31
|
+
target_node_label: str = "AnthropicOrganization"
|
|
32
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
33
|
+
{"id": PropertyRef("ORG_ID", set_in_kwargs=True)},
|
|
34
|
+
)
|
|
35
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
36
|
+
rel_label: str = "RESOURCE"
|
|
37
|
+
properties: AnthropicUserToOrganizationRelProperties = (
|
|
38
|
+
AnthropicUserToOrganizationRelProperties()
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(frozen=True)
|
|
43
|
+
class AnthropicUserSchema(CartographyNodeSchema):
|
|
44
|
+
label: str = "AnthropicUser"
|
|
45
|
+
properties: AnthropicUserNodeProperties = AnthropicUserNodeProperties()
|
|
46
|
+
sub_resource_relationship: AnthropicUserToOrganizationRel = (
|
|
47
|
+
AnthropicUserToOrganizationRel()
|
|
48
|
+
)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from cartography.models.core.common import PropertyRef
|
|
4
|
+
from cartography.models.core.nodes import CartographyNodeProperties
|
|
5
|
+
from cartography.models.core.nodes import CartographyNodeSchema
|
|
6
|
+
from cartography.models.core.relationships import CartographyRelProperties
|
|
7
|
+
from cartography.models.core.relationships import CartographyRelSchema
|
|
8
|
+
from cartography.models.core.relationships import LinkDirection
|
|
9
|
+
from cartography.models.core.relationships import make_target_node_matcher
|
|
10
|
+
from cartography.models.core.relationships import OtherRelationships
|
|
11
|
+
from cartography.models.core.relationships import TargetNodeMatcher
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class AnthropicWorkspaceNodeProperties(CartographyNodeProperties):
|
|
16
|
+
id: PropertyRef = PropertyRef("id")
|
|
17
|
+
name: PropertyRef = PropertyRef("name")
|
|
18
|
+
created_at: PropertyRef = PropertyRef("created_at")
|
|
19
|
+
archived_at: PropertyRef = PropertyRef("archived_at")
|
|
20
|
+
display_color: PropertyRef = PropertyRef("display_color")
|
|
21
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class AnthropicWorkspaceToOrganizationRelProperties(CartographyRelProperties):
|
|
26
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
# (:AnthropicOrganization)-[:RESOURCE]->(:AnthropicWorkspace)
|
|
31
|
+
class AnthropicWorkspaceToOrganizationRel(CartographyRelSchema):
|
|
32
|
+
target_node_label: str = "AnthropicOrganization"
|
|
33
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
34
|
+
{"id": PropertyRef("ORG_ID", set_in_kwargs=True)},
|
|
35
|
+
)
|
|
36
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
37
|
+
rel_label: str = "RESOURCE"
|
|
38
|
+
properties: AnthropicWorkspaceToOrganizationRelProperties = (
|
|
39
|
+
AnthropicWorkspaceToOrganizationRelProperties()
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class AnthropicWorkspaceToUserRelProperties(CartographyRelProperties):
|
|
45
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass(frozen=True)
|
|
49
|
+
# (:AnthropicUser)-[:MEMBER_OF]->(:AnthropicWorkspace)
|
|
50
|
+
class AnthropicWorkspaceToUserRel(CartographyRelSchema):
|
|
51
|
+
target_node_label: str = "AnthropicUser"
|
|
52
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
53
|
+
{"id": PropertyRef("users", one_to_many=True)},
|
|
54
|
+
)
|
|
55
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
56
|
+
rel_label: str = "MEMBER_OF"
|
|
57
|
+
properties: AnthropicWorkspaceToUserRelProperties = (
|
|
58
|
+
AnthropicWorkspaceToUserRelProperties()
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(frozen=True)
|
|
63
|
+
class AnthropicWorkspaceToUserAdminRelProperties(CartographyRelProperties):
|
|
64
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(frozen=True)
|
|
68
|
+
# (:AnthropicUser)-[:ADMIN_OF]->(:AnthropicWorkspace)
|
|
69
|
+
class AnthropicWorkspaceToUserAdminRel(CartographyRelSchema):
|
|
70
|
+
target_node_label: str = "AnthropicUser"
|
|
71
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
72
|
+
{"id": PropertyRef("admins", one_to_many=True)},
|
|
73
|
+
)
|
|
74
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
75
|
+
rel_label: str = "ADMIN_OF"
|
|
76
|
+
properties: AnthropicWorkspaceToUserAdminRelProperties = (
|
|
77
|
+
AnthropicWorkspaceToUserAdminRelProperties()
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass(frozen=True)
|
|
82
|
+
class AnthropicWorkspaceSchema(CartographyNodeSchema):
|
|
83
|
+
label: str = "AnthropicWorkspace"
|
|
84
|
+
properties: AnthropicWorkspaceNodeProperties = AnthropicWorkspaceNodeProperties()
|
|
85
|
+
sub_resource_relationship: AnthropicWorkspaceToOrganizationRel = (
|
|
86
|
+
AnthropicWorkspaceToOrganizationRel()
|
|
87
|
+
)
|
|
88
|
+
other_relationships: OtherRelationships = OtherRelationships(
|
|
89
|
+
[AnthropicWorkspaceToUserRel(), AnthropicWorkspaceToUserAdminRel()],
|
|
90
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from cartography.models.core.common import PropertyRef
|
|
4
|
+
from cartography.models.core.nodes import CartographyNodeProperties
|
|
5
|
+
from cartography.models.core.nodes import CartographyNodeSchema
|
|
6
|
+
from cartography.models.core.relationships import CartographyRelProperties
|
|
7
|
+
from cartography.models.core.relationships import CartographyRelSchema
|
|
8
|
+
from cartography.models.core.relationships import LinkDirection
|
|
9
|
+
from cartography.models.core.relationships import make_target_node_matcher
|
|
10
|
+
from cartography.models.core.relationships import OtherRelationships
|
|
11
|
+
from cartography.models.core.relationships import TargetNodeMatcher
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class SecretsManagerSecretVersionNodeProperties(CartographyNodeProperties):
|
|
16
|
+
"""
|
|
17
|
+
Properties for AWS Secrets Manager Secret Version
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# Align property names with the actual keys in the data
|
|
21
|
+
id: PropertyRef = PropertyRef("ARN")
|
|
22
|
+
arn: PropertyRef = PropertyRef("ARN", extra_index=True)
|
|
23
|
+
secret_id: PropertyRef = PropertyRef("SecretId")
|
|
24
|
+
version_id: PropertyRef = PropertyRef("VersionId")
|
|
25
|
+
version_stages: PropertyRef = PropertyRef("VersionStages")
|
|
26
|
+
created_date: PropertyRef = PropertyRef("CreatedDate")
|
|
27
|
+
region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
|
|
28
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
29
|
+
# Make KMS and tags properties without required=False parameter
|
|
30
|
+
kms_key_id: PropertyRef = PropertyRef("KmsKeyId")
|
|
31
|
+
tags: PropertyRef = PropertyRef("Tags")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True)
|
|
35
|
+
class SecretsManagerSecretVersionRelProperties(CartographyRelProperties):
|
|
36
|
+
"""
|
|
37
|
+
Properties for relationships between Secret Version and other nodes
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class SecretsManagerSecretVersionToAWSAccountRel(CartographyRelSchema):
|
|
45
|
+
"""
|
|
46
|
+
Relationship between Secret Version and AWS Account
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
target_node_label: str = "AWSAccount"
|
|
50
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
51
|
+
{"id": PropertyRef("AWS_ID", set_in_kwargs=True)},
|
|
52
|
+
)
|
|
53
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
54
|
+
rel_label: str = "RESOURCE"
|
|
55
|
+
properties: SecretsManagerSecretVersionRelProperties = (
|
|
56
|
+
SecretsManagerSecretVersionRelProperties()
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass(frozen=True)
|
|
61
|
+
class SecretsManagerSecretVersionToSecretRel(CartographyRelSchema):
|
|
62
|
+
"""
|
|
63
|
+
Relationship between Secret Version and its parent Secret
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
target_node_label: str = "SecretsManagerSecret"
|
|
67
|
+
# Use only one matcher for the id field
|
|
68
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
69
|
+
{"id": PropertyRef("SecretId")},
|
|
70
|
+
)
|
|
71
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
72
|
+
rel_label: str = "VERSION_OF"
|
|
73
|
+
properties: SecretsManagerSecretVersionRelProperties = (
|
|
74
|
+
SecretsManagerSecretVersionRelProperties()
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass(frozen=True)
|
|
79
|
+
class SecretsManagerSecretVersionToKMSKeyRel(CartographyRelSchema):
|
|
80
|
+
"""
|
|
81
|
+
Relationship between Secret Version and its KMS key
|
|
82
|
+
Only created when KmsKeyId is present
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
target_node_label: str = "AWSKMSKey"
|
|
86
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
87
|
+
{"id": PropertyRef("KmsKeyId")},
|
|
88
|
+
)
|
|
89
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
90
|
+
rel_label: str = "ENCRYPTED_BY"
|
|
91
|
+
properties: SecretsManagerSecretVersionRelProperties = (
|
|
92
|
+
SecretsManagerSecretVersionRelProperties()
|
|
93
|
+
)
|
|
94
|
+
# Only create this relationship if KmsKeyId exists
|
|
95
|
+
conditional_match_property: str = "KmsKeyId"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass(frozen=True)
|
|
99
|
+
class SecretsManagerSecretVersionSchema(CartographyNodeSchema):
|
|
100
|
+
"""
|
|
101
|
+
Schema for AWS Secrets Manager Secret Version
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
label: str = "SecretsManagerSecretVersion"
|
|
105
|
+
properties: SecretsManagerSecretVersionNodeProperties = (
|
|
106
|
+
SecretsManagerSecretVersionNodeProperties()
|
|
107
|
+
)
|
|
108
|
+
sub_resource_relationship: SecretsManagerSecretVersionToAWSAccountRel = (
|
|
109
|
+
SecretsManagerSecretVersionToAWSAccountRel()
|
|
110
|
+
)
|
|
111
|
+
other_relationships: OtherRelationships = OtherRelationships(
|
|
112
|
+
[
|
|
113
|
+
SecretsManagerSecretVersionToSecretRel(),
|
|
114
|
+
SecretsManagerSecretVersionToKMSKeyRel(),
|
|
115
|
+
],
|
|
116
|
+
)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from cartography.models.core.common import PropertyRef
|
|
4
|
+
from cartography.models.core.nodes import CartographyNodeProperties
|
|
5
|
+
from cartography.models.core.nodes import CartographyNodeSchema
|
|
6
|
+
from cartography.models.core.relationships import CartographyRelProperties
|
|
7
|
+
from cartography.models.core.relationships import CartographyRelSchema
|
|
8
|
+
from cartography.models.core.relationships import LinkDirection
|
|
9
|
+
from cartography.models.core.relationships import make_target_node_matcher
|
|
10
|
+
from cartography.models.core.relationships import OtherRelationships
|
|
11
|
+
from cartography.models.core.relationships import TargetNodeMatcher
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class SSMParameterNodeProperties(CartographyNodeProperties):
|
|
16
|
+
|
|
17
|
+
arn: PropertyRef = PropertyRef("ARN", extra_index=True)
|
|
18
|
+
id: PropertyRef = PropertyRef("ARN")
|
|
19
|
+
name: PropertyRef = PropertyRef("Name")
|
|
20
|
+
description: PropertyRef = PropertyRef("Description")
|
|
21
|
+
type: PropertyRef = PropertyRef("Type")
|
|
22
|
+
keyid: PropertyRef = PropertyRef("KeyId")
|
|
23
|
+
kms_key_id_short: PropertyRef = PropertyRef("KMSKeyIdShort")
|
|
24
|
+
version: PropertyRef = PropertyRef("Version")
|
|
25
|
+
lastmodifieddate: PropertyRef = PropertyRef("LastModifiedDate")
|
|
26
|
+
tier: PropertyRef = PropertyRef("Tier")
|
|
27
|
+
lastmodifieduser: PropertyRef = PropertyRef("LastModifiedUser")
|
|
28
|
+
datatype: PropertyRef = PropertyRef("DataType")
|
|
29
|
+
allowedpattern: PropertyRef = PropertyRef("AllowedPattern")
|
|
30
|
+
policies_json: PropertyRef = PropertyRef("PoliciesJson")
|
|
31
|
+
region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
|
|
32
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(frozen=True)
|
|
36
|
+
class SSMParameterToAWSAccountRelProperties(CartographyRelProperties):
|
|
37
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class SSMParameterToAWSAccountRel(CartographyRelSchema):
|
|
42
|
+
target_node_label: str = "AWSAccount"
|
|
43
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
44
|
+
{"id": PropertyRef("AWS_ID", set_in_kwargs=True)},
|
|
45
|
+
)
|
|
46
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
47
|
+
rel_label: str = "RESOURCE"
|
|
48
|
+
properties: SSMParameterToAWSAccountRelProperties = (
|
|
49
|
+
SSMParameterToAWSAccountRelProperties()
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class SSMParameterToKMSKeyRelProperties(CartographyRelProperties):
|
|
55
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass(frozen=True)
|
|
59
|
+
class SSMParameterToKMSKeyRel(CartographyRelSchema):
|
|
60
|
+
target_node_label: str = "KMSKey"
|
|
61
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
62
|
+
{
|
|
63
|
+
"id": PropertyRef("KMSKeyIdShort"),
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
67
|
+
rel_label: str = "ENCRYPTED_BY"
|
|
68
|
+
properties: SSMParameterToKMSKeyRelProperties = SSMParameterToKMSKeyRelProperties()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass(frozen=True)
|
|
72
|
+
class SSMParameterSchema(CartographyNodeSchema):
|
|
73
|
+
|
|
74
|
+
label: str = "SSMParameter"
|
|
75
|
+
properties: SSMParameterNodeProperties = SSMParameterNodeProperties()
|
|
76
|
+
sub_resource_relationship: SSMParameterToAWSAccountRel = (
|
|
77
|
+
SSMParameterToAWSAccountRel()
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
other_relationships: OtherRelationships = OtherRelationships(
|
|
81
|
+
[
|
|
82
|
+
SSMParameterToKMSKeyRel(),
|
|
83
|
+
],
|
|
84
|
+
)
|