cartography 0.108.0rc2__py3-none-any.whl → 0.109.0rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cartography might be problematic. Click here for more details.

Files changed (26) hide show
  1. cartography/_version.py +2 -2
  2. cartography/data/indexes.cypher +0 -2
  3. cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json +0 -12
  4. cartography/intel/aws/cloudtrail_management_events.py +36 -3
  5. cartography/intel/aws/ecr.py +55 -80
  6. cartography/intel/aws/resourcegroupstaggingapi.py +77 -18
  7. cartography/intel/aws/secretsmanager.py +62 -44
  8. cartography/intel/entra/groups.py +29 -1
  9. cartography/intel/gcp/__init__.py +10 -0
  10. cartography/intel/gcp/compute.py +19 -42
  11. cartography/models/aws/ecr/__init__.py +0 -0
  12. cartography/models/aws/ecr/image.py +41 -0
  13. cartography/models/aws/ecr/repository.py +72 -0
  14. cartography/models/aws/ecr/repository_image.py +95 -0
  15. cartography/models/aws/secretsmanager/secret.py +106 -0
  16. cartography/models/entra/group.py +26 -0
  17. cartography/models/entra/user.py +6 -0
  18. cartography/models/gcp/compute/__init__.py +0 -0
  19. cartography/models/gcp/compute/vpc.py +50 -0
  20. {cartography-0.108.0rc2.dist-info → cartography-0.109.0rc1.dist-info}/METADATA +1 -1
  21. {cartography-0.108.0rc2.dist-info → cartography-0.109.0rc1.dist-info}/RECORD +25 -19
  22. cartography/data/jobs/cleanup/aws_import_secrets_cleanup.json +0 -8
  23. {cartography-0.108.0rc2.dist-info → cartography-0.109.0rc1.dist-info}/WHEEL +0 -0
  24. {cartography-0.108.0rc2.dist-info → cartography-0.109.0rc1.dist-info}/entry_points.txt +0 -0
  25. {cartography-0.108.0rc2.dist-info → cartography-0.109.0rc1.dist-info}/licenses/LICENSE +0 -0
  26. {cartography-0.108.0rc2.dist-info → cartography-0.109.0rc1.dist-info}/top_level.txt +0 -0
@@ -391,6 +391,7 @@ def _sync_multiple_projects(
391
391
  # Compute data sync
392
392
  for project in projects:
393
393
  project_id = project["projectId"]
394
+ common_job_parameters["PROJECT_ID"] = project_id
394
395
  logger.info("Syncing GCP project %s for Compute.", project_id)
395
396
  _sync_single_project_compute(
396
397
  neo4j_session,
@@ -399,10 +400,12 @@ def _sync_multiple_projects(
399
400
  gcp_update_tag,
400
401
  common_job_parameters,
401
402
  )
403
+ del common_job_parameters["PROJECT_ID"]
402
404
 
403
405
  # Storage data sync
404
406
  for project in projects:
405
407
  project_id = project["projectId"]
408
+ common_job_parameters["PROJECT_ID"] = project_id
406
409
  logger.info("Syncing GCP project %s for Storage", project_id)
407
410
  _sync_single_project_storage(
408
411
  neo4j_session,
@@ -411,10 +414,12 @@ def _sync_multiple_projects(
411
414
  gcp_update_tag,
412
415
  common_job_parameters,
413
416
  )
417
+ del common_job_parameters["PROJECT_ID"]
414
418
 
415
419
  # GKE data sync
416
420
  for project in projects:
417
421
  project_id = project["projectId"]
422
+ common_job_parameters["PROJECT_ID"] = project_id
418
423
  logger.info("Syncing GCP project %s for GKE", project_id)
419
424
  _sync_single_project_gke(
420
425
  neo4j_session,
@@ -423,10 +428,12 @@ def _sync_multiple_projects(
423
428
  gcp_update_tag,
424
429
  common_job_parameters,
425
430
  )
431
+ del common_job_parameters["PROJECT_ID"]
426
432
 
427
433
  # DNS data sync
428
434
  for project in projects:
429
435
  project_id = project["projectId"]
436
+ common_job_parameters["PROJECT_ID"] = project_id
430
437
  logger.info("Syncing GCP project %s for DNS", project_id)
431
438
  _sync_single_project_dns(
432
439
  neo4j_session,
@@ -435,14 +442,17 @@ def _sync_multiple_projects(
435
442
  gcp_update_tag,
436
443
  common_job_parameters,
437
444
  )
445
+ del common_job_parameters["PROJECT_ID"]
438
446
 
439
447
  # IAM data sync
440
448
  for project in projects:
441
449
  project_id = project["projectId"]
450
+ common_job_parameters["PROJECT_ID"] = project_id
442
451
  logger.info("Syncing GCP project %s for IAM", project_id)
443
452
  _sync_single_project_iam(
444
453
  neo4j_session, resources, project_id, gcp_update_tag, common_job_parameters
445
454
  )
455
+ del common_job_parameters["PROJECT_ID"]
446
456
 
447
457
 
448
458
  @timeit
@@ -14,6 +14,9 @@ import neo4j
14
14
  from googleapiclient.discovery import HttpError
15
15
  from googleapiclient.discovery import Resource
16
16
 
17
+ from cartography.client.core.tx import load
18
+ from cartography.graph.job import GraphJob
19
+ from cartography.models.gcp.compute.vpc import GCPVpcSchema
17
20
  from cartography.util import run_cleanup_job
18
21
  from cartography.util import timeit
19
22
 
@@ -600,48 +603,17 @@ def load_gcp_instances(
600
603
  @timeit
601
604
  def load_gcp_vpcs(
602
605
  neo4j_session: neo4j.Session,
603
- vpcs: List[Dict],
606
+ vpcs: list[dict[str, Any]],
604
607
  gcp_update_tag: int,
608
+ project_id: str,
605
609
  ) -> None:
606
- """
607
- Ingest VPCs to Neo4j
608
- :param neo4j_session: The Neo4j session object
609
- :param vpcs: List of VPCs to ingest
610
- :param gcp_update_tag: The timestamp value to set our new Neo4j nodes with
611
- :return: Nothing
612
- """
613
- query = """
614
- MERGE(p:GCPProject{id:$ProjectId})
615
- ON CREATE SET p.firstseen = timestamp()
616
- SET p.lastupdated = $gcp_update_tag
617
-
618
- MERGE(vpc:GCPVpc{id:$PartialUri})
619
- ON CREATE SET vpc.firstseen = timestamp(),
620
- vpc.partial_uri = $PartialUri
621
- SET vpc.self_link = $SelfLink,
622
- vpc.name = $VpcName,
623
- vpc.project_id = $ProjectId,
624
- vpc.auto_create_subnetworks = $AutoCreateSubnetworks,
625
- vpc.routing_config_routing_mode = $RoutingMode,
626
- vpc.description = $Description,
627
- vpc.lastupdated = $gcp_update_tag
628
-
629
- MERGE (p)-[r:RESOURCE]->(vpc)
630
- ON CREATE SET r.firstseen = timestamp()
631
- SET r.lastupdated = $gcp_update_tag
632
- """
633
- for vpc in vpcs:
634
- neo4j_session.run(
635
- query,
636
- ProjectId=vpc["project_id"],
637
- PartialUri=vpc["partial_uri"],
638
- SelfLink=vpc["self_link"],
639
- VpcName=vpc["name"],
640
- AutoCreateSubnetworks=vpc["auto_create_subnetworks"],
641
- RoutingMode=vpc["routing_config_routing_mode"],
642
- Description=vpc["description"],
643
- gcp_update_tag=gcp_update_tag,
644
- )
610
+ load(
611
+ neo4j_session,
612
+ GCPVpcSchema(),
613
+ vpcs,
614
+ PROJECT_ID=project_id,
615
+ LASTUPDATED=gcp_update_tag,
616
+ )
645
617
 
646
618
 
647
619
  @timeit
@@ -1159,6 +1131,12 @@ def cleanup_gcp_vpcs(neo4j_session: neo4j.Session, common_job_parameters: Dict)
1159
1131
  :param common_job_parameters: dict of other job parameters to pass to Neo4j
1160
1132
  :return: Nothing
1161
1133
  """
1134
+ GraphJob.from_node_schema(
1135
+ GCPVpcSchema(),
1136
+ common_job_parameters,
1137
+ ).run(neo4j_session)
1138
+
1139
+ # TODO: remove this once we refactor GCP instances and add the instance to vpc rel as an object
1162
1140
  run_cleanup_job(
1163
1141
  "gcp_compute_vpc_cleanup.json",
1164
1142
  neo4j_session,
@@ -1267,8 +1245,7 @@ def sync_gcp_vpcs(
1267
1245
  """
1268
1246
  vpc_res = get_gcp_vpcs(project_id, compute)
1269
1247
  vpcs = transform_gcp_vpcs(vpc_res)
1270
- load_gcp_vpcs(neo4j_session, vpcs, gcp_update_tag)
1271
- # TODO scope the cleanup to the current project - https://github.com/cartography-cncf/cartography/issues/381
1248
+ load_gcp_vpcs(neo4j_session, vpcs, gcp_update_tag, project_id)
1272
1249
  cleanup_gcp_vpcs(neo4j_session, common_job_parameters)
1273
1250
 
1274
1251
 
File without changes
@@ -0,0 +1,41 @@
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 ECRImageNodeProperties(CartographyNodeProperties):
15
+ id: PropertyRef = PropertyRef("imageDigest")
16
+ digest: PropertyRef = PropertyRef("imageDigest")
17
+ region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
18
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class ECRImageToAWSAccountRelProperties(CartographyRelProperties):
23
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
24
+
25
+
26
+ @dataclass(frozen=True)
27
+ class ECRImageToAWSAccountRel(CartographyRelSchema):
28
+ target_node_label: str = "AWSAccount"
29
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
30
+ {"id": PropertyRef("AWS_ID", set_in_kwargs=True)}
31
+ )
32
+ direction: LinkDirection = LinkDirection.INWARD
33
+ rel_label: str = "RESOURCE"
34
+ properties: ECRImageToAWSAccountRelProperties = ECRImageToAWSAccountRelProperties()
35
+
36
+
37
+ @dataclass(frozen=True)
38
+ class ECRImageSchema(CartographyNodeSchema):
39
+ label: str = "ECRImage"
40
+ properties: ECRImageNodeProperties = ECRImageNodeProperties()
41
+ sub_resource_relationship: ECRImageToAWSAccountRel = ECRImageToAWSAccountRel()
@@ -0,0 +1,72 @@
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 ECRRepositoryNodeProperties(CartographyNodeProperties):
16
+ id: PropertyRef = PropertyRef("repositoryArn")
17
+ arn: PropertyRef = PropertyRef("repositoryArn", extra_index=True)
18
+ name: PropertyRef = PropertyRef("repositoryName", extra_index=True)
19
+ uri: PropertyRef = PropertyRef("repositoryUri", extra_index=True)
20
+ created_at: PropertyRef = PropertyRef("createdAt")
21
+ region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
22
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class ECRRepositoryToAWSAccountRelProperties(CartographyRelProperties):
27
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class ECRRepositoryToAWSAccountRel(CartographyRelSchema):
32
+ target_node_label: str = "AWSAccount"
33
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
34
+ {"id": PropertyRef("AWS_ID", set_in_kwargs=True)}
35
+ )
36
+ direction: LinkDirection = LinkDirection.INWARD
37
+ rel_label: str = "RESOURCE"
38
+ properties: ECRRepositoryToAWSAccountRelProperties = (
39
+ ECRRepositoryToAWSAccountRelProperties()
40
+ )
41
+
42
+
43
+ @dataclass(frozen=True)
44
+ class ECRRepositoryToRepositoryImageRelProperties(CartographyRelProperties):
45
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class ECRRepositoryToRepositoryImageRel(CartographyRelSchema):
50
+ target_node_label: str = "ECRRepositoryImage"
51
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
52
+ {"id": PropertyRef("id")}
53
+ )
54
+ direction: LinkDirection = LinkDirection.OUTWARD
55
+ rel_label: str = "REPO_IMAGE"
56
+ properties: ECRRepositoryToRepositoryImageRelProperties = (
57
+ ECRRepositoryToRepositoryImageRelProperties()
58
+ )
59
+
60
+
61
+ @dataclass(frozen=True)
62
+ class ECRRepositorySchema(CartographyNodeSchema):
63
+ label: str = "ECRRepository"
64
+ properties: ECRRepositoryNodeProperties = ECRRepositoryNodeProperties()
65
+ sub_resource_relationship: ECRRepositoryToAWSAccountRel = (
66
+ ECRRepositoryToAWSAccountRel()
67
+ )
68
+ other_relationships: OtherRelationships = OtherRelationships(
69
+ [
70
+ ECRRepositoryToRepositoryImageRel(),
71
+ ]
72
+ )
@@ -0,0 +1,95 @@
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 ECRRepositoryImageNodeProperties(CartographyNodeProperties):
16
+ id: PropertyRef = PropertyRef("id")
17
+ tag: PropertyRef = PropertyRef("imageTag")
18
+ uri: PropertyRef = PropertyRef("uri")
19
+ repo_uri: PropertyRef = PropertyRef("repo_uri")
20
+ image_size_bytes: PropertyRef = PropertyRef("imageSizeInBytes")
21
+ image_pushed_at: PropertyRef = PropertyRef("imagePushedAt")
22
+ image_manifest_media_type: PropertyRef = PropertyRef("imageManifestMediaType")
23
+ artifact_media_type: PropertyRef = PropertyRef("artifactMediaType")
24
+ last_recorded_pull_time: PropertyRef = PropertyRef("lastRecordedPullTime")
25
+ region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
26
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class ECRRepositoryImageToAWSAccountRelProperties(CartographyRelProperties):
31
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class ECRRepositoryImageToAWSAccountRel(CartographyRelSchema):
36
+ target_node_label: str = "AWSAccount"
37
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
38
+ {"id": PropertyRef("AWS_ID", set_in_kwargs=True)}
39
+ )
40
+ direction: LinkDirection = LinkDirection.INWARD
41
+ rel_label: str = "RESOURCE"
42
+ properties: ECRRepositoryImageToAWSAccountRelProperties = (
43
+ ECRRepositoryImageToAWSAccountRelProperties()
44
+ )
45
+
46
+
47
+ @dataclass(frozen=True)
48
+ class ECRRepositoryImageToECRRepositoryRelProperties(CartographyRelProperties):
49
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
50
+
51
+
52
+ @dataclass(frozen=True)
53
+ class ECRRepositoryImageToECRRepositoryRel(CartographyRelSchema):
54
+ target_node_label: str = "ECRRepository"
55
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
56
+ {"uri": PropertyRef("repo_uri")}
57
+ )
58
+ direction: LinkDirection = LinkDirection.INWARD
59
+ rel_label: str = "REPO_IMAGE"
60
+ properties: ECRRepositoryImageToECRRepositoryRelProperties = (
61
+ ECRRepositoryImageToECRRepositoryRelProperties()
62
+ )
63
+
64
+
65
+ @dataclass(frozen=True)
66
+ class ECRRepositoryImageToECRImageRelProperties(CartographyRelProperties):
67
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
68
+
69
+
70
+ @dataclass(frozen=True)
71
+ class ECRRepositoryImageToECRImageRel(CartographyRelSchema):
72
+ target_node_label: str = "ECRImage"
73
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
74
+ {"id": PropertyRef("imageDigest")}
75
+ )
76
+ direction: LinkDirection = LinkDirection.OUTWARD
77
+ rel_label: str = "IMAGE"
78
+ properties: ECRRepositoryImageToECRImageRelProperties = (
79
+ ECRRepositoryImageToECRImageRelProperties()
80
+ )
81
+
82
+
83
+ @dataclass(frozen=True)
84
+ class ECRRepositoryImageSchema(CartographyNodeSchema):
85
+ label: str = "ECRRepositoryImage"
86
+ properties: ECRRepositoryImageNodeProperties = ECRRepositoryImageNodeProperties()
87
+ sub_resource_relationship: ECRRepositoryImageToAWSAccountRel = (
88
+ ECRRepositoryImageToAWSAccountRel()
89
+ )
90
+ other_relationships: OtherRelationships = OtherRelationships(
91
+ [
92
+ ECRRepositoryImageToECRRepositoryRel(),
93
+ ECRRepositoryImageToECRImageRel(),
94
+ ]
95
+ )
@@ -0,0 +1,106 @@
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 SecretsManagerSecretNodeProperties(CartographyNodeProperties):
16
+ """
17
+ Properties for AWS Secrets Manager Secret
18
+ """
19
+
20
+ id: PropertyRef = PropertyRef("ARN")
21
+ arn: PropertyRef = PropertyRef("ARN", extra_index=True)
22
+ name: PropertyRef = PropertyRef("Name", extra_index=True)
23
+ description: PropertyRef = PropertyRef("Description")
24
+
25
+ # Rotation properties
26
+ rotation_enabled: PropertyRef = PropertyRef("RotationEnabled")
27
+ rotation_lambda_arn: PropertyRef = PropertyRef("RotationLambdaARN")
28
+ rotation_rules_automatically_after_days: PropertyRef = PropertyRef(
29
+ "RotationRulesAutomaticallyAfterDays"
30
+ )
31
+
32
+ # Date properties (will be converted to epoch timestamps)
33
+ created_date: PropertyRef = PropertyRef("CreatedDate")
34
+ last_rotated_date: PropertyRef = PropertyRef("LastRotatedDate")
35
+ last_changed_date: PropertyRef = PropertyRef("LastChangedDate")
36
+ last_accessed_date: PropertyRef = PropertyRef("LastAccessedDate")
37
+ deleted_date: PropertyRef = PropertyRef("DeletedDate")
38
+
39
+ # Other properties
40
+ kms_key_id: PropertyRef = PropertyRef("KmsKeyId")
41
+ owning_service: PropertyRef = PropertyRef("OwningService")
42
+ primary_region: PropertyRef = PropertyRef("PrimaryRegion")
43
+
44
+ # Standard cartography properties
45
+ region: PropertyRef = PropertyRef("Region", set_in_kwargs=True)
46
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
47
+
48
+
49
+ @dataclass(frozen=True)
50
+ class SecretsManagerSecretRelProperties(CartographyRelProperties):
51
+ """
52
+ Properties for relationships between Secret and other nodes
53
+ """
54
+
55
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
56
+
57
+
58
+ @dataclass(frozen=True)
59
+ class SecretsManagerSecretToAWSAccountRel(CartographyRelSchema):
60
+ """
61
+ Relationship between Secret and AWS Account
62
+ """
63
+
64
+ target_node_label: str = "AWSAccount"
65
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
66
+ {"id": PropertyRef("AWS_ID", set_in_kwargs=True)},
67
+ )
68
+ direction: LinkDirection = LinkDirection.INWARD
69
+ rel_label: str = "RESOURCE"
70
+ properties: SecretsManagerSecretRelProperties = SecretsManagerSecretRelProperties()
71
+
72
+
73
+ @dataclass(frozen=True)
74
+ class SecretsManagerSecretToKMSKeyRel(CartographyRelSchema):
75
+ """
76
+ Relationship between Secret and its KMS key
77
+ Only created when KmsKeyId is present
78
+ """
79
+
80
+ target_node_label: str = "AWSKMSKey"
81
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
82
+ {"id": PropertyRef("KmsKeyId")},
83
+ )
84
+ direction: LinkDirection = LinkDirection.OUTWARD
85
+ rel_label: str = "ENCRYPTED_BY"
86
+ properties: SecretsManagerSecretRelProperties = SecretsManagerSecretRelProperties()
87
+
88
+
89
+ @dataclass(frozen=True)
90
+ class SecretsManagerSecretSchema(CartographyNodeSchema):
91
+ """
92
+ Schema for AWS Secrets Manager Secret
93
+ """
94
+
95
+ label: str = "SecretsManagerSecret"
96
+ properties: SecretsManagerSecretNodeProperties = (
97
+ SecretsManagerSecretNodeProperties()
98
+ )
99
+ sub_resource_relationship: SecretsManagerSecretToAWSAccountRel = (
100
+ SecretsManagerSecretToAWSAccountRel()
101
+ )
102
+ other_relationships: OtherRelationships = OtherRelationships(
103
+ [
104
+ SecretsManagerSecretToKMSKeyRel(),
105
+ ],
106
+ )
@@ -3,6 +3,7 @@ from dataclasses import dataclass
3
3
  from cartography.models.core.common import PropertyRef
4
4
  from cartography.models.core.nodes import CartographyNodeProperties
5
5
  from cartography.models.core.nodes import CartographyNodeSchema
6
+ from cartography.models.core.nodes import ExtraNodeLabels
6
7
  from cartography.models.core.relationships import CartographyRelProperties
7
8
  from cartography.models.core.relationships import CartographyRelSchema
8
9
  from cartography.models.core.relationships import LinkDirection
@@ -78,6 +79,25 @@ class EntraGroupToGroupRel(CartographyRelSchema):
78
79
  properties: EntraGroupToGroupRelProperties = EntraGroupToGroupRelProperties()
79
80
 
80
81
 
82
+ @dataclass(frozen=True)
83
+ class EntraGroupToOwnerRelProperties(CartographyRelProperties):
84
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
85
+
86
+
87
+ @dataclass(frozen=True)
88
+ # (:EntraGroup)<-[:OWNER_OF]-(:EntraUser)
89
+ class EntraGroupToOwnerRel(CartographyRelSchema):
90
+ # EntraUsers and Entra service principals can be owners of a group, so we match on the general label
91
+ # Because id is indexed, this should be fast even though EntraIdentity will also include EntraGroups
92
+ target_node_label: str = "EntraIdentity"
93
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
94
+ {"id": PropertyRef("owner_ids", one_to_many=True)}
95
+ )
96
+ direction: LinkDirection = LinkDirection.INWARD
97
+ rel_label: str = "OWNER_OF"
98
+ properties: EntraGroupToOwnerRelProperties = EntraGroupToOwnerRelProperties()
99
+
100
+
81
101
  @dataclass(frozen=True)
82
102
  class EntraGroupSchema(CartographyNodeSchema):
83
103
  label: str = "EntraGroup"
@@ -87,5 +107,11 @@ class EntraGroupSchema(CartographyNodeSchema):
87
107
  [
88
108
  EntraGroupToGroupRel(),
89
109
  EntraGroupToUserRel(),
110
+ EntraGroupToOwnerRel(),
111
+ ]
112
+ )
113
+ extra_node_labels: ExtraNodeLabels = ExtraNodeLabels(
114
+ [
115
+ "EntraIdentity",
90
116
  ]
91
117
  )
@@ -3,6 +3,7 @@ from dataclasses import dataclass
3
3
  from cartography.models.core.common import PropertyRef
4
4
  from cartography.models.core.nodes import CartographyNodeProperties
5
5
  from cartography.models.core.nodes import CartographyNodeSchema
6
+ from cartography.models.core.nodes import ExtraNodeLabels
6
7
  from cartography.models.core.relationships import CartographyRelProperties
7
8
  from cartography.models.core.relationships import CartographyRelSchema
8
9
  from cartography.models.core.relationships import LinkDirection
@@ -63,3 +64,8 @@ class EntraUserSchema(CartographyNodeSchema):
63
64
  label: str = "EntraUser"
64
65
  properties: EntraUserNodeProperties = EntraUserNodeProperties()
65
66
  sub_resource_relationship: EntraUserToTenantRel = EntraUserToTenantRel()
67
+ extra_node_labels: ExtraNodeLabels = ExtraNodeLabels(
68
+ [
69
+ "EntraIdentity",
70
+ ]
71
+ )
File without changes
@@ -0,0 +1,50 @@
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 GCPVpcNodeProperties(CartographyNodeProperties):
15
+ id: PropertyRef = PropertyRef("partial_uri", extra_index=True)
16
+ lastupdated: PropertyRef = PropertyRef("LASTUPDATED", set_in_kwargs=True)
17
+ partial_uri: PropertyRef = PropertyRef("partial_uri")
18
+ self_link: PropertyRef = PropertyRef("self_link")
19
+ name: PropertyRef = PropertyRef("name", extra_index=True)
20
+ project_id: PropertyRef = PropertyRef("PROJECT_ID", set_in_kwargs=True)
21
+ auto_create_subnetworks: PropertyRef = PropertyRef("auto_create_subnetworks")
22
+ routing_config_routing_mode: PropertyRef = PropertyRef(
23
+ "routing_config_routing_mode"
24
+ )
25
+ description: PropertyRef = PropertyRef("description")
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class GCPVpcToProjectRelProperties(CartographyRelProperties):
30
+ lastupdated: PropertyRef = PropertyRef("LASTUPDATED", set_in_kwargs=True)
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ class GCPVpcToProjectRel(CartographyRelSchema):
35
+ target_node_label: str = "GCPProject"
36
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
37
+ {
38
+ "id": PropertyRef("PROJECT_ID", set_in_kwargs=True),
39
+ }
40
+ )
41
+ direction: LinkDirection = LinkDirection.INWARD
42
+ rel_label: str = "RESOURCE"
43
+ properties: GCPVpcToProjectRelProperties = GCPVpcToProjectRelProperties()
44
+
45
+
46
+ @dataclass(frozen=True)
47
+ class GCPVpcSchema(CartographyNodeSchema):
48
+ label: str = "GCPVpc"
49
+ properties: GCPVpcNodeProperties = GCPVpcNodeProperties()
50
+ sub_resource_relationship: GCPVpcToProjectRel = GCPVpcToProjectRel()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cartography
3
- Version: 0.108.0rc2
3
+ Version: 0.109.0rc1
4
4
  Summary: Explore assets and their relationships across your technical infrastructure.
5
5
  Maintainer: Cartography Contributors
6
6
  License: apache2