cartography 0.107.0rc1__py3-none-any.whl → 0.107.0rc3__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/intel/aws/cloudwatch.py +77 -0
- cartography/intel/aws/ec2/subnets.py +1 -1
- cartography/intel/aws/ecs.py +17 -0
- cartography/intel/aws/inspector.py +77 -48
- cartography/intel/sentinelone/__init__.py +8 -2
- cartography/intel/sentinelone/application.py +248 -0
- cartography/intel/sentinelone/utils.py +20 -1
- cartography/models/aws/cloudwatch/log_metric_filter.py +79 -0
- cartography/models/aws/ec2/networkinterfaces.py +2 -0
- cartography/models/aws/ec2/subnet_instance.py +2 -0
- cartography/models/aws/ec2/subnet_networkinterface.py +2 -0
- cartography/models/aws/ecs/tasks.py +24 -1
- cartography/models/aws/inspector/findings.py +37 -0
- cartography/models/aws/inspector/packages.py +1 -31
- cartography/models/sentinelone/application.py +44 -0
- cartography/models/sentinelone/application_version.py +96 -0
- {cartography-0.107.0rc1.dist-info → cartography-0.107.0rc3.dist-info}/METADATA +1 -1
- {cartography-0.107.0rc1.dist-info → cartography-0.107.0rc3.dist-info}/RECORD +23 -19
- {cartography-0.107.0rc1.dist-info → cartography-0.107.0rc3.dist-info}/WHEEL +0 -0
- {cartography-0.107.0rc1.dist-info → cartography-0.107.0rc3.dist-info}/entry_points.txt +0 -0
- {cartography-0.107.0rc1.dist-info → cartography-0.107.0rc3.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.107.0rc1.dist-info → cartography-0.107.0rc3.dist-info}/top_level.txt +0 -0
cartography/_version.py
CHANGED
|
@@ -17,5 +17,5 @@ __version__: str
|
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
|
18
18
|
version_tuple: VERSION_TUPLE
|
|
19
19
|
|
|
20
|
-
__version__ = version = '0.107.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 107, 0, '
|
|
20
|
+
__version__ = version = '0.107.0rc3'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 107, 0, 'rc3')
|
|
@@ -9,6 +9,9 @@ import neo4j
|
|
|
9
9
|
from cartography.client.core.tx import load
|
|
10
10
|
from cartography.graph.job import GraphJob
|
|
11
11
|
from cartography.intel.aws.ec2.util import get_botocore_config
|
|
12
|
+
from cartography.models.aws.cloudwatch.log_metric_filter import (
|
|
13
|
+
CloudWatchLogMetricFilterSchema,
|
|
14
|
+
)
|
|
12
15
|
from cartography.models.aws.cloudwatch.loggroup import CloudWatchLogGroupSchema
|
|
13
16
|
from cartography.util import aws_handle_regions
|
|
14
17
|
from cartography.util import timeit
|
|
@@ -31,6 +34,47 @@ def get_cloudwatch_log_groups(
|
|
|
31
34
|
return logGroups
|
|
32
35
|
|
|
33
36
|
|
|
37
|
+
@timeit
|
|
38
|
+
@aws_handle_regions
|
|
39
|
+
def get_cloudwatch_log_metric_filters(
|
|
40
|
+
boto3_session: boto3.Session, region: str
|
|
41
|
+
) -> List[Dict[str, Any]]:
|
|
42
|
+
logs_client = boto3_session.client(
|
|
43
|
+
"logs", region_name=region, config=get_botocore_config()
|
|
44
|
+
)
|
|
45
|
+
paginator = logs_client.get_paginator("describe_metric_filters")
|
|
46
|
+
metric_filters = []
|
|
47
|
+
|
|
48
|
+
for page in paginator.paginate():
|
|
49
|
+
metric_filters.extend(page.get("metricFilters", []))
|
|
50
|
+
|
|
51
|
+
return metric_filters
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def transform_metric_filters(
|
|
55
|
+
metric_filters: List[Dict[str, Any]], region: str
|
|
56
|
+
) -> List[Dict[str, Any]]:
|
|
57
|
+
"""
|
|
58
|
+
Transform CloudWatch log metric filter data for ingestion into Neo4j.
|
|
59
|
+
Ensures that the 'id' field is a unique combination of logGroupName and filterName.
|
|
60
|
+
"""
|
|
61
|
+
transformed_filters = []
|
|
62
|
+
for filter in metric_filters:
|
|
63
|
+
transformed_filter = {
|
|
64
|
+
"id": f"{filter['logGroupName']}:{filter['filterName']}",
|
|
65
|
+
"arn": f"{filter['logGroupName']}:{filter['filterName']}",
|
|
66
|
+
"filterName": filter["filterName"],
|
|
67
|
+
"filterPattern": filter.get("filterPattern"),
|
|
68
|
+
"logGroupName": filter["logGroupName"],
|
|
69
|
+
"metricName": filter["metricTransformations"][0]["metricName"],
|
|
70
|
+
"metricNamespace": filter["metricTransformations"][0]["metricNamespace"],
|
|
71
|
+
"metricValue": filter["metricTransformations"][0]["metricValue"],
|
|
72
|
+
"Region": region,
|
|
73
|
+
}
|
|
74
|
+
transformed_filters.append(transformed_filter)
|
|
75
|
+
return transformed_filters
|
|
76
|
+
|
|
77
|
+
|
|
34
78
|
@timeit
|
|
35
79
|
def load_cloudwatch_log_groups(
|
|
36
80
|
neo4j_session: neo4j.Session,
|
|
@@ -52,6 +96,27 @@ def load_cloudwatch_log_groups(
|
|
|
52
96
|
)
|
|
53
97
|
|
|
54
98
|
|
|
99
|
+
@timeit
|
|
100
|
+
def load_cloudwatch_log_metric_filters(
|
|
101
|
+
neo4j_session: neo4j.Session,
|
|
102
|
+
data: List[Dict[str, Any]],
|
|
103
|
+
region: str,
|
|
104
|
+
current_aws_account_id: str,
|
|
105
|
+
aws_update_tag: int,
|
|
106
|
+
) -> None:
|
|
107
|
+
logger.info(
|
|
108
|
+
f"Loading CloudWatch {len(data)} log metric filters for region '{region}' into graph.",
|
|
109
|
+
)
|
|
110
|
+
load(
|
|
111
|
+
neo4j_session,
|
|
112
|
+
CloudWatchLogMetricFilterSchema(),
|
|
113
|
+
data,
|
|
114
|
+
lastupdated=aws_update_tag,
|
|
115
|
+
Region=region,
|
|
116
|
+
AWS_ID=current_aws_account_id,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
55
120
|
@timeit
|
|
56
121
|
def cleanup(
|
|
57
122
|
neo4j_session: neo4j.Session,
|
|
@@ -62,6 +127,9 @@ def cleanup(
|
|
|
62
127
|
CloudWatchLogGroupSchema(), common_job_parameters
|
|
63
128
|
)
|
|
64
129
|
cleanup_job.run(neo4j_session)
|
|
130
|
+
GraphJob.from_node_schema(
|
|
131
|
+
CloudWatchLogMetricFilterSchema(), common_job_parameters
|
|
132
|
+
).run(neo4j_session)
|
|
65
133
|
|
|
66
134
|
|
|
67
135
|
@timeit
|
|
@@ -90,4 +158,13 @@ def sync(
|
|
|
90
158
|
update_tag,
|
|
91
159
|
)
|
|
92
160
|
|
|
161
|
+
metric_filters = get_cloudwatch_log_metric_filters(boto3_session, region)
|
|
162
|
+
transformed_filters = transform_metric_filters(metric_filters, region)
|
|
163
|
+
load_cloudwatch_log_metric_filters(
|
|
164
|
+
neo4j_session,
|
|
165
|
+
transformed_filters,
|
|
166
|
+
region,
|
|
167
|
+
current_aws_account_id,
|
|
168
|
+
update_tag,
|
|
169
|
+
)
|
|
93
170
|
cleanup(neo4j_session, common_job_parameters)
|
|
@@ -53,7 +53,7 @@ def load_subnets(
|
|
|
53
53
|
snet.state = subnet.State, snet.assignipv6addressoncreation = subnet.AssignIpv6AddressOnCreation,
|
|
54
54
|
snet.map_public_ip_on_launch = subnet.MapPublicIpOnLaunch, snet.subnet_arn = subnet.SubnetArn,
|
|
55
55
|
snet.availability_zone = subnet.AvailabilityZone, snet.availability_zone_id = subnet.AvailabilityZoneId,
|
|
56
|
-
snet.
|
|
56
|
+
snet.subnet_id = subnet.SubnetId
|
|
57
57
|
"""
|
|
58
58
|
|
|
59
59
|
ingest_subnet_vpc_relations = """
|
cartography/intel/aws/ecs.py
CHANGED
|
@@ -169,6 +169,22 @@ def _get_containers_from_tasks(tasks: list[dict[str, Any]]) -> list[dict[str, An
|
|
|
169
169
|
return containers
|
|
170
170
|
|
|
171
171
|
|
|
172
|
+
def transform_ecs_tasks(tasks: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
173
|
+
"""
|
|
174
|
+
Extract network interface ID from task attachments.
|
|
175
|
+
"""
|
|
176
|
+
for task in tasks:
|
|
177
|
+
for attachment in task.get("attachments", []):
|
|
178
|
+
if attachment.get("type") == "ElasticNetworkInterface":
|
|
179
|
+
details = attachment.get("details", [])
|
|
180
|
+
for detail in details:
|
|
181
|
+
if detail.get("name") == "networkInterfaceId":
|
|
182
|
+
task["networkInterfaceId"] = detail.get("value")
|
|
183
|
+
break
|
|
184
|
+
break
|
|
185
|
+
return tasks
|
|
186
|
+
|
|
187
|
+
|
|
172
188
|
@timeit
|
|
173
189
|
def load_ecs_clusters(
|
|
174
190
|
neo4j_session: neo4j.Session,
|
|
@@ -407,6 +423,7 @@ def _sync_ecs_task_and_container_defns(
|
|
|
407
423
|
boto3_session,
|
|
408
424
|
region,
|
|
409
425
|
)
|
|
426
|
+
tasks = transform_ecs_tasks(tasks)
|
|
410
427
|
containers = _get_containers_from_tasks(tasks)
|
|
411
428
|
load_ecs_tasks(
|
|
412
429
|
neo4j_session,
|
|
@@ -3,14 +3,17 @@ from typing import Any
|
|
|
3
3
|
from typing import Dict
|
|
4
4
|
from typing import Iterator
|
|
5
5
|
from typing import List
|
|
6
|
+
from typing import Set
|
|
6
7
|
from typing import Tuple
|
|
7
8
|
|
|
8
9
|
import boto3
|
|
9
10
|
import neo4j
|
|
10
11
|
|
|
11
12
|
from cartography.client.core.tx import load
|
|
13
|
+
from cartography.client.core.tx import load_matchlinks
|
|
12
14
|
from cartography.graph.job import GraphJob
|
|
13
15
|
from cartography.models.aws.inspector.findings import AWSInspectorFindingSchema
|
|
16
|
+
from cartography.models.aws.inspector.findings import InspectorFindingToPackageMatchLink
|
|
14
17
|
from cartography.models.aws.inspector.packages import AWSInspectorPackageSchema
|
|
15
18
|
from cartography.util import aws_handle_regions
|
|
16
19
|
from cartography.util import aws_paginate
|
|
@@ -107,9 +110,10 @@ def get_inspector_findings(
|
|
|
107
110
|
|
|
108
111
|
def transform_inspector_findings(
|
|
109
112
|
results: List[Dict[str, Any]],
|
|
110
|
-
) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
|
|
113
|
+
) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]], List[Dict[str, str]]]:
|
|
111
114
|
findings_list: List[Dict] = []
|
|
112
|
-
|
|
115
|
+
packages_set: Set[frozenset] = set()
|
|
116
|
+
finding_to_package_map: List[Dict[str, str]] = []
|
|
113
117
|
|
|
114
118
|
for f in results:
|
|
115
119
|
finding: Dict = {}
|
|
@@ -163,55 +167,45 @@ def transform_inspector_findings(
|
|
|
163
167
|
"vendorUpdatedAt",
|
|
164
168
|
)
|
|
165
169
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
packages = transform_inspector_packages(f["packageVulnerabilityDetails"])
|
|
171
|
+
finding["vulnerablepackageids"] = list(packages.keys())
|
|
172
|
+
for package_id, package in packages.items():
|
|
173
|
+
finding_to_package_map.append(
|
|
174
|
+
{
|
|
175
|
+
"findingarn": finding["id"],
|
|
176
|
+
"packageid": package_id,
|
|
177
|
+
"remediation": package.get("remediation"),
|
|
178
|
+
"fixedInVersion": package.get("fixedInVersion"),
|
|
179
|
+
"filePath": package.get("filePath"),
|
|
180
|
+
"sourceLayerHash": package.get("sourceLayerHash"),
|
|
181
|
+
"sourceLambdaLayerArn": package.get("sourceLambdaLayerArn"),
|
|
182
|
+
}
|
|
183
|
+
)
|
|
184
|
+
packages_set.add(frozenset(package.items()))
|
|
174
185
|
findings_list.append(finding)
|
|
175
|
-
packages_list =
|
|
176
|
-
return findings_list, packages_list
|
|
177
|
-
|
|
186
|
+
packages_list = [dict(p) for p in packages_set]
|
|
187
|
+
return findings_list, packages_list, finding_to_package_map
|
|
178
188
|
|
|
179
|
-
def transform_inspector_packages(packages: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
180
|
-
packages_list: List[Dict] = []
|
|
181
|
-
for package_id in packages.keys():
|
|
182
|
-
packages_list.append(packages[package_id])
|
|
183
189
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def _process_packages(
|
|
190
|
+
def transform_inspector_packages(
|
|
188
191
|
package_details: Dict[str, Any],
|
|
189
|
-
aws_account_id: str,
|
|
190
|
-
finding_arn: str,
|
|
191
192
|
) -> Dict[str, Any]:
|
|
192
193
|
packages: Dict[str, Any] = {}
|
|
193
194
|
for package in package_details["vulnerablePackages"]:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
f"{
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
new_package["filepath"] = package.get("filePath")
|
|
209
|
-
new_package["fixedinversion"] = package.get("fixedInVersion")
|
|
210
|
-
new_package["sourcelayerhash"] = package.get("sourceLayerHash")
|
|
211
|
-
new_package["awsaccount"] = aws_account_id
|
|
212
|
-
new_package["findingarn"] = finding_arn
|
|
213
|
-
|
|
214
|
-
packages[new_package["id"]] = new_package
|
|
195
|
+
# Following RPM package naming convention for consistency
|
|
196
|
+
name = package["name"] # Mandatory field
|
|
197
|
+
epoch = str(package.get("epoch", ""))
|
|
198
|
+
if epoch:
|
|
199
|
+
epoch = f"{epoch}:"
|
|
200
|
+
version = package["version"] # Mandatory field
|
|
201
|
+
release = package.get("release", "")
|
|
202
|
+
if release:
|
|
203
|
+
release = f"-{release}"
|
|
204
|
+
arch = package.get("arch", "")
|
|
205
|
+
if arch:
|
|
206
|
+
arch = f".{arch}"
|
|
207
|
+
id = f"{name}|{epoch}{version}{release}{arch}"
|
|
208
|
+
packages[id] = {**package, "id": id}
|
|
215
209
|
|
|
216
210
|
return packages
|
|
217
211
|
|
|
@@ -244,7 +238,6 @@ def load_inspector_findings(
|
|
|
244
238
|
def load_inspector_packages(
|
|
245
239
|
neo4j_session: neo4j.Session,
|
|
246
240
|
packages: List[Dict[str, Any]],
|
|
247
|
-
region: str,
|
|
248
241
|
aws_update_tag: int,
|
|
249
242
|
current_aws_account_id: str,
|
|
250
243
|
) -> None:
|
|
@@ -252,12 +245,28 @@ def load_inspector_packages(
|
|
|
252
245
|
neo4j_session,
|
|
253
246
|
AWSInspectorPackageSchema(),
|
|
254
247
|
packages,
|
|
255
|
-
Region=region,
|
|
256
248
|
AWS_ID=current_aws_account_id,
|
|
257
249
|
lastupdated=aws_update_tag,
|
|
258
250
|
)
|
|
259
251
|
|
|
260
252
|
|
|
253
|
+
@timeit
|
|
254
|
+
def load_inspector_finding_to_package_match_links(
|
|
255
|
+
neo4j_session: neo4j.Session,
|
|
256
|
+
finding_to_package_map: List[Dict[str, str]],
|
|
257
|
+
aws_update_tag: int,
|
|
258
|
+
current_aws_account_id: str,
|
|
259
|
+
) -> None:
|
|
260
|
+
load_matchlinks(
|
|
261
|
+
neo4j_session,
|
|
262
|
+
InspectorFindingToPackageMatchLink(),
|
|
263
|
+
finding_to_package_map,
|
|
264
|
+
lastupdated=aws_update_tag,
|
|
265
|
+
_sub_resource_label="AWSAccount",
|
|
266
|
+
_sub_resource_id=current_aws_account_id,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
|
|
261
270
|
@timeit
|
|
262
271
|
def cleanup(
|
|
263
272
|
neo4j_session: neo4j.Session,
|
|
@@ -270,6 +279,14 @@ def cleanup(
|
|
|
270
279
|
GraphJob.from_node_schema(AWSInspectorPackageSchema(), common_job_parameters).run(
|
|
271
280
|
neo4j_session,
|
|
272
281
|
)
|
|
282
|
+
GraphJob.from_matchlink(
|
|
283
|
+
InspectorFindingToPackageMatchLink(),
|
|
284
|
+
"AWSAccount",
|
|
285
|
+
common_job_parameters["ACCOUNT_ID"],
|
|
286
|
+
common_job_parameters["UPDATE_TAG"],
|
|
287
|
+
).run(
|
|
288
|
+
neo4j_session,
|
|
289
|
+
)
|
|
273
290
|
|
|
274
291
|
|
|
275
292
|
def _sync_findings_for_account(
|
|
@@ -288,7 +305,9 @@ def _sync_findings_for_account(
|
|
|
288
305
|
logger.info(f"No findings to sync for account {account_id} in region {region}")
|
|
289
306
|
return
|
|
290
307
|
for f_batch in findings:
|
|
291
|
-
finding_data, package_data =
|
|
308
|
+
finding_data, package_data, finding_to_package_map = (
|
|
309
|
+
transform_inspector_findings(f_batch)
|
|
310
|
+
)
|
|
292
311
|
logger.info(f"Loading {len(finding_data)} findings from account {account_id}")
|
|
293
312
|
load_inspector_findings(
|
|
294
313
|
neo4j_session,
|
|
@@ -301,7 +320,15 @@ def _sync_findings_for_account(
|
|
|
301
320
|
load_inspector_packages(
|
|
302
321
|
neo4j_session,
|
|
303
322
|
package_data,
|
|
304
|
-
|
|
323
|
+
update_tag,
|
|
324
|
+
current_aws_account_id,
|
|
325
|
+
)
|
|
326
|
+
logger.info(
|
|
327
|
+
f"Loading {len(finding_to_package_map)} finding to package relationships"
|
|
328
|
+
)
|
|
329
|
+
load_inspector_finding_to_package_match_links(
|
|
330
|
+
neo4j_session,
|
|
331
|
+
finding_to_package_map,
|
|
305
332
|
update_tag,
|
|
306
333
|
current_aws_account_id,
|
|
307
334
|
)
|
|
@@ -337,5 +364,7 @@ def sync(
|
|
|
337
364
|
update_tag,
|
|
338
365
|
current_aws_account_id,
|
|
339
366
|
)
|
|
367
|
+
common_job_parameters["ACCOUNT_ID"] = current_aws_account_id
|
|
368
|
+
common_job_parameters["UPDATE_TAG"] = update_tag
|
|
340
369
|
|
|
341
370
|
cleanup(neo4j_session, common_job_parameters)
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
import neo4j
|
|
4
4
|
|
|
5
5
|
import cartography.intel.sentinelone.agent
|
|
6
|
+
import cartography.intel.sentinelone.application
|
|
6
7
|
from cartography.config import Config
|
|
7
8
|
from cartography.intel.sentinelone.account import sync_accounts
|
|
8
9
|
from cartography.stats import get_stats_client
|
|
@@ -39,7 +40,7 @@ def start_sentinelone_ingestion(neo4j_session: neo4j.Session, config: Config) ->
|
|
|
39
40
|
config.sentinelone_account_ids,
|
|
40
41
|
)
|
|
41
42
|
|
|
42
|
-
# Sync agents for each account
|
|
43
|
+
# Sync agents and applications for each account
|
|
43
44
|
for account_id in synced_account_ids:
|
|
44
45
|
# Add account-specific parameter
|
|
45
46
|
common_job_parameters["S1_ACCOUNT_ID"] = account_id
|
|
@@ -49,7 +50,12 @@ def start_sentinelone_ingestion(neo4j_session: neo4j.Session, config: Config) ->
|
|
|
49
50
|
common_job_parameters,
|
|
50
51
|
)
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
cartography.intel.sentinelone.application.sync(
|
|
54
|
+
neo4j_session,
|
|
55
|
+
common_job_parameters,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Clean up account-specific parameters
|
|
53
59
|
del common_job_parameters["S1_ACCOUNT_ID"]
|
|
54
60
|
|
|
55
61
|
# Record that the sync is complete
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import neo4j
|
|
5
|
+
|
|
6
|
+
from cartography.client.core.tx import load
|
|
7
|
+
from cartography.graph.job import GraphJob
|
|
8
|
+
from cartography.intel.sentinelone.api import get_paginated_results
|
|
9
|
+
from cartography.intel.sentinelone.utils import get_application_id
|
|
10
|
+
from cartography.intel.sentinelone.utils import get_application_version_id
|
|
11
|
+
from cartography.models.sentinelone.application import S1ApplicationSchema
|
|
12
|
+
from cartography.models.sentinelone.application_version import (
|
|
13
|
+
S1ApplicationVersionSchema,
|
|
14
|
+
)
|
|
15
|
+
from cartography.util import timeit
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@timeit
|
|
21
|
+
def get_application_data(
|
|
22
|
+
account_id: str, api_url: str, api_token: str
|
|
23
|
+
) -> list[dict[str, Any]]:
|
|
24
|
+
"""
|
|
25
|
+
Get application data from SentinelOne API
|
|
26
|
+
:param account_id: SentinelOne account ID
|
|
27
|
+
:param api_url: SentinelOne API URL
|
|
28
|
+
:param api_token: SentinelOne API token
|
|
29
|
+
:return: A list of application data dictionaries
|
|
30
|
+
"""
|
|
31
|
+
logger.info(f"Retrieving SentinelOne application data for account {account_id}")
|
|
32
|
+
applications = get_paginated_results(
|
|
33
|
+
api_url=api_url,
|
|
34
|
+
endpoint="/web/api/v2.1/application-management/inventory",
|
|
35
|
+
api_token=api_token,
|
|
36
|
+
params={
|
|
37
|
+
"accountIds": account_id,
|
|
38
|
+
"limit": 1000,
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
logger.info(f"Retrieved {len(applications)} applications from SentinelOne")
|
|
43
|
+
return applications
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@timeit
|
|
47
|
+
def get_application_installs(
|
|
48
|
+
app_inventory: list[dict[str, Any]], account_id: str, api_url: str, api_token: str
|
|
49
|
+
) -> list[dict[str, Any]]:
|
|
50
|
+
"""
|
|
51
|
+
Get application installs from SentinelOne API
|
|
52
|
+
:param app_inventory: List of applications to get installs for
|
|
53
|
+
:param account_id: SentinelOne account ID
|
|
54
|
+
:param api_url: SentinelOne API URL
|
|
55
|
+
:param api_token: SentinelOne API token
|
|
56
|
+
:return: A list of application installs data dictionaries
|
|
57
|
+
"""
|
|
58
|
+
logger.info(
|
|
59
|
+
f"Retrieving SentinelOne application installs for "
|
|
60
|
+
f"{len(app_inventory)} applications in account "
|
|
61
|
+
f"{account_id}",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
application_installs = []
|
|
65
|
+
for i, app in enumerate(app_inventory):
|
|
66
|
+
logger.info(
|
|
67
|
+
f"Retrieving SentinelOne installs for {app.get('applicationName')} "
|
|
68
|
+
f"{app.get('applicationVendor')} ({i + 1}/{len(app_inventory)})",
|
|
69
|
+
)
|
|
70
|
+
name = app["applicationName"]
|
|
71
|
+
vendor = app["applicationVendor"]
|
|
72
|
+
app_installs = get_paginated_results(
|
|
73
|
+
api_url=api_url,
|
|
74
|
+
endpoint="/web/api/v2.1/application-management/inventory/endpoints",
|
|
75
|
+
api_token=api_token,
|
|
76
|
+
params={
|
|
77
|
+
"accountIds": account_id,
|
|
78
|
+
"limit": 1000,
|
|
79
|
+
"applicationName": name,
|
|
80
|
+
"applicationVendor": vendor,
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Replace applicationVendor and applicationName with original values
|
|
85
|
+
# for consistency with the application data
|
|
86
|
+
for app_install in app_installs:
|
|
87
|
+
app_install["applicationVendor"] = vendor
|
|
88
|
+
app_install["applicationName"] = name
|
|
89
|
+
application_installs.extend(app_installs)
|
|
90
|
+
|
|
91
|
+
return application_installs
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def transform_applications(
|
|
95
|
+
applications_list: list[dict[str, Any]],
|
|
96
|
+
) -> list[dict[str, Any]]:
|
|
97
|
+
"""
|
|
98
|
+
Transform SentinelOne application data for loading into Neo4j
|
|
99
|
+
:param applications_list: Raw application data from the API
|
|
100
|
+
:return: Transformed application data
|
|
101
|
+
"""
|
|
102
|
+
transformed_data = []
|
|
103
|
+
for app in applications_list:
|
|
104
|
+
vendor = app["applicationVendor"].strip()
|
|
105
|
+
name = app["applicationName"].strip()
|
|
106
|
+
app_id = get_application_id(name, vendor)
|
|
107
|
+
transformed_app = {
|
|
108
|
+
"id": app_id,
|
|
109
|
+
"name": name,
|
|
110
|
+
"vendor": vendor,
|
|
111
|
+
}
|
|
112
|
+
transformed_data.append(transformed_app)
|
|
113
|
+
|
|
114
|
+
return transformed_data
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def transform_application_versions(
|
|
118
|
+
application_installs_list: list[dict[str, Any]],
|
|
119
|
+
) -> list[dict[str, Any]]:
|
|
120
|
+
"""
|
|
121
|
+
Transform SentinelOne application installs for loading into Neo4j
|
|
122
|
+
:param application_installs_list: Raw application installs data from the API
|
|
123
|
+
:return: Transformed application installs data
|
|
124
|
+
"""
|
|
125
|
+
transformed_data = []
|
|
126
|
+
for installed_version in application_installs_list:
|
|
127
|
+
app_name = installed_version["applicationName"]
|
|
128
|
+
app_vendor = installed_version["applicationVendor"]
|
|
129
|
+
version = installed_version["version"]
|
|
130
|
+
|
|
131
|
+
transformed_version = {
|
|
132
|
+
"id": get_application_version_id(
|
|
133
|
+
app_name,
|
|
134
|
+
app_vendor,
|
|
135
|
+
version,
|
|
136
|
+
),
|
|
137
|
+
"application_id": get_application_id(
|
|
138
|
+
app_name,
|
|
139
|
+
app_vendor,
|
|
140
|
+
),
|
|
141
|
+
"application_name": app_name,
|
|
142
|
+
"application_vendor": app_vendor,
|
|
143
|
+
"agent_uuid": installed_version.get("endpointUuid"),
|
|
144
|
+
"installation_path": installed_version.get("applicationInstallationPath"),
|
|
145
|
+
"installed_dt": installed_version.get("applicationInstallationDate"),
|
|
146
|
+
"version": version,
|
|
147
|
+
}
|
|
148
|
+
transformed_data.append(transformed_version)
|
|
149
|
+
|
|
150
|
+
return transformed_data
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@timeit
|
|
154
|
+
def load_application_data(
|
|
155
|
+
neo4j_session: neo4j.Session,
|
|
156
|
+
data: list[dict[str, Any]],
|
|
157
|
+
account_id: str,
|
|
158
|
+
update_tag: int,
|
|
159
|
+
) -> None:
|
|
160
|
+
"""
|
|
161
|
+
Load SentinelOne application data into Neo4j
|
|
162
|
+
:param neo4j_session: Neo4j session
|
|
163
|
+
:param data: The transformed application data
|
|
164
|
+
:param account_id: The SentinelOne account ID
|
|
165
|
+
:param update_tag: Update tag to set on the nodes
|
|
166
|
+
:return: None
|
|
167
|
+
"""
|
|
168
|
+
logger.info(f"Loading {len(data)} SentinelOne applications into Neo4j")
|
|
169
|
+
load(
|
|
170
|
+
neo4j_session,
|
|
171
|
+
S1ApplicationSchema(),
|
|
172
|
+
data,
|
|
173
|
+
lastupdated=update_tag,
|
|
174
|
+
S1_ACCOUNT_ID=account_id,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@timeit
|
|
179
|
+
def load_application_versions(
|
|
180
|
+
neo4j_session: neo4j.Session,
|
|
181
|
+
data: list[dict[str, Any]],
|
|
182
|
+
account_id: str,
|
|
183
|
+
update_tag: int,
|
|
184
|
+
) -> None:
|
|
185
|
+
logger.info(f"Loading {len(data)} SentinelOne application versions into Neo4j")
|
|
186
|
+
load(
|
|
187
|
+
neo4j_session,
|
|
188
|
+
S1ApplicationVersionSchema(),
|
|
189
|
+
data,
|
|
190
|
+
lastupdated=update_tag,
|
|
191
|
+
S1_ACCOUNT_ID=account_id,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@timeit
|
|
196
|
+
def cleanup(
|
|
197
|
+
neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
|
|
198
|
+
) -> None:
|
|
199
|
+
logger.debug("Running SentinelOne S1Application cleanup")
|
|
200
|
+
GraphJob.from_node_schema(S1ApplicationSchema(), common_job_parameters).run(
|
|
201
|
+
neo4j_session
|
|
202
|
+
)
|
|
203
|
+
logger.debug("Running SentinelOne S1ApplicationVersion cleanup")
|
|
204
|
+
GraphJob.from_node_schema(S1ApplicationVersionSchema(), common_job_parameters).run(
|
|
205
|
+
neo4j_session
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@timeit
|
|
210
|
+
def sync(
|
|
211
|
+
neo4j_session: neo4j.Session,
|
|
212
|
+
common_job_parameters: dict[str, Any],
|
|
213
|
+
) -> None:
|
|
214
|
+
"""
|
|
215
|
+
Sync SentinelOne applications
|
|
216
|
+
:param neo4j_session: Neo4j session
|
|
217
|
+
:param common_job_parameters: Common job parameters containing API_URL, API_TOKEN, etc.
|
|
218
|
+
:return: None
|
|
219
|
+
"""
|
|
220
|
+
logger.info("Syncing SentinelOne application data")
|
|
221
|
+
account_id = str(common_job_parameters["S1_ACCOUNT_ID"])
|
|
222
|
+
api_url = str(common_job_parameters["API_URL"])
|
|
223
|
+
api_token = str(common_job_parameters["API_TOKEN"])
|
|
224
|
+
|
|
225
|
+
applications = get_application_data(account_id, api_url, api_token)
|
|
226
|
+
application_versions = get_application_installs(
|
|
227
|
+
applications, account_id, api_url, api_token
|
|
228
|
+
)
|
|
229
|
+
transformed_applications = transform_applications(applications)
|
|
230
|
+
transformed_application_versions = transform_application_versions(
|
|
231
|
+
application_versions
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
load_application_data(
|
|
235
|
+
neo4j_session,
|
|
236
|
+
transformed_applications,
|
|
237
|
+
account_id,
|
|
238
|
+
common_job_parameters["UPDATE_TAG"],
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
load_application_versions(
|
|
242
|
+
neo4j_session,
|
|
243
|
+
transformed_application_versions,
|
|
244
|
+
account_id,
|
|
245
|
+
common_job_parameters["UPDATE_TAG"],
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
cleanup(neo4j_session, common_job_parameters)
|
|
@@ -2,8 +2,27 @@ import re
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
def get_application_id(name: str, vendor: str) -> str:
|
|
5
|
+
"""
|
|
6
|
+
Generate a normalized unique identifier for an application.
|
|
7
|
+
:param name: Application name
|
|
8
|
+
:param vendor: Application vendor/publisher
|
|
9
|
+
:return: Normalized unique identifier in format 'vendor:name'
|
|
10
|
+
"""
|
|
5
11
|
name_normalized = name.strip().lower().replace(" ", "_")
|
|
6
12
|
vendor_normalized = vendor.strip().lower().replace(" ", "_")
|
|
7
13
|
name_normalized = re.sub(r"[^\w]", "", name_normalized)
|
|
8
|
-
vendor_normalized = re.sub(r"[^\w
|
|
14
|
+
vendor_normalized = re.sub(r"[^\w]", "", vendor_normalized)
|
|
9
15
|
return f"{vendor_normalized}:{name_normalized}"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_application_version_id(name: str, vendor: str, version: str) -> str:
|
|
19
|
+
"""
|
|
20
|
+
Generate a unique identifier for an application version
|
|
21
|
+
:param name: Application name
|
|
22
|
+
:param vendor: Application vendor
|
|
23
|
+
:param version: Application version
|
|
24
|
+
:return: Unique identifier for the application version in format 'vendor:name:version'
|
|
25
|
+
"""
|
|
26
|
+
app_id = get_application_id(name, vendor)
|
|
27
|
+
version_normalized = version.strip().lower().replace(" ", "_")
|
|
28
|
+
return f"{app_id}:{version_normalized}"
|
|
@@ -0,0 +1,79 @@
|
|
|
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 CloudWatchLogMetricFilterNodeProperties(CartographyNodeProperties):
|
|
16
|
+
id: PropertyRef = PropertyRef("id")
|
|
17
|
+
arn: PropertyRef = PropertyRef("filterName", extra_index=True)
|
|
18
|
+
region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
|
|
19
|
+
filter_name: PropertyRef = PropertyRef("filterName")
|
|
20
|
+
filter_pattern: PropertyRef = PropertyRef("filterPattern")
|
|
21
|
+
log_group_name: PropertyRef = PropertyRef("logGroupName")
|
|
22
|
+
metric_name: PropertyRef = PropertyRef("metricName")
|
|
23
|
+
metric_namespace: PropertyRef = PropertyRef("metricNamespace")
|
|
24
|
+
metric_value: PropertyRef = PropertyRef("metricValue")
|
|
25
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class CloudWatchLogMetricFilterToAwsAccountRelProperties(CartographyRelProperties):
|
|
30
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class CloudWatchLogMetricFilterToAWSAccountRel(CartographyRelSchema):
|
|
35
|
+
target_node_label: str = "AWSAccount"
|
|
36
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
37
|
+
{"id": PropertyRef("AWS_ID", set_in_kwargs=True)},
|
|
38
|
+
)
|
|
39
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
40
|
+
rel_label: str = "RESOURCE"
|
|
41
|
+
properties: CloudWatchLogMetricFilterToAwsAccountRelProperties = (
|
|
42
|
+
CloudWatchLogMetricFilterToAwsAccountRelProperties()
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True)
|
|
47
|
+
class CloudWatchLogMetricFilterToCloudWatchLogGroupRelProperties(
|
|
48
|
+
CartographyRelProperties
|
|
49
|
+
):
|
|
50
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class CloudWatchLogMetricFilterToCloudWatchLogGroupRel(CartographyRelSchema):
|
|
55
|
+
target_node_label: str = "CloudWatchLogGroup"
|
|
56
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
57
|
+
{"log_group_name": PropertyRef("logGroupName")},
|
|
58
|
+
)
|
|
59
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
60
|
+
rel_label: str = "METRIC_FILTER_OF"
|
|
61
|
+
properties: CloudWatchLogMetricFilterToCloudWatchLogGroupRelProperties = (
|
|
62
|
+
CloudWatchLogMetricFilterToCloudWatchLogGroupRelProperties()
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(frozen=True)
|
|
67
|
+
class CloudWatchLogMetricFilterSchema(CartographyNodeSchema):
|
|
68
|
+
label: str = "CloudWatchLogMetricFilter"
|
|
69
|
+
properties: CloudWatchLogMetricFilterNodeProperties = (
|
|
70
|
+
CloudWatchLogMetricFilterNodeProperties()
|
|
71
|
+
)
|
|
72
|
+
sub_resource_relationship: CloudWatchLogMetricFilterToAWSAccountRel = (
|
|
73
|
+
CloudWatchLogMetricFilterToAWSAccountRel()
|
|
74
|
+
)
|
|
75
|
+
other_relationships: OtherRelationships = OtherRelationships(
|
|
76
|
+
[
|
|
77
|
+
CloudWatchLogMetricFilterToCloudWatchLogGroupRel(),
|
|
78
|
+
]
|
|
79
|
+
)
|
|
@@ -44,7 +44,9 @@ class EC2NetworkInterfaceNodeProperties(CartographyNodeProperties):
|
|
|
44
44
|
requester_id: PropertyRef = PropertyRef("RequesterId", extra_index=True)
|
|
45
45
|
requester_managed: PropertyRef = PropertyRef("RequesterManaged")
|
|
46
46
|
source_dest_check: PropertyRef = PropertyRef("SourceDestCheck")
|
|
47
|
+
# TODO: remove subnetid once we have migrated to subnet_id
|
|
47
48
|
subnetid: PropertyRef = PropertyRef("SubnetId", extra_index=True)
|
|
49
|
+
subnet_id: PropertyRef = PropertyRef("SubnetId", extra_index=True)
|
|
48
50
|
|
|
49
51
|
|
|
50
52
|
@dataclass(frozen=True)
|
|
@@ -15,7 +15,9 @@ from cartography.models.core.relationships import TargetNodeMatcher
|
|
|
15
15
|
class EC2SubnetInstanceNodeProperties(CartographyNodeProperties):
|
|
16
16
|
# arn: PropertyRef = PropertyRef('Arn', extra_index=True) TODO use arn; issue #1024
|
|
17
17
|
id: PropertyRef = PropertyRef("SubnetId")
|
|
18
|
+
# TODO: remove subnetid once we have migrated to subnet_id
|
|
18
19
|
subnetid: PropertyRef = PropertyRef("SubnetId", extra_index=True)
|
|
20
|
+
subnet_id: PropertyRef = PropertyRef("SubnetId", extra_index=True)
|
|
19
21
|
region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
|
|
20
22
|
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
21
23
|
|
|
@@ -16,6 +16,8 @@ from cartography.models.core.relationships import TargetNodeMatcher
|
|
|
16
16
|
@dataclass(frozen=True)
|
|
17
17
|
class EC2SubnetNetworkInterfaceNodeProperties(CartographyNodeProperties):
|
|
18
18
|
id: PropertyRef = PropertyRef("SubnetId")
|
|
19
|
+
# TODO: remove subnetid once we have migrated to subnet_id
|
|
20
|
+
subnetid: PropertyRef = PropertyRef("SubnetId", extra_index=True)
|
|
19
21
|
subnet_id: PropertyRef = PropertyRef("SubnetId", extra_index=True)
|
|
20
22
|
region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
|
|
21
23
|
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
@@ -46,6 +46,7 @@ class ECSTaskNodeProperties(CartographyNodeProperties):
|
|
|
46
46
|
ephemeral_storage_size_in_gib: PropertyRef = PropertyRef(
|
|
47
47
|
"ephemeralStorage.sizeInGiB"
|
|
48
48
|
)
|
|
49
|
+
network_interface_id: PropertyRef = PropertyRef("networkInterfaceId")
|
|
49
50
|
region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
|
|
50
51
|
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
51
52
|
|
|
@@ -100,11 +101,33 @@ class ECSTaskToAWSAccountRel(CartographyRelSchema):
|
|
|
100
101
|
properties: ECSTaskToAWSAccountRelProperties = ECSTaskToAWSAccountRelProperties()
|
|
101
102
|
|
|
102
103
|
|
|
104
|
+
@dataclass(frozen=True)
|
|
105
|
+
class ECSTaskToNetworkInterfaceRelProperties(CartographyRelProperties):
|
|
106
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass(frozen=True)
|
|
110
|
+
class ECSTaskToNetworkInterfaceRel(CartographyRelSchema):
|
|
111
|
+
target_node_label: str = "NetworkInterface"
|
|
112
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
113
|
+
{"id": PropertyRef("networkInterfaceId")}
|
|
114
|
+
)
|
|
115
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
116
|
+
rel_label: str = "NETWORK_INTERFACE"
|
|
117
|
+
properties: ECSTaskToNetworkInterfaceRelProperties = (
|
|
118
|
+
ECSTaskToNetworkInterfaceRelProperties()
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
103
122
|
@dataclass(frozen=True)
|
|
104
123
|
class ECSTaskSchema(CartographyNodeSchema):
|
|
105
124
|
label: str = "ECSTask"
|
|
106
125
|
properties: ECSTaskNodeProperties = ECSTaskNodeProperties()
|
|
107
126
|
sub_resource_relationship: ECSTaskToAWSAccountRel = ECSTaskToAWSAccountRel()
|
|
108
127
|
other_relationships: OtherRelationships = OtherRelationships(
|
|
109
|
-
[
|
|
128
|
+
[
|
|
129
|
+
ECSTaskToContainerInstanceRel(),
|
|
130
|
+
ECSTaskToECSClusterRel(),
|
|
131
|
+
ECSTaskToNetworkInterfaceRel(),
|
|
132
|
+
]
|
|
110
133
|
)
|
|
@@ -7,8 +7,10 @@ from cartography.models.core.nodes import ExtraNodeLabels
|
|
|
7
7
|
from cartography.models.core.relationships import CartographyRelProperties
|
|
8
8
|
from cartography.models.core.relationships import CartographyRelSchema
|
|
9
9
|
from cartography.models.core.relationships import LinkDirection
|
|
10
|
+
from cartography.models.core.relationships import make_source_node_matcher
|
|
10
11
|
from cartography.models.core.relationships import make_target_node_matcher
|
|
11
12
|
from cartography.models.core.relationships import OtherRelationships
|
|
13
|
+
from cartography.models.core.relationships import SourceNodeMatcher
|
|
12
14
|
from cartography.models.core.relationships import TargetNodeMatcher
|
|
13
15
|
|
|
14
16
|
|
|
@@ -135,6 +137,40 @@ class InspectorFindingToECRImageRel(CartographyRelSchema):
|
|
|
135
137
|
)
|
|
136
138
|
|
|
137
139
|
|
|
140
|
+
@dataclass(frozen=True)
|
|
141
|
+
class InspectorFindingToPackageRelRelProperties(CartographyRelProperties):
|
|
142
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
143
|
+
_sub_resource_label: PropertyRef = PropertyRef(
|
|
144
|
+
"_sub_resource_label", set_in_kwargs=True
|
|
145
|
+
)
|
|
146
|
+
_sub_resource_id: PropertyRef = PropertyRef("_sub_resource_id", set_in_kwargs=True)
|
|
147
|
+
# The following properties live in vulnerablePackages from AWS API
|
|
148
|
+
# Adding them here to avoid multiple repetion of packages
|
|
149
|
+
filepath: PropertyRef = PropertyRef("filePath")
|
|
150
|
+
fixedinversion: PropertyRef = PropertyRef("fixedInVersion")
|
|
151
|
+
remediation: PropertyRef = PropertyRef("remediation")
|
|
152
|
+
sourcelayerhash: PropertyRef = PropertyRef("sourceLayerHash")
|
|
153
|
+
sourcelambdalayerarn: PropertyRef = PropertyRef("sourceLambdaLayerArn")
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@dataclass(frozen=True)
|
|
157
|
+
# (:AWSInspectorFinding)-[:HAS]->(:AWSInspectorPackage)
|
|
158
|
+
class InspectorFindingToPackageMatchLink(CartographyRelSchema):
|
|
159
|
+
target_node_label: str = "AWSInspectorPackage"
|
|
160
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
161
|
+
{"id": PropertyRef("packageid")},
|
|
162
|
+
)
|
|
163
|
+
source_node_label: str = "AWSInspectorFinding"
|
|
164
|
+
source_node_matcher: SourceNodeMatcher = make_source_node_matcher(
|
|
165
|
+
{"id": PropertyRef("findingarn")},
|
|
166
|
+
)
|
|
167
|
+
properties: InspectorFindingToPackageRelRelProperties = (
|
|
168
|
+
InspectorFindingToPackageRelRelProperties()
|
|
169
|
+
)
|
|
170
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
171
|
+
rel_label: str = "HAS"
|
|
172
|
+
|
|
173
|
+
|
|
138
174
|
@dataclass(frozen=True)
|
|
139
175
|
class AWSInspectorFindingSchema(CartographyNodeSchema):
|
|
140
176
|
label: str = "AWSInspectorFinding"
|
|
@@ -146,6 +182,7 @@ class AWSInspectorFindingSchema(CartographyNodeSchema):
|
|
|
146
182
|
other_relationships: OtherRelationships = OtherRelationships(
|
|
147
183
|
[
|
|
148
184
|
InspectorFindingToEC2InstanceRel(),
|
|
185
|
+
# TODO: Fix ECRRepository and ECRImage relationships
|
|
149
186
|
InspectorFindingToECRRepositoryRel(),
|
|
150
187
|
InspectorFindingToECRImageRel(),
|
|
151
188
|
InspectorFindingToAWSAccountRelDelegateRel(),
|
|
@@ -7,25 +7,18 @@ from cartography.models.core.relationships import CartographyRelProperties
|
|
|
7
7
|
from cartography.models.core.relationships import CartographyRelSchema
|
|
8
8
|
from cartography.models.core.relationships import LinkDirection
|
|
9
9
|
from cartography.models.core.relationships import make_target_node_matcher
|
|
10
|
-
from cartography.models.core.relationships import OtherRelationships
|
|
11
10
|
from cartography.models.core.relationships import TargetNodeMatcher
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
@dataclass(frozen=True)
|
|
15
14
|
class AWSInspectorPackageNodeProperties(CartographyNodeProperties):
|
|
16
15
|
id: PropertyRef = PropertyRef("id")
|
|
17
|
-
region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
|
|
18
|
-
awsaccount: PropertyRef = PropertyRef("AWS_ID", set_in_kwargs=True)
|
|
19
|
-
findingarn: PropertyRef = PropertyRef("findingarn", extra_index=True)
|
|
20
16
|
name: PropertyRef = PropertyRef("name", extra_index=True)
|
|
21
|
-
arch: PropertyRef = PropertyRef("arch")
|
|
22
17
|
version: PropertyRef = PropertyRef("version", extra_index=True)
|
|
23
18
|
release: PropertyRef = PropertyRef("release", extra_index=True)
|
|
19
|
+
arch: PropertyRef = PropertyRef("arch")
|
|
24
20
|
epoch: PropertyRef = PropertyRef("epoch")
|
|
25
21
|
manager: PropertyRef = PropertyRef("packageManager")
|
|
26
|
-
filepath: PropertyRef = PropertyRef("filePath")
|
|
27
|
-
fixedinversion: PropertyRef = PropertyRef("fixedInVersion")
|
|
28
|
-
sourcelayerhash: PropertyRef = PropertyRef("sourceLayerHash")
|
|
29
22
|
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
30
23
|
|
|
31
24
|
|
|
@@ -47,24 +40,6 @@ class InspectorPackageToAWSAccountRel(CartographyRelSchema):
|
|
|
47
40
|
)
|
|
48
41
|
|
|
49
42
|
|
|
50
|
-
@dataclass(frozen=True)
|
|
51
|
-
class InspectorPackageToFindingRelRelProperties(CartographyRelProperties):
|
|
52
|
-
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
@dataclass(frozen=True)
|
|
56
|
-
class InspectorPackageToFindingRel(CartographyRelSchema):
|
|
57
|
-
target_node_label: str = "AWSInspectorFinding"
|
|
58
|
-
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
59
|
-
{"id": PropertyRef("findingarn")},
|
|
60
|
-
)
|
|
61
|
-
direction: LinkDirection = LinkDirection.INWARD
|
|
62
|
-
rel_label: str = "HAS"
|
|
63
|
-
properties: InspectorPackageToFindingRelRelProperties = (
|
|
64
|
-
InspectorPackageToFindingRelRelProperties()
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
|
|
68
43
|
@dataclass(frozen=True)
|
|
69
44
|
class AWSInspectorPackageSchema(CartographyNodeSchema):
|
|
70
45
|
label: str = "AWSInspectorPackage"
|
|
@@ -72,8 +47,3 @@ class AWSInspectorPackageSchema(CartographyNodeSchema):
|
|
|
72
47
|
sub_resource_relationship: InspectorPackageToAWSAccountRel = (
|
|
73
48
|
InspectorPackageToAWSAccountRel()
|
|
74
49
|
)
|
|
75
|
-
other_relationships: OtherRelationships = OtherRelationships(
|
|
76
|
-
[
|
|
77
|
-
InspectorPackageToFindingRel(),
|
|
78
|
-
],
|
|
79
|
-
)
|
|
@@ -0,0 +1,44 @@
|
|
|
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 S1ApplicationNodeProperties(CartographyNodeProperties):
|
|
15
|
+
id: PropertyRef = PropertyRef("id")
|
|
16
|
+
name: PropertyRef = PropertyRef("name")
|
|
17
|
+
vendor: PropertyRef = PropertyRef("vendor")
|
|
18
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class S1ApplicationToAccountRelProperties(CartographyRelProperties):
|
|
23
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(frozen=True)
|
|
27
|
+
# (:S1Application)<-[:RESOURCE]-(:S1Account)
|
|
28
|
+
class S1ApplicationToAccount(CartographyRelSchema):
|
|
29
|
+
target_node_label: str = "S1Account"
|
|
30
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
31
|
+
{"id": PropertyRef("S1_ACCOUNT_ID", set_in_kwargs=True)},
|
|
32
|
+
)
|
|
33
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
34
|
+
rel_label: str = "RESOURCE"
|
|
35
|
+
properties: S1ApplicationToAccountRelProperties = (
|
|
36
|
+
S1ApplicationToAccountRelProperties()
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class S1ApplicationSchema(CartographyNodeSchema):
|
|
42
|
+
label: str = "S1Application"
|
|
43
|
+
properties: S1ApplicationNodeProperties = S1ApplicationNodeProperties()
|
|
44
|
+
sub_resource_relationship: S1ApplicationToAccount = S1ApplicationToAccount()
|
|
@@ -0,0 +1,96 @@
|
|
|
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 S1ApplicationVersionNodeProperties(CartographyNodeProperties):
|
|
16
|
+
id: PropertyRef = PropertyRef("id", extra_index=True)
|
|
17
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
18
|
+
application_name: PropertyRef = PropertyRef("application_name")
|
|
19
|
+
application_vendor: PropertyRef = PropertyRef("application_vendor")
|
|
20
|
+
version: PropertyRef = PropertyRef("version")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True)
|
|
24
|
+
class S1ApplicationVersionToAccountRelProperties(CartographyRelProperties):
|
|
25
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
# (:S1ApplicationVersion)<-[:RESOURCE]-(:S1Account)
|
|
30
|
+
class S1ApplicationVersionToAccount(CartographyRelSchema):
|
|
31
|
+
target_node_label: str = "S1Account"
|
|
32
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
33
|
+
{"id": PropertyRef("S1_ACCOUNT_ID", set_in_kwargs=True)},
|
|
34
|
+
)
|
|
35
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
36
|
+
rel_label: str = "RESOURCE"
|
|
37
|
+
properties: S1ApplicationVersionToAccountRelProperties = (
|
|
38
|
+
S1ApplicationVersionToAccountRelProperties()
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(frozen=True)
|
|
43
|
+
class S1AgentToApplicationVersionRelProperties(CartographyRelProperties):
|
|
44
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
45
|
+
installeddatetime: PropertyRef = PropertyRef("installed_dt")
|
|
46
|
+
installationpath: PropertyRef = PropertyRef("installation_path")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(frozen=True)
|
|
50
|
+
# (:S1Agent)-[:HAS_INSTALLED]->(:S1ApplicationVersion)
|
|
51
|
+
class S1AgentToS1ApplicationVersion(CartographyRelSchema):
|
|
52
|
+
target_node_label: str = "S1Agent"
|
|
53
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
54
|
+
{"uuid": PropertyRef("agent_uuid")},
|
|
55
|
+
)
|
|
56
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
57
|
+
rel_label: str = "HAS_INSTALLED"
|
|
58
|
+
properties: S1AgentToApplicationVersionRelProperties = (
|
|
59
|
+
S1AgentToApplicationVersionRelProperties()
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(frozen=True)
|
|
64
|
+
class S1ApplicationVersionToApplicationRelProperties(CartographyRelProperties):
|
|
65
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(frozen=True)
|
|
69
|
+
# (:S1ApplicationVersion)<-[:VERSION]-(:S1Application)
|
|
70
|
+
class S1ApplicationVersionToApplication(CartographyRelSchema):
|
|
71
|
+
target_node_label: str = "S1Application"
|
|
72
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
73
|
+
{"id": PropertyRef("application_id")},
|
|
74
|
+
)
|
|
75
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
76
|
+
rel_label: str = "VERSION"
|
|
77
|
+
properties: S1ApplicationVersionToApplicationRelProperties = (
|
|
78
|
+
S1ApplicationVersionToApplicationRelProperties()
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass(frozen=True)
|
|
83
|
+
class S1ApplicationVersionSchema(CartographyNodeSchema):
|
|
84
|
+
label: str = "S1ApplicationVersion"
|
|
85
|
+
properties: S1ApplicationVersionNodeProperties = (
|
|
86
|
+
S1ApplicationVersionNodeProperties()
|
|
87
|
+
)
|
|
88
|
+
sub_resource_relationship: S1ApplicationVersionToAccount = (
|
|
89
|
+
S1ApplicationVersionToAccount()
|
|
90
|
+
)
|
|
91
|
+
other_relationships: OtherRelationships = OtherRelationships(
|
|
92
|
+
[
|
|
93
|
+
S1AgentToS1ApplicationVersion(),
|
|
94
|
+
S1ApplicationVersionToApplication(),
|
|
95
|
+
],
|
|
96
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
cartography/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
cartography/__main__.py,sha256=y5iqUrj4BmqZfjeDT-9balzpXeMARgHeIedRMRI1gr8,100
|
|
3
|
-
cartography/_version.py,sha256=
|
|
3
|
+
cartography/_version.py,sha256=Mw8xqndv8cO5u8s9TF2NfNZPshP9CgkSEhbYGTmeNck,525
|
|
4
4
|
cartography/cli.py,sha256=e5F9239v_JoLR293JMZI1toYg43li2RX_F-qOHTB-HA,46054
|
|
5
5
|
cartography/config.py,sha256=mM7Frg8maGB4a0Oad2nvktM38uC7zgrwSmofO5l4Aus,16492
|
|
6
6
|
cartography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -158,12 +158,12 @@ cartography/intel/aws/acm.py,sha256=a_i2pYPpocjlL8itwlcrmg8KrSLfjcmrkhcrPP-Omj8,
|
|
|
158
158
|
cartography/intel/aws/apigateway.py,sha256=hOYVSY70DbrEfhi9gkX7PAMtg9WiPE0Pbp2wqGes7Vs,12198
|
|
159
159
|
cartography/intel/aws/cloudtrail.py,sha256=kip3O39ulRmuo9RpfkofzUcGnkNnF8ksD7hP0Qe75-A,2441
|
|
160
160
|
cartography/intel/aws/cloudtrail_management_events.py,sha256=_kJR3N4eHm1c1OgObsUgAdB11UQjN91B9B0U3kuk0_o,13036
|
|
161
|
-
cartography/intel/aws/cloudwatch.py,sha256=
|
|
161
|
+
cartography/intel/aws/cloudwatch.py,sha256=Irocf84_n-JqFIbTf9tPkpJe5cpKSubd5daE7G8298Q,5107
|
|
162
162
|
cartography/intel/aws/codebuild.py,sha256=8I-Xzm_c5-ixnGOOHIQLYYpClnaGjjHrEMjQ0-DGsgM,3958
|
|
163
163
|
cartography/intel/aws/config.py,sha256=IIICicLQ0OTT3H3o8LDakIkA1BPUMwSyzpKonet-PaY,7658
|
|
164
164
|
cartography/intel/aws/dynamodb.py,sha256=VvvjeUgi1ZrqY9flXIQnfhhaSVSEqXXHW6T9917VLBk,5728
|
|
165
165
|
cartography/intel/aws/ecr.py,sha256=7a9EHZru6AUIGE_6MJ4h4_ZmrvBxsXaerCHtGr59lJ0,8393
|
|
166
|
-
cartography/intel/aws/ecs.py,sha256
|
|
166
|
+
cartography/intel/aws/ecs.py,sha256=h5Nn09MzqPftbXV46jybjsxnYVYW1Vit41kCkaFIq_4,14105
|
|
167
167
|
cartography/intel/aws/efs.py,sha256=6ZvFmVHLfZlyo8xx2dlRsC1IoVOpBOtsij_AdFczkDo,7884
|
|
168
168
|
cartography/intel/aws/eks.py,sha256=bPItyEj5q0nSDltJrr0S5MIrTPV0fK3xkqF6EV8fcqA,3759
|
|
169
169
|
cartography/intel/aws/elasticache.py,sha256=dpRJCYxgUW2ImgGMt4L54xFil8apUoJxZq6hpewXxAE,4590
|
|
@@ -172,7 +172,7 @@ cartography/intel/aws/emr.py,sha256=EJoKjHQP7-F_A1trUNU05Sb42yNR1i0C9VIpGcCfAXw,
|
|
|
172
172
|
cartography/intel/aws/iam.py,sha256=bkyIzWw2OC4MHxuoCvTiZ5eEGEQhz2asiUgY_tkX2GY,34322
|
|
173
173
|
cartography/intel/aws/iam_instance_profiles.py,sha256=QUyu30xid60BFaemp-q0y9FgNsHaIQyQnQ8gHUzWC4k,2211
|
|
174
174
|
cartography/intel/aws/identitycenter.py,sha256=C2EOfwQO1zBjePAXtreUcJIy7RU__ior3liRT4SpGO8,9544
|
|
175
|
-
cartography/intel/aws/inspector.py,sha256=
|
|
175
|
+
cartography/intel/aws/inspector.py,sha256=G8a60uuFCuENvR2DNJ9VmWEJwG9UDENaC1buULvuSZc,12415
|
|
176
176
|
cartography/intel/aws/kms.py,sha256=RtCxNG-Den-f4Il-NO3YL_-BFUmg1qFt4lNucue9SQM,12130
|
|
177
177
|
cartography/intel/aws/lambda_function.py,sha256=cutCsMnvyJB8vKUP0fHORrhijw944cXSoLKOHYdi6SM,10389
|
|
178
178
|
cartography/intel/aws/organizations.py,sha256=m5qk60N6pe7iKLN-Rtfg9aYv7OozoloSkcsuePd-RGs,4680
|
|
@@ -205,7 +205,7 @@ cartography/intel/aws/ec2/reserved_instances.py,sha256=BsshVUzkuOstbidYEGq0By2Y-
|
|
|
205
205
|
cartography/intel/aws/ec2/route_tables.py,sha256=NSW7B-4wII4mf5ClX5F1q4cKfSNAjxBSnrdk4EhxXz0,10465
|
|
206
206
|
cartography/intel/aws/ec2/security_groups.py,sha256=JT3UFD-LgcdH85bel0GomHDEkCntPjvH0IXl9-ELMqI,6447
|
|
207
207
|
cartography/intel/aws/ec2/snapshots.py,sha256=BiTvxR8ibt7wdBTNNpz75zRqc1Iiy6ksmowBSyBUhEU,5685
|
|
208
|
-
cartography/intel/aws/ec2/subnets.py,sha256=
|
|
208
|
+
cartography/intel/aws/ec2/subnets.py,sha256=LDuWdkQH-2O8TmqYlvyIn3STUgP6vlhKjG8o8XNMuGE,4142
|
|
209
209
|
cartography/intel/aws/ec2/tgw.py,sha256=FcXWgLkr4EcD9DRXJMeyWQIgIHidaq40UrZneKhvnuE,9621
|
|
210
210
|
cartography/intel/aws/ec2/util.py,sha256=t6oJX9nCTejvp0D9ihxfhmCoD1aoOXQB0cuvz0pMCe0,226
|
|
211
211
|
cartography/intel/aws/ec2/volumes.py,sha256=C5V9LRE41REU4siHMAaE9yAjtbpLi8yTkaqLEw1uXMg,3726
|
|
@@ -329,11 +329,12 @@ cartography/intel/semgrep/__init__.py,sha256=zNAH5iDbLeLeQex2L5RZytGVFY4OHYvfGuE
|
|
|
329
329
|
cartography/intel/semgrep/dependencies.py,sha256=C_gAVOx8wN70sqvFUQD9fZ3ijv_D4W_-EiLrZ4qsvHY,8429
|
|
330
330
|
cartography/intel/semgrep/deployment.py,sha256=RdLuTxSyKiIaAuposppp7Vjjq4w9M9QFSXmHgGmSWkY,2020
|
|
331
331
|
cartography/intel/semgrep/findings.py,sha256=EtNwK__L1Af45xilyQPnMzu40mjWVfiCaw4WL-MWH7c,10036
|
|
332
|
-
cartography/intel/sentinelone/__init__.py,sha256=
|
|
332
|
+
cartography/intel/sentinelone/__init__.py,sha256=P6XGOQNNyjXp465rNOAXBbWMfEElPym-vLnayup8jM8,2174
|
|
333
333
|
cartography/intel/sentinelone/account.py,sha256=FHWAl6iqpVUKTSNr0u6iAoZ7HgZezvY5JaNzYLs6GdY,4404
|
|
334
334
|
cartography/intel/sentinelone/agent.py,sha256=7ZAG1D6X-7LkhZ2Yjatm84VvFybfNEmILqky0XsYGwQ,4386
|
|
335
335
|
cartography/intel/sentinelone/api.py,sha256=2SUD5ukrUt8-JcMkJ6e0_ZUwh68DwBDssbUZMYInDR0,3042
|
|
336
|
-
cartography/intel/sentinelone/
|
|
336
|
+
cartography/intel/sentinelone/application.py,sha256=11V57OtQqcW6_K6NxIjQQVKfU-91qbQhDxxBu30RBAI,7951
|
|
337
|
+
cartography/intel/sentinelone/utils.py,sha256=asKaF2aHNcoutu89z_aXqG7lOmZ55TJJTNd90FJtBW8,1112
|
|
337
338
|
cartography/intel/snipeit/__init__.py,sha256=XIBEduCoQirs1NuOJ02XKvcBAc0pyeFMJNJsn4iJfXc,1102
|
|
338
339
|
cartography/intel/snipeit/asset.py,sha256=kQQQwYPM6Pm7bJRSMguKmFLg0s6AD6RG1nU5LLLbhVk,2043
|
|
339
340
|
cartography/intel/snipeit/user.py,sha256=qO-uwbwyM_Ft95-q-yWUxOL9UdtGpxSn4XM5T-evdNs,1987
|
|
@@ -374,6 +375,7 @@ cartography/models/aws/cloudtrail/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
|
|
|
374
375
|
cartography/models/aws/cloudtrail/management_events.py,sha256=RKAHm6RGVJBaOS90Csa7Vg1LEgq4lXY9YnRIMD2iLwM,2816
|
|
375
376
|
cartography/models/aws/cloudtrail/trail.py,sha256=qQnpqFypKef8E7-JOR83euAtI6_j2KdjzGGFiQa6xkA,3676
|
|
376
377
|
cartography/models/aws/cloudwatch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
378
|
+
cartography/models/aws/cloudwatch/log_metric_filter.py,sha256=hROU3pp_D_q21dAPTddm4lcAcCZaDV_UJ49QAZ6SCLc,3321
|
|
377
379
|
cartography/models/aws/cloudwatch/loggroup.py,sha256=_MRpRvU_Vg2rVlUdzfae6vOpbpmYaYE1EVN5zWucFbE,2456
|
|
378
380
|
cartography/models/aws/codebuild/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
379
381
|
cartography/models/aws/codebuild/project.py,sha256=r_DMCtHlbG9FGUk_I8j_E1inIbFcGAXtL6HxHrcgg0U,2122
|
|
@@ -395,7 +397,7 @@ cartography/models/aws/ec2/loadbalancerv2.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
|
|
|
395
397
|
cartography/models/aws/ec2/network_acl_rules.py,sha256=G2YJNOY67XQWfQbHQXkuquabiLQJp4smleLn_pdFrGY,4034
|
|
396
398
|
cartography/models/aws/ec2/network_acls.py,sha256=HFInVqHmINe2kWnsbJe8rGng-UHsZDkhRXRnd1nI0v4,3532
|
|
397
399
|
cartography/models/aws/ec2/networkinterface_instance.py,sha256=Gq2vGL7waocwsYRxMwOCV2vqBpUhtJDFilnylkMiKn4,4849
|
|
398
|
-
cartography/models/aws/ec2/networkinterfaces.py,sha256=
|
|
400
|
+
cartography/models/aws/ec2/networkinterfaces.py,sha256=Q1AodKLX7IJWp1Z6tP2uCl21uSjdtZiX8SZImBCIbWo,4404
|
|
399
401
|
cartography/models/aws/ec2/privateip_networkinterface.py,sha256=8Dt2r0sELvTAYYsUX13X-SKLJ6LDpTGmoAyLdNVYcBY,3128
|
|
400
402
|
cartography/models/aws/ec2/reservations.py,sha256=Lep6M-srupbAZZzCFmOpiwz22AafJLwKzSAuuxe3BlA,1980
|
|
401
403
|
cartography/models/aws/ec2/route_table_associations.py,sha256=Rs9uG976zZazcUIGL5oGpLkB72gLxWHFNCUqrvjMTvg,3974
|
|
@@ -403,8 +405,8 @@ cartography/models/aws/ec2/route_tables.py,sha256=R0gcwaOsLXRjpuvL9Pq-uGosetZysH
|
|
|
403
405
|
cartography/models/aws/ec2/routes.py,sha256=T_PR1-pf_ZiE_w3zNaHaksXI5sIsaDwmH3sRctlP4uc,3725
|
|
404
406
|
cartography/models/aws/ec2/securitygroup_instance.py,sha256=j-g1CQHYFTb0D0YsLP5QLy-lBJ0IUc3xTtaX8r9nzIY,2974
|
|
405
407
|
cartography/models/aws/ec2/securitygroup_networkinterface.py,sha256=2MBxYXxuq_L0COeC04SgFfwxeXw-pc4N4JAH9oZyWQE,2481
|
|
406
|
-
cartography/models/aws/ec2/subnet_instance.py,sha256=
|
|
407
|
-
cartography/models/aws/ec2/subnet_networkinterface.py,sha256=
|
|
408
|
+
cartography/models/aws/ec2/subnet_instance.py,sha256=6bgrWbFcCjBIjqd_6lcKv6rWyll-Zx1aA5TK68DcIhg,2952
|
|
409
|
+
cartography/models/aws/ec2/subnet_networkinterface.py,sha256=B60S1YvEopVWNlRL5W-hMby3-P06uaNcC_8oOLoRGik,3872
|
|
408
410
|
cartography/models/aws/ec2/volumes.py,sha256=ITSJ_1HgrU5wTF1zZV8sYRZsI0QzktoHkvTgpnfM1hI,4547
|
|
409
411
|
cartography/models/aws/ecs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
410
412
|
cartography/models/aws/ecs/clusters.py,sha256=uu-UzkSbpLu4UG5I6NsFMaThrPYl6jYe71EX8baMy1Q,2845
|
|
@@ -413,7 +415,7 @@ cartography/models/aws/ecs/container_instances.py,sha256=LhBkyEWfOSejD57AERoQYVE
|
|
|
413
415
|
cartography/models/aws/ecs/containers.py,sha256=jmMdaonho4VI-TdZqBgTc1Ck-6XqI4O0hKRh1Ioerc4,3955
|
|
414
416
|
cartography/models/aws/ecs/services.py,sha256=YPVTS0BB3X6tFCqIX3V1AZXcnHQEADusQkErd88oH7o,4964
|
|
415
417
|
cartography/models/aws/ecs/task_definitions.py,sha256=Wee44GZazQfZQ1TRRZr8bYXwSGgNNDuYxHRBhOmvWzg,5573
|
|
416
|
-
cartography/models/aws/ecs/tasks.py,sha256=
|
|
418
|
+
cartography/models/aws/ecs/tasks.py,sha256=E_wx1lwV0b9MMgFW-nBZFfq_AhFTV38-NC1LKGxs3lE,5809
|
|
417
419
|
cartography/models/aws/efs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
418
420
|
cartography/models/aws/efs/access_point.py,sha256=Auk8E0AoPjrCxch8bP8fhT3JZ2WxblTTfYSqamA_p8g,3185
|
|
419
421
|
cartography/models/aws/efs/file_system.py,sha256=6BNzjQJKZ-rYlDLw1UvDBhVRKre07-9EkcW9xvR3Wh0,2842
|
|
@@ -427,8 +429,8 @@ cartography/models/aws/identitycenter/awsidentitycenter.py,sha256=-ybcEgdZjwF0RI
|
|
|
427
429
|
cartography/models/aws/identitycenter/awspermissionset.py,sha256=12kDKzsJQOHg6d9dlX98sM9gKXGMQh7FaxzlJov7Dgo,3651
|
|
428
430
|
cartography/models/aws/identitycenter/awsssouser.py,sha256=EWnyX5ev2aaK64YjKGuJSoknBF5b_kS5xc0kDf_0xfo,2886
|
|
429
431
|
cartography/models/aws/inspector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
430
|
-
cartography/models/aws/inspector/findings.py,sha256=
|
|
431
|
-
cartography/models/aws/inspector/packages.py,sha256=
|
|
432
|
+
cartography/models/aws/inspector/findings.py,sha256=ikm0vvjhGK_-BDt5VGyS4_0KwJsq81T6VgROq9HK2NE,8188
|
|
433
|
+
cartography/models/aws/inspector/packages.py,sha256=IoJT7w6n8Vx3vGGJPWKDgJLRpioqtOS5iMYZLnX7thg,2113
|
|
432
434
|
cartography/models/aws/s3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
433
435
|
cartography/models/aws/s3/account_public_access_block.py,sha256=L6AS0OncfSOWHP4pOXshnJFDPwnWqywzUIeUppJcw-Q,2256
|
|
434
436
|
cartography/models/aws/s3/notification.py,sha256=SF1VvCP_2WVh8K29d4ms8MUcg9AyO_MN8vCgzLFlGAs,1017
|
|
@@ -527,6 +529,8 @@ cartography/models/semgrep/locations.py,sha256=uC0QCsqSWV0ZCvQuR3OPpecImbumNLpRq
|
|
|
527
529
|
cartography/models/sentinelone/__init__.py,sha256=DNFTywfYLRp-cX6S6zbVRkFmjud5MVtMM4Fro8PTU4Q,26
|
|
528
530
|
cartography/models/sentinelone/account.py,sha256=bUh07nyPXEMXVx8kCqT0-gX9tBH8-GufcQvC2TlHnP0,1370
|
|
529
531
|
cartography/models/sentinelone/agent.py,sha256=3FTJQQ_QRq9GGeIjuV0_8ZeJcnKWGHHC3exddZldqCY,2287
|
|
532
|
+
cartography/models/sentinelone/application.py,sha256=g77cmjuTmiX_AwgZ7-x5eP-DsKXoCjzeAQuYtuCAcyo,1811
|
|
533
|
+
cartography/models/sentinelone/application_version.py,sha256=ICxaz1rndwBpaJUgbdTshhn-cbcU_KbV7VeKyUqsdoQ,3829
|
|
530
534
|
cartography/models/snipeit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
531
535
|
cartography/models/snipeit/asset.py,sha256=64Cq6ff0jemj_fvhQ_-B1xEHqsZ95RqtcbDSTzCI_00,3312
|
|
532
536
|
cartography/models/snipeit/tenant.py,sha256=E6uaY3d2W3MmfuUqF2TLpRP3T1QZkoIXRtp9BGxxSxk,695
|
|
@@ -542,9 +546,9 @@ cartography/models/trivy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
542
546
|
cartography/models/trivy/findings.py,sha256=SgI_h1aRyR20uAHvuXIZ1T6r4IZJt6SVhxRaF2bTsm0,3085
|
|
543
547
|
cartography/models/trivy/fix.py,sha256=ho9ENVl9HSXqyggyCwR6ilkOBKDxpQ7rGibo_j21NA4,2587
|
|
544
548
|
cartography/models/trivy/package.py,sha256=IwO1RZZ-MFRtNbt8Cq6YFl6fdNJMFmULnJkkK8Q4rL4,2809
|
|
545
|
-
cartography-0.107.
|
|
546
|
-
cartography-0.107.
|
|
547
|
-
cartography-0.107.
|
|
548
|
-
cartography-0.107.
|
|
549
|
-
cartography-0.107.
|
|
550
|
-
cartography-0.107.
|
|
549
|
+
cartography-0.107.0rc3.dist-info/licenses/LICENSE,sha256=kvLEBRYaQ1RvUni6y7Ti9uHeooqnjPoo6n_-0JO1ETc,11351
|
|
550
|
+
cartography-0.107.0rc3.dist-info/METADATA,sha256=JGMCRDlbdo4dqinKGOf1MUnv_1tQ-i4v38lYyJ1_jfg,12861
|
|
551
|
+
cartography-0.107.0rc3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
552
|
+
cartography-0.107.0rc3.dist-info/entry_points.txt,sha256=GVIAWD0o0_K077qMA_k1oZU4v-M0a8GLKGJR8tZ-qH8,112
|
|
553
|
+
cartography-0.107.0rc3.dist-info/top_level.txt,sha256=BHqsNJQiI6Q72DeypC1IINQJE59SLhU4nllbQjgJi9g,12
|
|
554
|
+
cartography-0.107.0rc3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|