cartography 0.117.0__py3-none-any.whl → 0.118.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.

Files changed (57) hide show
  1. cartography/_version.py +2 -2
  2. cartography/cli.py +11 -0
  3. cartography/config.py +5 -0
  4. cartography/graph/job.py +6 -2
  5. cartography/graph/statement.py +4 -0
  6. cartography/intel/aws/__init__.py +1 -0
  7. cartography/intel/aws/apigateway.py +18 -5
  8. cartography/intel/aws/ec2/elastic_ip_addresses.py +3 -1
  9. cartography/intel/aws/ec2/internet_gateways.py +4 -2
  10. cartography/intel/aws/ec2/load_balancer_v2s.py +11 -5
  11. cartography/intel/aws/ec2/network_interfaces.py +4 -0
  12. cartography/intel/aws/ec2/reserved_instances.py +3 -1
  13. cartography/intel/aws/ec2/tgw.py +11 -5
  14. cartography/intel/aws/ec2/volumes.py +1 -1
  15. cartography/intel/aws/ecr.py +202 -26
  16. cartography/intel/aws/elasticsearch.py +13 -4
  17. cartography/intel/aws/identitycenter.py +93 -54
  18. cartography/intel/aws/inspector.py +26 -14
  19. cartography/intel/aws/permission_relationships.py +3 -3
  20. cartography/intel/aws/s3.py +26 -13
  21. cartography/intel/aws/ssm.py +3 -5
  22. cartography/intel/azure/compute.py +9 -4
  23. cartography/intel/azure/cosmosdb.py +31 -15
  24. cartography/intel/azure/sql.py +25 -12
  25. cartography/intel/azure/storage.py +19 -9
  26. cartography/intel/azure/subscription.py +3 -1
  27. cartography/intel/crowdstrike/spotlight.py +5 -2
  28. cartography/intel/entra/app_role_assignments.py +9 -2
  29. cartography/intel/gcp/__init__.py +26 -9
  30. cartography/intel/gcp/clients.py +8 -4
  31. cartography/intel/gcp/compute.py +39 -18
  32. cartography/intel/gcp/crm/folders.py +9 -3
  33. cartography/intel/gcp/crm/orgs.py +8 -3
  34. cartography/intel/gcp/crm/projects.py +14 -3
  35. cartography/intel/jamf/computers.py +7 -1
  36. cartography/intel/oci/iam.py +23 -9
  37. cartography/intel/oci/organizations.py +3 -1
  38. cartography/intel/oci/utils.py +28 -5
  39. cartography/intel/okta/awssaml.py +8 -7
  40. cartography/intel/pagerduty/escalation_policies.py +13 -6
  41. cartography/intel/pagerduty/schedules.py +9 -4
  42. cartography/intel/pagerduty/services.py +7 -3
  43. cartography/intel/pagerduty/teams.py +5 -2
  44. cartography/intel/pagerduty/users.py +3 -1
  45. cartography/intel/pagerduty/vendors.py +3 -1
  46. cartography/intel/trivy/__init__.py +109 -58
  47. cartography/models/aws/ec2/networkinterfaces.py +2 -0
  48. cartography/models/aws/ecr/image.py +8 -0
  49. cartography/models/aws/ecr/repository_image.py +1 -1
  50. cartography/sync.py +1 -1
  51. cartography/util.py +5 -1
  52. {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/METADATA +3 -3
  53. {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/RECORD +57 -57
  54. {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/WHEEL +0 -0
  55. {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/entry_points.txt +0 -0
  56. {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/licenses/LICENSE +0 -0
  57. {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,7 @@ import botocore.config
8
8
  import neo4j
9
9
  from policyuniverse.policy import Policy
10
10
 
11
+ from cartography.client.core.tx import run_write_query
11
12
  from cartography.intel.dns import ingest_dns_record_by_fqdn
12
13
  from cartography.util import aws_handle_regions
13
14
  from cartography.util import run_cleanup_job
@@ -95,7 +96,8 @@ def _load_es_domains(
95
96
  for d in domain_list:
96
97
  del d["ServiceSoftwareOptions"]
97
98
 
98
- neo4j_session.run(
99
+ run_write_query(
100
+ neo4j_session,
99
101
  ingest_records,
100
102
  Records=domain_list,
101
103
  AWS_ACCOUNT_ID=aws_account_id,
@@ -179,7 +181,8 @@ def _link_es_domain_vpc(
179
181
  groupList = vpc_data.get("SecurityGroupIds", [])
180
182
 
181
183
  if len(subnetList) > 0:
182
- neo4j_session.run(
184
+ run_write_query(
185
+ neo4j_session,
183
186
  ingest_subnet,
184
187
  DomainId=domain_id,
185
188
  SubnetList=subnetList,
@@ -187,7 +190,8 @@ def _link_es_domain_vpc(
187
190
  )
188
191
 
189
192
  if len(groupList) > 0:
190
- neo4j_session.run(
193
+ run_write_query(
194
+ neo4j_session,
191
195
  ingest_sec_groups,
192
196
  DomainId=domain_id,
193
197
  SecGroupList=groupList,
@@ -220,7 +224,12 @@ def _process_access_policy(
220
224
  if policy.is_internet_accessible():
221
225
  exposed_internet = True
222
226
 
223
- neo4j_session.run(tag_es, DomainId=domain_id, InternetExposed=exposed_internet)
227
+ run_write_query(
228
+ neo4j_session,
229
+ tag_es,
230
+ DomainId=domain_id,
231
+ InternetExposed=exposed_internet,
232
+ )
224
233
 
225
234
 
226
235
  @timeit
@@ -6,10 +6,12 @@ from typing import Optional
6
6
  from typing import Union
7
7
 
8
8
  import boto3
9
+ import botocore.exceptions
9
10
  import neo4j
10
11
 
11
12
  from cartography.client.core.tx import load
12
13
  from cartography.client.core.tx import load_matchlinks
14
+ from cartography.client.core.tx import read_list_of_dicts_tx
13
15
  from cartography.graph.job import GraphJob
14
16
  from cartography.models.aws.identitycenter.awsidentitycenter import (
15
17
  AWSIdentityCenterInstanceSchema,
@@ -31,6 +33,18 @@ from cartography.util import timeit
31
33
  logger = logging.getLogger(__name__)
32
34
 
33
35
 
36
+ def _is_permission_set_sync_unsupported_error(
37
+ error: botocore.exceptions.ClientError,
38
+ ) -> bool:
39
+ """Return True when the Identity Center instance does not support permission sets."""
40
+ error_info = error.response.get("Error", {})
41
+ if error_info.get("Code") != "ValidationException":
42
+ return False
43
+
44
+ message = error_info.get("Message", "").lower()
45
+ return "not supported for this identity center instance" in message
46
+
47
+
34
48
  @timeit
35
49
  @aws_handle_regions
36
50
  def get_identity_center_instances(
@@ -394,8 +408,11 @@ def get_permset_roles(
394
408
  WHERE permset.arn IN $PermSetIds
395
409
  RETURN permset.arn AS PermissionSetArn, role.arn AS RoleArn
396
410
  """
397
- result = neo4j_session.run(query, PermSetIds=permset_ids)
398
- permset_to_role = [record.data() for record in result]
411
+ permset_to_role = neo4j_session.execute_read(
412
+ read_list_of_dicts_tx,
413
+ query,
414
+ PermSetIds=permset_ids,
415
+ )
399
416
 
400
417
  # Create mapping from permission set ARN to role ARN
401
418
  permset_to_role_map = {
@@ -504,32 +521,51 @@ def sync_identity_center_instances(
504
521
  instance_arn = instance["InstanceArn"]
505
522
  identity_store_id = instance["IdentityStoreId"]
506
523
 
507
- permission_sets = get_permission_sets(boto3_session, instance_arn, region)
508
-
509
- load_permission_sets(
510
- neo4j_session,
511
- permission_sets,
512
- instance_arn,
513
- region,
514
- current_aws_account_id,
515
- update_tag,
516
- )
524
+ permission_set_sync_supported = True
525
+ try:
526
+ permission_sets = get_permission_sets(
527
+ boto3_session, instance_arn, region
528
+ )
529
+ except botocore.exceptions.ClientError as error:
530
+ if _is_permission_set_sync_unsupported_error(error):
531
+ permission_set_sync_supported = False
532
+ permission_sets = []
533
+ logger.warning(
534
+ "Skipping permission set sync for Identity Center instance %s in region %s "
535
+ "because the instance does not support permission sets.",
536
+ instance_arn,
537
+ region,
538
+ )
539
+ else:
540
+ raise
541
+
542
+ if permission_set_sync_supported:
543
+ load_permission_sets(
544
+ neo4j_session,
545
+ permission_sets,
546
+ instance_arn,
547
+ region,
548
+ current_aws_account_id,
549
+ update_tag,
550
+ )
517
551
 
518
552
  # Fetch groups first to avoid interleaving between groups and users
519
553
  groups = get_sso_groups(boto3_session, identity_store_id, region)
520
554
 
521
555
  # Get permission set assignments for groups
522
556
  group_permission_sets: Dict[str, List[str]] = {}
523
- group_role_assignments_raw = get_group_role_assignments(
524
- boto3_session,
525
- groups,
526
- instance_arn,
527
- region,
528
- )
529
- for assignment in group_role_assignments_raw:
530
- group_id = assignment["GroupId"]
531
- perm_set = assignment["PermissionSetArn"]
532
- group_permission_sets.setdefault(group_id, []).append(perm_set)
557
+ group_role_assignments_raw: List[Dict[str, Any]] = []
558
+ if permission_set_sync_supported:
559
+ group_role_assignments_raw = get_group_role_assignments(
560
+ boto3_session,
561
+ groups,
562
+ instance_arn,
563
+ region,
564
+ )
565
+ for assignment in group_role_assignments_raw:
566
+ group_id = assignment["GroupId"]
567
+ perm_set = assignment["PermissionSetArn"]
568
+ group_permission_sets.setdefault(group_id, []).append(perm_set)
533
569
 
534
570
  # Transform and load groups with their permission set assignments FIRST
535
571
  # so that user->group membership edges can attach in the same run.
@@ -554,16 +590,18 @@ def sync_identity_center_instances(
554
590
 
555
591
  # Get direct permission set assignments for users
556
592
  user_permission_sets: Dict[str, List[str]] = {}
557
- user_role_assignments_raw = get_role_assignments(
558
- boto3_session,
559
- users,
560
- instance_arn,
561
- region,
562
- )
563
- for assignment in user_role_assignments_raw:
564
- uid = assignment["UserId"]
565
- perm_set = assignment["PermissionSetArn"]
566
- user_permission_sets.setdefault(uid, []).append(perm_set)
593
+ user_role_assignments_raw: List[Dict[str, Any]] = []
594
+ if permission_set_sync_supported:
595
+ user_role_assignments_raw = get_role_assignments(
596
+ boto3_session,
597
+ users,
598
+ instance_arn,
599
+ region,
600
+ )
601
+ for assignment in user_role_assignments_raw:
602
+ uid = assignment["UserId"]
603
+ perm_set = assignment["PermissionSetArn"]
604
+ user_permission_sets.setdefault(uid, []).append(perm_set)
567
605
 
568
606
  # Transform and load users with their group memberships AFTER groups exist
569
607
  transformed_users = transform_sso_users(
@@ -584,28 +622,29 @@ def sync_identity_center_instances(
584
622
  # Note: we do this after groups and users are loaded so that
585
623
  # load_role_assignments calls can MATCH existing AWSSSOUser/AWSSSOGroup
586
624
  # nodes when drawing the ALLOWED_BY edges.
587
- enriched_role_assignments = get_permset_roles(
588
- neo4j_session,
589
- user_role_assignments_raw,
590
- )
591
- load_role_assignments(
592
- neo4j_session,
593
- enriched_role_assignments,
594
- current_aws_account_id,
595
- update_tag,
596
- RoleAssignmentAllowedByMatchLink(),
597
- )
625
+ if permission_set_sync_supported:
626
+ enriched_role_assignments = get_permset_roles(
627
+ neo4j_session,
628
+ user_role_assignments_raw,
629
+ )
630
+ load_role_assignments(
631
+ neo4j_session,
632
+ enriched_role_assignments,
633
+ current_aws_account_id,
634
+ update_tag,
635
+ RoleAssignmentAllowedByMatchLink(),
636
+ )
598
637
 
599
- enriched_group_role_assignments = get_permset_roles(
600
- neo4j_session,
601
- group_role_assignments_raw,
602
- )
603
- load_role_assignments(
604
- neo4j_session,
605
- enriched_group_role_assignments,
606
- current_aws_account_id,
607
- update_tag,
608
- RoleAssignmentAllowedByGroupMatchLink(),
609
- )
638
+ enriched_group_role_assignments = get_permset_roles(
639
+ neo4j_session,
640
+ group_role_assignments_raw,
641
+ )
642
+ load_role_assignments(
643
+ neo4j_session,
644
+ enriched_group_role_assignments,
645
+ current_aws_account_id,
646
+ update_tag,
647
+ RoleAssignmentAllowedByGroupMatchLink(),
648
+ )
610
649
 
611
650
  cleanup(neo4j_session, common_job_parameters)
@@ -75,16 +75,17 @@ def get_inspector_findings(
75
75
  session: boto3.session.Session,
76
76
  region: str,
77
77
  account_id: str,
78
+ batch_size: int,
78
79
  ) -> Iterator[List[Dict[str, Any]]]:
79
80
  """
80
81
  Query inspector2.list_findings by filtering the request, otherwise the request could timeout.
81
82
  First, we filter by account_id. And since there may be millions of CLOSED findings that may never go away,
82
83
  only fetch those in ACTIVE or SUPPRESSED statuses.
83
- Run the query in batches of 1000 findings and return an iterator to fetch the results.
84
+ Run the query in batches and return an iterator to fetch the results.
84
85
  """
85
86
  client = session.client("inspector2", region_name=region)
86
87
  logger.info(
87
- f"Getting findings in batches of {BATCH_SIZE} for account {account_id} in region {region}"
88
+ f"Getting findings in batches of {batch_size} for account {account_id} in region {region}"
88
89
  )
89
90
  aws_args: Dict[str, Any] = {
90
91
  "filterCriteria": {
@@ -103,7 +104,7 @@ def get_inspector_findings(
103
104
  }
104
105
  }
105
106
  findings_batches = batch(
106
- aws_paginate(client, "list_findings", "findings", None, **aws_args), BATCH_SIZE
107
+ aws_paginate(client, "list_findings", "findings", None, **aws_args), batch_size
107
108
  )
108
109
  yield from findings_batches
109
110
 
@@ -271,19 +272,25 @@ def load_inspector_finding_to_package_match_links(
271
272
  def cleanup(
272
273
  neo4j_session: neo4j.Session,
273
274
  common_job_parameters: Dict[str, Any],
275
+ batch_size: int = BATCH_SIZE,
274
276
  ) -> None:
275
277
  logger.info("Running AWS Inspector cleanup")
276
- GraphJob.from_node_schema(AWSInspectorFindingSchema(), common_job_parameters).run(
277
- neo4j_session,
278
- )
279
- GraphJob.from_node_schema(AWSInspectorPackageSchema(), common_job_parameters).run(
280
- neo4j_session,
281
- )
282
278
  GraphJob.from_matchlink(
283
279
  InspectorFindingToPackageMatchLink(),
284
280
  "AWSAccount",
285
281
  common_job_parameters["ACCOUNT_ID"],
286
282
  common_job_parameters["UPDATE_TAG"],
283
+ iterationsize=batch_size,
284
+ ).run(
285
+ neo4j_session,
286
+ )
287
+ GraphJob.from_node_schema(
288
+ AWSInspectorPackageSchema(), common_job_parameters, iterationsize=batch_size
289
+ ).run(
290
+ neo4j_session,
291
+ )
292
+ GraphJob.from_node_schema(
293
+ AWSInspectorFindingSchema(), common_job_parameters, iterationsize=batch_size
287
294
  ).run(
288
295
  neo4j_session,
289
296
  )
@@ -296,11 +303,12 @@ def _sync_findings_for_account(
296
303
  account_id: str,
297
304
  update_tag: int,
298
305
  current_aws_account_id: str,
306
+ batch_size: int = BATCH_SIZE,
299
307
  ) -> None:
300
308
  """
301
309
  Syncs the findings for a given account in a given region.
302
310
  """
303
- findings = get_inspector_findings(boto3_session, region, account_id)
311
+ findings = get_inspector_findings(boto3_session, region, account_id, batch_size)
304
312
  if not findings:
305
313
  logger.info(f"No findings to sync for account {account_id} in region {region}")
306
314
  return
@@ -343,6 +351,10 @@ def sync(
343
351
  update_tag: int,
344
352
  common_job_parameters: Dict[str, Any],
345
353
  ) -> None:
354
+ batch_size = common_job_parameters.get(
355
+ "experimental_aws_inspector_batch", BATCH_SIZE
356
+ )
357
+
346
358
  inspector_regions = [
347
359
  region for region in regions if region in AWS_INSPECTOR_REGIONS
348
360
  ]
@@ -363,8 +375,8 @@ def sync(
363
375
  account_id,
364
376
  update_tag,
365
377
  current_aws_account_id,
378
+ batch_size,
366
379
  )
367
- common_job_parameters["ACCOUNT_ID"] = current_aws_account_id
368
- common_job_parameters["UPDATE_TAG"] = update_tag
369
-
370
- cleanup(neo4j_session, common_job_parameters)
380
+ common_job_parameters["ACCOUNT_ID"] = current_aws_account_id
381
+ common_job_parameters["UPDATE_TAG"] = update_tag
382
+ cleanup(neo4j_session, common_job_parameters, batch_size)
@@ -13,6 +13,7 @@ import neo4j
13
13
  import yaml
14
14
 
15
15
  from cartography.client.core.tx import read_list_of_dicts_tx
16
+ from cartography.client.core.tx import read_list_of_values_tx
16
17
  from cartography.client.core.tx import run_write_query
17
18
  from cartography.graph.statement import GraphStatement
18
19
  from cartography.util import timeit
@@ -300,12 +301,11 @@ def get_resource_arns(
300
301
  get_resource_query_template = get_resource_query.safe_substitute(
301
302
  node_label=node_label,
302
303
  )
303
- results = neo4j_session.run(
304
+ return neo4j_session.execute_read(
305
+ read_list_of_values_tx,
304
306
  get_resource_query_template,
305
307
  AccountId=account_id,
306
308
  )
307
- arns = [r["arn"] for r in results]
308
- return arns
309
309
 
310
310
 
311
311
  def load_principal_mappings(
@@ -16,6 +16,7 @@ from botocore.exceptions import ClientError
16
16
  from botocore.exceptions import EndpointConnectionError
17
17
  from policyuniverse.policy import Policy
18
18
 
19
+ from cartography.client.core.tx import run_write_query
19
20
  from cartography.stats import get_stats_client
20
21
  from cartography.util import aws_handle_regions
21
22
  from cartography.util import merge_module_sync_metadata
@@ -334,7 +335,8 @@ def _load_s3_acls(
334
335
  SET r.lastupdated = $UpdateTag
335
336
  """
336
337
 
337
- neo4j_session.run(
338
+ run_write_query(
339
+ neo4j_session,
338
340
  ingest_acls,
339
341
  acls=acls,
340
342
  UpdateTag=update_tag,
@@ -368,7 +370,8 @@ def _load_s3_policies(
368
370
  s.lastupdated = $UpdateTag
369
371
  """
370
372
 
371
- neo4j_session.run(
373
+ run_write_query(
374
+ neo4j_session,
372
375
  ingest_policies,
373
376
  policies=policies,
374
377
  UpdateTag=update_tag,
@@ -401,11 +404,12 @@ def _load_s3_policy_statements(
401
404
  MERGE (bucket)-[r:POLICY_STATEMENT]->(statement)
402
405
  SET r.lastupdated = $UpdateTag
403
406
  """
404
- neo4j_session.run(
407
+ run_write_query(
408
+ neo4j_session,
405
409
  ingest_policy_statement,
406
410
  Statements=statements,
407
411
  UpdateTag=update_tag,
408
- ).consume()
412
+ )
409
413
 
410
414
 
411
415
  @timeit
@@ -427,7 +431,8 @@ def _load_s3_encryption(
427
431
  s.lastupdated = $UpdateTag
428
432
  """
429
433
 
430
- neo4j_session.run(
434
+ run_write_query(
435
+ neo4j_session,
431
436
  ingest_encryption,
432
437
  encryption_configs=encryption_configs,
433
438
  UpdateTag=update_tag,
@@ -451,7 +456,8 @@ def _load_s3_versioning(
451
456
  s.lastupdated = $UpdateTag
452
457
  """
453
458
 
454
- neo4j_session.run(
459
+ run_write_query(
460
+ neo4j_session,
455
461
  ingest_versioning,
456
462
  versioning_configs=versioning_configs,
457
463
  UpdateTag=update_tag,
@@ -477,7 +483,8 @@ def _load_s3_public_access_block(
477
483
  s.lastupdated = $UpdateTag
478
484
  """
479
485
 
480
- neo4j_session.run(
486
+ run_write_query(
487
+ neo4j_session,
481
488
  ingest_public_access_block,
482
489
  public_access_block_configs=public_access_block_configs,
483
490
  UpdateTag=update_tag,
@@ -500,7 +507,8 @@ def _load_bucket_ownership_controls(
500
507
  s.lastupdated = $UpdateTag
501
508
  """
502
509
 
503
- neo4j_session.run(
510
+ run_write_query(
511
+ neo4j_session,
504
512
  ingest_bucket_ownership_controls,
505
513
  bucket_ownership_controls_configs=bucket_ownership_controls_configs,
506
514
  UpdateTag=update_tag,
@@ -524,7 +532,8 @@ def _load_bucket_logging(
524
532
  bucket.logging_target_bucket = bucket_logging.target_bucket,
525
533
  bucket.lastupdated = $update_tag
526
534
  """
527
- neo4j_session.run(
535
+ run_write_query(
536
+ neo4j_session,
528
537
  ingest_bucket_logging,
529
538
  bucket_logging_configs=bucket_logging_configs,
530
539
  update_tag=update_tag,
@@ -536,7 +545,8 @@ def _set_default_values(neo4j_session: neo4j.Session, aws_account_id: str) -> No
536
545
  MATCH (:AWSAccount{id: $AWS_ID})-[:RESOURCE]->(s:S3Bucket) where s.anonymous_actions IS NULL
537
546
  SET s.anonymous_access = false, s.anonymous_actions = []
538
547
  """
539
- neo4j_session.run(
548
+ run_write_query(
549
+ neo4j_session,
540
550
  set_defaults,
541
551
  AWS_ID=aws_account_id,
542
552
  )
@@ -545,7 +555,8 @@ def _set_default_values(neo4j_session: neo4j.Session, aws_account_id: str) -> No
545
555
  MATCH (:AWSAccount{id: $AWS_ID})-[:RESOURCE]->(s:S3Bucket) where s.default_encryption IS NULL
546
556
  SET s.default_encryption = false
547
557
  """
548
- neo4j_session.run(
558
+ run_write_query(
559
+ neo4j_session,
549
560
  set_encryption_defaults,
550
561
  AWS_ID=aws_account_id,
551
562
  )
@@ -993,7 +1004,8 @@ def _load_s3_notifications(
993
1004
  ON CREATE SET r.firstseen = timestamp()
994
1005
  SET r.lastupdated = $UpdateTag
995
1006
  """
996
- neo4j_session.run(
1007
+ run_write_query(
1008
+ neo4j_session,
997
1009
  ingest_notifications,
998
1010
  notifications=notifications,
999
1011
  UpdateTag=update_tag,
@@ -1025,7 +1037,8 @@ def load_s3_buckets(
1025
1037
 
1026
1038
  for bucket in data["Buckets"]:
1027
1039
  arn = "arn:aws:s3:::" + bucket["Name"]
1028
- neo4j_session.run(
1040
+ run_write_query(
1041
+ neo4j_session,
1029
1042
  ingest_bucket,
1030
1043
  BucketName=bucket["Name"],
1031
1044
  BucketRegion=bucket["Region"],
@@ -9,6 +9,7 @@ import boto3
9
9
  import neo4j
10
10
 
11
11
  from cartography.client.core.tx import load
12
+ from cartography.client.core.tx import read_list_of_values_tx
12
13
  from cartography.graph.job import GraphJob
13
14
  from cartography.models.aws.ssm.instance_information import SSMInstanceInformationSchema
14
15
  from cartography.models.aws.ssm.instance_patch import SSMInstancePatchSchema
@@ -31,15 +32,12 @@ def get_instance_ids(
31
32
  WHERE i.region = $Region
32
33
  RETURN i.id
33
34
  """
34
- results = neo4j_session.run(
35
+ return neo4j_session.execute_read(
36
+ read_list_of_values_tx,
35
37
  get_instances_query,
36
38
  AWS_ACCOUNT_ID=current_aws_account_id,
37
39
  Region=region,
38
40
  )
39
- instance_ids = []
40
- for r in results:
41
- instance_ids.append(r["i.id"])
42
- return instance_ids
43
41
 
44
42
 
45
43
  @timeit
@@ -6,6 +6,7 @@ import neo4j
6
6
  from azure.core.exceptions import HttpResponseError
7
7
  from azure.mgmt.compute import ComputeManagementClient
8
8
 
9
+ from cartography.client.core.tx import run_write_query
9
10
  from cartography.util import run_cleanup_job
10
11
  from cartography.util import timeit
11
12
 
@@ -63,7 +64,8 @@ def load_vms(
63
64
  SET r.lastupdated = $update_tag
64
65
  """
65
66
 
66
- neo4j_session.run(
67
+ run_write_query(
68
+ neo4j_session,
67
69
  ingest_vm,
68
70
  vms=vm_list,
69
71
  SUBSCRIPTION_ID=subscription_id,
@@ -103,7 +105,8 @@ def load_vm_data_disks(
103
105
  """
104
106
 
105
107
  # for disk in data_disks:
106
- neo4j_session.run(
108
+ run_write_query(
109
+ neo4j_session,
107
110
  ingest_data_disk,
108
111
  disks=data_disks,
109
112
  VM_ID=vm_id,
@@ -162,7 +165,8 @@ def load_disks(
162
165
  ON CREATE SET r.firstseen = timestamp()
163
166
  SET r.lastupdated = $update_tag"""
164
167
 
165
- neo4j_session.run(
168
+ run_write_query(
169
+ neo4j_session,
166
170
  ingest_disks,
167
171
  disks=disk_list,
168
172
  SUBSCRIPTION_ID=subscription_id,
@@ -217,7 +221,8 @@ def load_snapshots(
217
221
  ON CREATE SET r.firstseen = timestamp()
218
222
  SET r.lastupdated = $update_tag"""
219
223
 
220
- neo4j_session.run(
224
+ run_write_query(
225
+ neo4j_session,
221
226
  ingest_snapshots,
222
227
  snapshots=snapshots,
223
228
  SUBSCRIPTION_ID=subscription_id,