cartography 0.102.0rc1__py3-none-any.whl → 0.103.0__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/__main__.py +1 -2
- cartography/_version.py +2 -2
- cartography/cli.py +376 -249
- cartography/client/core/tx.py +39 -18
- cartography/config.py +28 -0
- cartography/driftdetect/__main__.py +1 -2
- cartography/driftdetect/add_shortcut.py +10 -2
- cartography/driftdetect/cli.py +71 -75
- cartography/driftdetect/detect_deviations.py +7 -3
- cartography/driftdetect/get_states.py +20 -8
- cartography/driftdetect/model.py +5 -5
- cartography/driftdetect/serializers.py +8 -6
- cartography/driftdetect/storage.py +2 -2
- cartography/graph/cleanupbuilder.py +35 -15
- cartography/graph/job.py +46 -17
- cartography/graph/querybuilder.py +165 -80
- cartography/graph/statement.py +35 -26
- cartography/intel/analysis.py +4 -1
- cartography/intel/aws/__init__.py +114 -55
- cartography/intel/aws/apigateway.py +134 -63
- cartography/intel/aws/cloudtrail.py +127 -0
- cartography/intel/aws/cloudwatch.py +93 -0
- cartography/intel/aws/config.py +56 -20
- cartography/intel/aws/dynamodb.py +108 -40
- cartography/intel/aws/ec2/__init__.py +2 -2
- cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
- cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
- cartography/intel/aws/ec2/images.py +49 -20
- cartography/intel/aws/ec2/instances.py +234 -136
- cartography/intel/aws/ec2/internet_gateways.py +40 -11
- cartography/intel/aws/ec2/key_pairs.py +44 -20
- cartography/intel/aws/ec2/launch_templates.py +101 -59
- cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
- cartography/intel/aws/ec2/load_balancers.py +82 -42
- cartography/intel/aws/ec2/network_acls.py +89 -65
- cartography/intel/aws/ec2/network_interfaces.py +146 -87
- cartography/intel/aws/ec2/reserved_instances.py +45 -16
- cartography/intel/aws/ec2/route_tables.py +327 -0
- cartography/intel/aws/ec2/security_groups.py +71 -21
- cartography/intel/aws/ec2/snapshots.py +61 -22
- cartography/intel/aws/ec2/subnets.py +54 -18
- cartography/intel/aws/ec2/tgw.py +100 -34
- cartography/intel/aws/ec2/util.py +1 -1
- cartography/intel/aws/ec2/volumes.py +69 -41
- cartography/intel/aws/ec2/vpc.py +37 -12
- cartography/intel/aws/ec2/vpc_peerings.py +83 -24
- cartography/intel/aws/ecr.py +88 -32
- cartography/intel/aws/ecs.py +83 -47
- cartography/intel/aws/efs.py +93 -0
- cartography/intel/aws/eks.py +55 -29
- cartography/intel/aws/elasticache.py +42 -18
- cartography/intel/aws/elasticsearch.py +57 -20
- cartography/intel/aws/emr.py +61 -23
- cartography/intel/aws/iam.py +401 -145
- cartography/intel/aws/iam_instance_profiles.py +22 -22
- cartography/intel/aws/identitycenter.py +71 -37
- cartography/intel/aws/inspector.py +159 -89
- cartography/intel/aws/kms.py +92 -38
- cartography/intel/aws/lambda_function.py +103 -34
- cartography/intel/aws/organizations.py +30 -10
- cartography/intel/aws/permission_relationships.py +133 -51
- cartography/intel/aws/rds.py +249 -85
- cartography/intel/aws/redshift.py +107 -46
- cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
- cartography/intel/aws/resources.py +57 -44
- cartography/intel/aws/route53.py +108 -61
- cartography/intel/aws/s3.py +168 -83
- cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
- cartography/intel/aws/secretsmanager.py +24 -12
- cartography/intel/aws/securityhub.py +20 -9
- cartography/intel/aws/sns.py +166 -0
- cartography/intel/aws/sqs.py +60 -28
- cartography/intel/aws/ssm.py +70 -30
- cartography/intel/aws/util/arns.py +7 -7
- cartography/intel/aws/util/common.py +31 -4
- cartography/intel/azure/__init__.py +78 -19
- cartography/intel/azure/compute.py +101 -27
- cartography/intel/azure/cosmosdb.py +496 -170
- cartography/intel/azure/sql.py +296 -105
- cartography/intel/azure/storage.py +322 -113
- cartography/intel/azure/subscription.py +39 -23
- cartography/intel/azure/tenant.py +13 -4
- cartography/intel/azure/util/credentials.py +95 -55
- cartography/intel/bigfix/__init__.py +2 -2
- cartography/intel/bigfix/computers.py +93 -65
- cartography/intel/cloudflare/__init__.py +74 -0
- cartography/intel/cloudflare/accounts.py +57 -0
- cartography/intel/cloudflare/dnsrecords.py +64 -0
- cartography/intel/cloudflare/members.py +75 -0
- cartography/intel/cloudflare/roles.py +65 -0
- cartography/intel/cloudflare/zones.py +64 -0
- cartography/intel/create_indexes.py +3 -2
- cartography/intel/crowdstrike/__init__.py +11 -9
- cartography/intel/crowdstrike/endpoints.py +5 -1
- cartography/intel/crowdstrike/spotlight.py +8 -3
- cartography/intel/cve/__init__.py +46 -13
- cartography/intel/cve/feed.py +48 -12
- cartography/intel/digitalocean/__init__.py +22 -13
- cartography/intel/digitalocean/compute.py +75 -108
- cartography/intel/digitalocean/management.py +44 -80
- cartography/intel/digitalocean/platform.py +48 -43
- cartography/intel/dns.py +36 -10
- cartography/intel/duo/__init__.py +21 -16
- cartography/intel/duo/api_host.py +14 -9
- cartography/intel/duo/endpoints.py +50 -45
- cartography/intel/duo/groups.py +18 -14
- cartography/intel/duo/phones.py +37 -34
- cartography/intel/duo/tokens.py +26 -23
- cartography/intel/duo/users.py +54 -50
- cartography/intel/duo/web_authn_credentials.py +30 -25
- cartography/intel/entra/__init__.py +25 -7
- cartography/intel/entra/ou.py +112 -0
- cartography/intel/entra/users.py +69 -63
- cartography/intel/gcp/__init__.py +185 -49
- cartography/intel/gcp/compute.py +418 -231
- cartography/intel/gcp/crm.py +96 -43
- cartography/intel/gcp/dns.py +60 -19
- cartography/intel/gcp/gke.py +72 -38
- cartography/intel/gcp/iam.py +61 -41
- cartography/intel/gcp/storage.py +84 -55
- cartography/intel/github/__init__.py +13 -11
- cartography/intel/github/repos.py +270 -137
- cartography/intel/github/teams.py +170 -88
- cartography/intel/github/users.py +70 -39
- cartography/intel/github/util.py +36 -34
- cartography/intel/gsuite/__init__.py +47 -26
- cartography/intel/gsuite/api.py +73 -30
- cartography/intel/jamf/__init__.py +19 -1
- cartography/intel/jamf/computers.py +30 -7
- cartography/intel/jamf/util.py +7 -2
- cartography/intel/kandji/__init__.py +6 -3
- cartography/intel/kandji/devices.py +14 -8
- cartography/intel/kubernetes/namespaces.py +7 -4
- cartography/intel/kubernetes/pods.py +7 -4
- cartography/intel/kubernetes/services.py +8 -4
- cartography/intel/lastpass/__init__.py +2 -2
- cartography/intel/lastpass/users.py +23 -12
- cartography/intel/oci/__init__.py +44 -11
- cartography/intel/oci/iam.py +134 -38
- cartography/intel/oci/organizations.py +13 -6
- cartography/intel/oci/utils.py +43 -20
- cartography/intel/okta/__init__.py +66 -15
- cartography/intel/okta/applications.py +42 -20
- cartography/intel/okta/awssaml.py +93 -33
- cartography/intel/okta/factors.py +16 -4
- cartography/intel/okta/groups.py +56 -29
- cartography/intel/okta/organization.py +5 -1
- cartography/intel/okta/origins.py +6 -2
- cartography/intel/okta/roles.py +15 -5
- cartography/intel/okta/users.py +20 -8
- cartography/intel/okta/utils.py +6 -4
- cartography/intel/openai/__init__.py +86 -0
- cartography/intel/openai/adminapikeys.py +90 -0
- cartography/intel/openai/apikeys.py +96 -0
- cartography/intel/openai/projects.py +94 -0
- cartography/intel/openai/serviceaccounts.py +82 -0
- cartography/intel/openai/users.py +78 -0
- cartography/intel/openai/util.py +29 -0
- cartography/intel/pagerduty/__init__.py +8 -7
- cartography/intel/pagerduty/escalation_policies.py +18 -6
- cartography/intel/pagerduty/schedules.py +12 -4
- cartography/intel/pagerduty/services.py +11 -4
- cartography/intel/pagerduty/teams.py +8 -3
- cartography/intel/pagerduty/users.py +3 -1
- cartography/intel/pagerduty/vendors.py +3 -1
- cartography/intel/semgrep/__init__.py +24 -6
- cartography/intel/semgrep/dependencies.py +50 -28
- cartography/intel/semgrep/deployment.py +3 -1
- cartography/intel/semgrep/findings.py +42 -18
- cartography/intel/snipeit/__init__.py +17 -3
- cartography/intel/snipeit/asset.py +12 -6
- cartography/intel/snipeit/user.py +8 -5
- cartography/intel/snipeit/util.py +9 -4
- cartography/intel/tailscale/__init__.py +77 -0
- cartography/intel/tailscale/acls.py +146 -0
- cartography/intel/tailscale/devices.py +127 -0
- cartography/intel/tailscale/postureintegrations.py +81 -0
- cartography/intel/tailscale/tailnets.py +76 -0
- cartography/intel/tailscale/users.py +80 -0
- cartography/intel/tailscale/utils.py +132 -0
- cartography/models/aws/apigateway.py +21 -17
- cartography/models/aws/apigatewaycertificate.py +28 -22
- cartography/models/aws/apigatewayresource.py +28 -20
- cartography/models/aws/apigatewaystage.py +33 -25
- cartography/models/aws/cloudtrail/__init__.py +0 -0
- cartography/models/aws/cloudtrail/trail.py +61 -0
- cartography/models/aws/cloudwatch/__init__.py +0 -0
- cartography/models/aws/cloudwatch/loggroup.py +52 -0
- cartography/models/aws/dynamodb/gsi.py +30 -22
- cartography/models/aws/dynamodb/tables.py +25 -17
- cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
- cartography/models/aws/ec2/images.py +36 -34
- cartography/models/aws/ec2/instances.py +51 -45
- cartography/models/aws/ec2/keypair.py +21 -16
- cartography/models/aws/ec2/keypair_instance.py +28 -21
- cartography/models/aws/ec2/launch_configurations.py +30 -26
- cartography/models/aws/ec2/launch_template_versions.py +48 -38
- cartography/models/aws/ec2/launch_templates.py +21 -17
- cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
- cartography/models/aws/ec2/load_balancers.py +47 -37
- cartography/models/aws/ec2/network_acl_rules.py +38 -30
- cartography/models/aws/ec2/network_acls.py +38 -29
- cartography/models/aws/ec2/networkinterface_instance.py +52 -39
- cartography/models/aws/ec2/networkinterfaces.py +53 -37
- cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
- cartography/models/aws/ec2/reservations.py +18 -14
- cartography/models/aws/ec2/route_table_associations.py +97 -0
- cartography/models/aws/ec2/route_tables.py +128 -0
- cartography/models/aws/ec2/routes.py +85 -0
- cartography/models/aws/ec2/securitygroup_instance.py +29 -20
- cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
- cartography/models/aws/ec2/subnet_instance.py +24 -19
- cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
- cartography/models/aws/ec2/volumes.py +47 -40
- cartography/models/aws/efs/__init__.py +0 -0
- cartography/models/aws/efs/mount_target.py +52 -0
- cartography/models/aws/eks/clusters.py +23 -21
- cartography/models/aws/emr.py +32 -30
- cartography/models/aws/iam/instanceprofile.py +33 -24
- cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
- cartography/models/aws/identitycenter/awspermissionset.py +37 -29
- cartography/models/aws/identitycenter/awsssouser.py +23 -21
- cartography/models/aws/inspector/findings.py +77 -65
- cartography/models/aws/inspector/packages.py +35 -29
- cartography/models/aws/s3/__init__.py +0 -0
- cartography/models/aws/s3/account_public_access_block.py +51 -0
- cartography/models/aws/sns/__init__.py +0 -0
- cartography/models/aws/sns/topic.py +50 -0
- cartography/models/aws/ssm/instance_information.py +51 -39
- cartography/models/aws/ssm/instance_patch.py +32 -26
- cartography/models/bigfix/bigfix_computer.py +42 -38
- cartography/models/bigfix/bigfix_root.py +3 -3
- cartography/models/cloudflare/__init__.py +0 -0
- cartography/models/cloudflare/account.py +25 -0
- cartography/models/cloudflare/dnsrecord.py +55 -0
- cartography/models/cloudflare/member.py +82 -0
- cartography/models/cloudflare/role.py +44 -0
- cartography/models/cloudflare/zone.py +59 -0
- cartography/models/core/common.py +12 -10
- cartography/models/core/nodes.py +5 -2
- cartography/models/core/relationships.py +14 -6
- cartography/models/crowdstrike/hosts.py +37 -35
- cartography/models/cve/cve.py +34 -32
- cartography/models/cve/cve_feed.py +6 -6
- cartography/models/digitalocean/__init__.py +0 -0
- cartography/models/digitalocean/account.py +21 -0
- cartography/models/digitalocean/droplet.py +56 -0
- cartography/models/digitalocean/project.py +48 -0
- cartography/models/duo/api_host.py +3 -3
- cartography/models/duo/endpoint.py +43 -41
- cartography/models/duo/group.py +14 -14
- cartography/models/duo/phone.py +27 -27
- cartography/models/duo/token.py +16 -16
- cartography/models/duo/user.py +46 -44
- cartography/models/duo/web_authn_credential.py +27 -19
- cartography/models/entra/ou.py +48 -0
- cartography/models/entra/tenant.py +24 -18
- cartography/models/entra/user.py +64 -48
- cartography/models/gcp/iam.py +23 -23
- cartography/models/github/orgs.py +5 -4
- cartography/models/github/teams.py +37 -31
- cartography/models/github/users.py +34 -23
- cartography/models/kandji/device.py +22 -16
- cartography/models/kandji/tenant.py +6 -4
- cartography/models/lastpass/tenant.py +3 -3
- cartography/models/lastpass/user.py +32 -28
- cartography/models/openai/__init__.py +0 -0
- cartography/models/openai/adminapikey.py +90 -0
- cartography/models/openai/apikey.py +84 -0
- cartography/models/openai/organization.py +17 -0
- cartography/models/openai/project.py +70 -0
- cartography/models/openai/serviceaccount.py +50 -0
- cartography/models/openai/user.py +49 -0
- cartography/models/semgrep/dependencies.py +36 -24
- cartography/models/semgrep/deployment.py +5 -5
- cartography/models/semgrep/findings.py +58 -42
- cartography/models/semgrep/locations.py +27 -21
- cartography/models/snipeit/asset.py +30 -21
- cartography/models/snipeit/tenant.py +6 -4
- cartography/models/snipeit/user.py +19 -12
- cartography/models/tailscale/__init__.py +0 -0
- cartography/models/tailscale/device.py +95 -0
- cartography/models/tailscale/group.py +86 -0
- cartography/models/tailscale/postureintegration.py +58 -0
- cartography/models/tailscale/tag.py +102 -0
- cartography/models/tailscale/tailnet.py +29 -0
- cartography/models/tailscale/user.py +52 -0
- cartography/stats.py +3 -3
- cartography/sync.py +113 -31
- cartography/util.py +84 -62
- {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/METADATA +8 -15
- cartography-0.103.0.dist-info/RECORD +442 -0
- {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/WHEEL +1 -1
- cartography-0.102.0rc1.dist-info/RECORD +0 -377
- {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/entry_points.txt +0 -0
- {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/top_level.txt +0 -0
|
@@ -35,18 +35,28 @@ def build_cleanup_queries(node_schema: CartographyNodeSchema) -> List[str]:
|
|
|
35
35
|
:param node_schema: The given CartographyNodeSchema
|
|
36
36
|
:return: A list of Neo4j queries to clean up nodes and relationships.
|
|
37
37
|
"""
|
|
38
|
-
if
|
|
38
|
+
if (
|
|
39
|
+
not node_schema.sub_resource_relationship
|
|
40
|
+
and not node_schema.other_relationships
|
|
41
|
+
):
|
|
39
42
|
return []
|
|
40
43
|
|
|
41
44
|
if not node_schema.sub_resource_relationship:
|
|
42
45
|
queries = []
|
|
43
|
-
other_rels =
|
|
46
|
+
other_rels = (
|
|
47
|
+
node_schema.other_relationships.rels
|
|
48
|
+
if node_schema.other_relationships
|
|
49
|
+
else []
|
|
50
|
+
)
|
|
44
51
|
for rel in other_rels:
|
|
45
52
|
query = _build_cleanup_rel_query_no_sub_resource(node_schema, rel)
|
|
46
53
|
queries.append(query)
|
|
47
54
|
return queries
|
|
48
55
|
|
|
49
|
-
result = _build_cleanup_node_and_rel_queries(
|
|
56
|
+
result = _build_cleanup_node_and_rel_queries(
|
|
57
|
+
node_schema,
|
|
58
|
+
node_schema.sub_resource_relationship,
|
|
59
|
+
)
|
|
50
60
|
if node_schema.other_relationships:
|
|
51
61
|
for rel in node_schema.other_relationships.rels:
|
|
52
62
|
# [0] is the delete node query, [1] is the delete relationship query. We only want the latter.
|
|
@@ -57,16 +67,16 @@ def build_cleanup_queries(node_schema: CartographyNodeSchema) -> List[str]:
|
|
|
57
67
|
|
|
58
68
|
|
|
59
69
|
def _build_cleanup_rel_query_no_sub_resource(
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
node_schema: CartographyNodeSchema,
|
|
71
|
+
selected_relationship: CartographyRelSchema,
|
|
62
72
|
) -> str:
|
|
63
73
|
"""
|
|
64
74
|
Helper function to delete stale relationships for node_schemas that have no sub resource relationship defined.
|
|
65
75
|
"""
|
|
66
76
|
if node_schema.sub_resource_relationship:
|
|
67
77
|
raise ValueError(
|
|
68
|
-
f
|
|
69
|
-
|
|
78
|
+
f"Expected {node_schema.label} to not exist. "
|
|
79
|
+
"This function is intended for node_schemas without sub_resource_relationships.",
|
|
70
80
|
)
|
|
71
81
|
# Ensure the node is attached to the sub resource and delete the node
|
|
72
82
|
query_template = Template(
|
|
@@ -85,8 +95,8 @@ def _build_cleanup_rel_query_no_sub_resource(
|
|
|
85
95
|
|
|
86
96
|
|
|
87
97
|
def _build_cleanup_node_and_rel_queries(
|
|
88
|
-
|
|
89
|
-
|
|
98
|
+
node_schema: CartographyNodeSchema,
|
|
99
|
+
selected_relationship: CartographyRelSchema,
|
|
90
100
|
) -> List[str]:
|
|
91
101
|
"""
|
|
92
102
|
Private function that performs the main string template logic for generating cleanup node and relationship queries.
|
|
@@ -129,7 +139,9 @@ def _build_cleanup_node_and_rel_queries(
|
|
|
129
139
|
]
|
|
130
140
|
# Now clean up the relationships
|
|
131
141
|
if selected_relationship == node_schema.sub_resource_relationship:
|
|
132
|
-
_validate_target_node_matcher_for_cleanup_job(
|
|
142
|
+
_validate_target_node_matcher_for_cleanup_job(
|
|
143
|
+
node_schema.sub_resource_relationship.target_node_matcher,
|
|
144
|
+
)
|
|
133
145
|
delete_action_clauses.append(
|
|
134
146
|
"""
|
|
135
147
|
WHERE s.lastupdated <> $UPDATE_TAG
|
|
@@ -159,13 +171,17 @@ def _build_cleanup_node_and_rel_queries(
|
|
|
159
171
|
node_label=node_schema.label,
|
|
160
172
|
sub_resource_link=sub_resource_link,
|
|
161
173
|
sub_resource_label=node_schema.sub_resource_relationship.target_node_label,
|
|
162
|
-
match_sub_res_clause=_build_match_clause(
|
|
174
|
+
match_sub_res_clause=_build_match_clause(
|
|
175
|
+
node_schema.sub_resource_relationship.target_node_matcher,
|
|
176
|
+
),
|
|
163
177
|
selected_rel_clause=(
|
|
164
|
-
""
|
|
178
|
+
""
|
|
179
|
+
if selected_relationship == node_schema.sub_resource_relationship
|
|
165
180
|
else _build_selected_rel_clause(selected_relationship)
|
|
166
181
|
),
|
|
167
182
|
delete_action_clause=delete_action_clause,
|
|
168
|
-
)
|
|
183
|
+
)
|
|
184
|
+
for delete_action_clause in delete_action_clauses
|
|
169
185
|
]
|
|
170
186
|
|
|
171
187
|
|
|
@@ -179,8 +195,12 @@ def _build_selected_rel_clause(selected_relationship: CartographyRelSchema) -> s
|
|
|
179
195
|
selected_rel_template = Template("<-[r:$SelectedRelLabel]-")
|
|
180
196
|
else:
|
|
181
197
|
selected_rel_template = Template("-[r:$SelectedRelLabel]->")
|
|
182
|
-
selected_rel = selected_rel_template.safe_substitute(
|
|
183
|
-
|
|
198
|
+
selected_rel = selected_rel_template.safe_substitute(
|
|
199
|
+
SelectedRelLabel=selected_relationship.rel_label,
|
|
200
|
+
)
|
|
201
|
+
selected_rel_clause_template = Template(
|
|
202
|
+
"""MATCH (n)$selected_rel(:$other_node_label)""",
|
|
203
|
+
)
|
|
184
204
|
selected_rel_clause = selected_rel_clause_template.safe_substitute(
|
|
185
205
|
selected_rel=selected_rel,
|
|
186
206
|
other_node_label=selected_relationship.target_node_label,
|
cartography/graph/job.py
CHANGED
|
@@ -32,7 +32,7 @@ def _get_identifiers(template: string.Template) -> List[str]:
|
|
|
32
32
|
filter(
|
|
33
33
|
lambda v: v is not None,
|
|
34
34
|
(
|
|
35
|
-
mo.group(
|
|
35
|
+
mo.group("named") or mo.group("braced")
|
|
36
36
|
for mo in template.pattern.finditer(template.template)
|
|
37
37
|
),
|
|
38
38
|
),
|
|
@@ -71,7 +71,12 @@ class GraphJob:
|
|
|
71
71
|
A job that will run against the cartography graph. A job is a sequence of statements which execute sequentially.
|
|
72
72
|
"""
|
|
73
73
|
|
|
74
|
-
def __init__(
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
name: str,
|
|
77
|
+
statements: List[GraphStatement],
|
|
78
|
+
short_name: Optional[str] = None,
|
|
79
|
+
):
|
|
75
80
|
# E.g. "Okta intel module cleanup"
|
|
76
81
|
self.name = name
|
|
77
82
|
self.statements: List[GraphStatement] = statements
|
|
@@ -100,7 +105,11 @@ class GraphJob:
|
|
|
100
105
|
e,
|
|
101
106
|
)
|
|
102
107
|
raise
|
|
103
|
-
log_msg =
|
|
108
|
+
log_msg = (
|
|
109
|
+
f"Finished job {self.short_name}"
|
|
110
|
+
if self.short_name
|
|
111
|
+
else f"Finished job {self.name}"
|
|
112
|
+
)
|
|
104
113
|
logger.info(log_msg)
|
|
105
114
|
|
|
106
115
|
def as_dict(self) -> Dict:
|
|
@@ -114,7 +123,7 @@ class GraphJob:
|
|
|
114
123
|
}
|
|
115
124
|
|
|
116
125
|
@classmethod
|
|
117
|
-
def from_json(cls, blob: str, short_name: Optional[str] = None) ->
|
|
126
|
+
def from_json(cls, blob: str, short_name: Optional[str] = None) -> "GraphJob":
|
|
118
127
|
"""
|
|
119
128
|
Create a job from a JSON blob.
|
|
120
129
|
"""
|
|
@@ -125,10 +134,10 @@ class GraphJob:
|
|
|
125
134
|
|
|
126
135
|
@classmethod
|
|
127
136
|
def from_node_schema(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
) ->
|
|
137
|
+
cls,
|
|
138
|
+
node_schema: CartographyNodeSchema,
|
|
139
|
+
parameters: Dict[str, Any],
|
|
140
|
+
) -> "GraphJob":
|
|
132
141
|
"""
|
|
133
142
|
Create a cleanup job from a CartographyNodeSchema object.
|
|
134
143
|
For a given node, the fields used in the node_schema.sub_resource_relationship.target_node_node_matcher.keys()
|
|
@@ -139,14 +148,14 @@ class GraphJob:
|
|
|
139
148
|
expected_param_keys: Set[str] = get_parameters(queries)
|
|
140
149
|
actual_param_keys: Set[str] = set(parameters.keys())
|
|
141
150
|
# Hacky, but LIMIT_SIZE is specified by default in cartography.graph.statement, so we exclude it from validation
|
|
142
|
-
actual_param_keys.add(
|
|
151
|
+
actual_param_keys.add("LIMIT_SIZE")
|
|
143
152
|
|
|
144
153
|
missing_params: Set[str] = expected_param_keys - actual_param_keys
|
|
145
154
|
|
|
146
155
|
if missing_params:
|
|
147
156
|
raise ValueError(
|
|
148
157
|
f'GraphJob is missing the following expected query parameters: "{missing_params}". Please check the '
|
|
149
|
-
f
|
|
158
|
+
f"value passed to `parameters`.",
|
|
150
159
|
)
|
|
151
160
|
|
|
152
161
|
statements: List[GraphStatement] = [
|
|
@@ -157,7 +166,8 @@ class GraphJob:
|
|
|
157
166
|
iterationsize=100,
|
|
158
167
|
parent_job_name=node_schema.label,
|
|
159
168
|
parent_job_sequence_num=idx,
|
|
160
|
-
)
|
|
169
|
+
)
|
|
170
|
+
for idx, query in enumerate(queries, start=1)
|
|
161
171
|
]
|
|
162
172
|
|
|
163
173
|
return cls(
|
|
@@ -167,7 +177,7 @@ class GraphJob:
|
|
|
167
177
|
)
|
|
168
178
|
|
|
169
179
|
@classmethod
|
|
170
|
-
def from_json_file(cls, file_path: Union[str, Path]) ->
|
|
180
|
+
def from_json_file(cls, file_path: Union[str, Path]) -> "GraphJob":
|
|
171
181
|
"""
|
|
172
182
|
Create a job from a JSON file.
|
|
173
183
|
"""
|
|
@@ -175,13 +185,20 @@ class GraphJob:
|
|
|
175
185
|
data: Dict = json.load(j_file)
|
|
176
186
|
|
|
177
187
|
job_shortname: str = get_job_shortname(file_path)
|
|
178
|
-
statements: List[GraphStatement] = _get_statements_from_json(
|
|
188
|
+
statements: List[GraphStatement] = _get_statements_from_json(
|
|
189
|
+
data,
|
|
190
|
+
job_shortname,
|
|
191
|
+
)
|
|
179
192
|
name: str = data["name"]
|
|
180
193
|
return cls(name, statements, job_shortname)
|
|
181
194
|
|
|
182
195
|
@classmethod
|
|
183
196
|
def run_from_json(
|
|
184
|
-
cls,
|
|
197
|
+
cls,
|
|
198
|
+
neo4j_session: neo4j.Session,
|
|
199
|
+
blob: str,
|
|
200
|
+
parameters: Dict,
|
|
201
|
+
short_name: Optional[str] = None,
|
|
185
202
|
) -> None:
|
|
186
203
|
"""
|
|
187
204
|
Run a job from a JSON blob. This will deserialize the job and execute all statements sequentially.
|
|
@@ -194,7 +211,12 @@ class GraphJob:
|
|
|
194
211
|
job.run(neo4j_session)
|
|
195
212
|
|
|
196
213
|
@classmethod
|
|
197
|
-
def run_from_json_file(
|
|
214
|
+
def run_from_json_file(
|
|
215
|
+
cls,
|
|
216
|
+
file_path: Union[str, Path],
|
|
217
|
+
neo4j_session: neo4j.Session,
|
|
218
|
+
parameters: Dict,
|
|
219
|
+
) -> None:
|
|
198
220
|
"""
|
|
199
221
|
Run a job from a JSON file. This will deserialize the job and execute all statements sequentially.
|
|
200
222
|
"""
|
|
@@ -207,14 +229,21 @@ class GraphJob:
|
|
|
207
229
|
job.run(neo4j_session)
|
|
208
230
|
|
|
209
231
|
|
|
210
|
-
def _get_statements_from_json(
|
|
232
|
+
def _get_statements_from_json(
|
|
233
|
+
blob: Dict,
|
|
234
|
+
short_job_name: Optional[str] = None,
|
|
235
|
+
) -> List[GraphStatement]:
|
|
211
236
|
"""
|
|
212
237
|
Deserialize all statements from the JSON blob.
|
|
213
238
|
"""
|
|
214
239
|
statements: List[GraphStatement] = []
|
|
215
240
|
for i, statement_data in enumerate(blob["statements"]):
|
|
216
241
|
# i+1 to make it 1-based and not 0-based to help with log readability
|
|
217
|
-
statement: GraphStatement = GraphStatement.create_from_json(
|
|
242
|
+
statement: GraphStatement = GraphStatement.create_from_json(
|
|
243
|
+
statement_data,
|
|
244
|
+
short_job_name,
|
|
245
|
+
i + 1,
|
|
246
|
+
)
|
|
218
247
|
statements.append(statement)
|
|
219
248
|
|
|
220
249
|
return statements
|