cartography 0.117.0__py3-none-any.whl → 0.119.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cartography might be problematic. Click here for more details.
- cartography/_version.py +2 -2
- cartography/cli.py +31 -0
- cartography/client/core/tx.py +19 -3
- cartography/config.py +14 -0
- cartography/data/indexes.cypher +0 -6
- cartography/graph/job.py +13 -7
- cartography/graph/statement.py +4 -0
- cartography/intel/aws/__init__.py +22 -9
- cartography/intel/aws/apigateway.py +18 -5
- cartography/intel/aws/ec2/elastic_ip_addresses.py +3 -1
- cartography/intel/aws/ec2/internet_gateways.py +4 -2
- cartography/intel/aws/ec2/load_balancer_v2s.py +11 -5
- cartography/intel/aws/ec2/network_interfaces.py +4 -0
- cartography/intel/aws/ec2/reserved_instances.py +3 -1
- cartography/intel/aws/ec2/tgw.py +11 -5
- cartography/intel/aws/ec2/volumes.py +1 -1
- cartography/intel/aws/ecr.py +209 -26
- cartography/intel/aws/ecr_image_layers.py +143 -42
- cartography/intel/aws/elasticsearch.py +13 -4
- cartography/intel/aws/identitycenter.py +93 -54
- cartography/intel/aws/inspector.py +90 -46
- cartography/intel/aws/permission_relationships.py +3 -3
- cartography/intel/aws/resourcegroupstaggingapi.py +1 -1
- cartography/intel/aws/s3.py +26 -13
- cartography/intel/aws/ssm.py +3 -5
- cartography/intel/azure/compute.py +9 -4
- cartography/intel/azure/cosmosdb.py +31 -15
- cartography/intel/azure/sql.py +25 -12
- cartography/intel/azure/storage.py +19 -9
- cartography/intel/azure/subscription.py +3 -1
- cartography/intel/crowdstrike/spotlight.py +5 -2
- cartography/intel/entra/app_role_assignments.py +9 -2
- cartography/intel/gcp/__init__.py +26 -9
- cartography/intel/gcp/clients.py +8 -4
- cartography/intel/gcp/compute.py +42 -21
- cartography/intel/gcp/crm/folders.py +9 -3
- cartography/intel/gcp/crm/orgs.py +8 -3
- cartography/intel/gcp/crm/projects.py +14 -3
- cartography/intel/github/repos.py +23 -5
- cartography/intel/gsuite/__init__.py +12 -8
- cartography/intel/gsuite/groups.py +291 -0
- cartography/intel/gsuite/users.py +142 -0
- cartography/intel/jamf/computers.py +7 -1
- cartography/intel/oci/iam.py +23 -9
- cartography/intel/oci/organizations.py +3 -1
- cartography/intel/oci/utils.py +28 -5
- cartography/intel/okta/awssaml.py +9 -8
- cartography/intel/okta/users.py +1 -1
- cartography/intel/ontology/__init__.py +44 -0
- cartography/intel/ontology/devices.py +54 -0
- cartography/intel/ontology/users.py +54 -0
- cartography/intel/ontology/utils.py +121 -0
- cartography/intel/pagerduty/escalation_policies.py +13 -6
- cartography/intel/pagerduty/schedules.py +9 -4
- cartography/intel/pagerduty/services.py +7 -3
- cartography/intel/pagerduty/teams.py +5 -2
- cartography/intel/pagerduty/users.py +3 -1
- cartography/intel/pagerduty/vendors.py +3 -1
- cartography/intel/trivy/__init__.py +109 -58
- cartography/models/airbyte/user.py +4 -0
- cartography/models/anthropic/user.py +4 -0
- cartography/models/aws/ec2/networkinterfaces.py +2 -0
- cartography/models/aws/ecr/image.py +55 -0
- cartography/models/aws/ecr/repository_image.py +1 -1
- cartography/models/aws/iam/group_membership.py +3 -2
- cartography/models/aws/identitycenter/awsssouser.py +3 -1
- cartography/models/bigfix/bigfix_computer.py +1 -1
- cartography/models/cloudflare/member.py +4 -0
- cartography/models/crowdstrike/hosts.py +1 -1
- cartography/models/duo/endpoint.py +1 -1
- cartography/models/duo/phone.py +2 -2
- cartography/models/duo/user.py +4 -0
- cartography/models/entra/user.py +2 -1
- cartography/models/github/users.py +4 -0
- cartography/models/gsuite/__init__.py +0 -0
- cartography/models/gsuite/group.py +218 -0
- cartography/models/gsuite/tenant.py +29 -0
- cartography/models/gsuite/user.py +107 -0
- cartography/models/kandji/device.py +1 -2
- cartography/models/keycloak/user.py +4 -0
- cartography/models/lastpass/user.py +4 -0
- cartography/models/ontology/__init__.py +0 -0
- cartography/models/ontology/device.py +125 -0
- cartography/models/ontology/mapping/__init__.py +16 -0
- cartography/models/ontology/mapping/data/__init__.py +1 -0
- cartography/models/ontology/mapping/data/devices.py +160 -0
- cartography/models/ontology/mapping/data/users.py +239 -0
- cartography/models/ontology/mapping/specs.py +65 -0
- cartography/models/ontology/user.py +52 -0
- cartography/models/openai/user.py +4 -0
- cartography/models/scaleway/iam/user.py +4 -0
- cartography/models/snipeit/asset.py +1 -0
- cartography/models/snipeit/user.py +4 -0
- cartography/models/tailscale/device.py +1 -1
- cartography/models/tailscale/user.py +6 -1
- cartography/rules/data/frameworks/mitre_attack/requirements/t1098_account_manipulation/__init__.py +176 -89
- cartography/sync.py +4 -1
- cartography/util.py +49 -18
- {cartography-0.117.0.dist-info → cartography-0.119.0.dist-info}/METADATA +3 -3
- {cartography-0.117.0.dist-info → cartography-0.119.0.dist-info}/RECORD +104 -89
- cartography/data/jobs/cleanup/gsuite_ingest_groups_cleanup.json +0 -23
- cartography/data/jobs/cleanup/gsuite_ingest_users_cleanup.json +0 -11
- cartography/intel/gsuite/api.py +0 -355
- {cartography-0.117.0.dist-info → cartography-0.119.0.dist-info}/WHEEL +0 -0
- {cartography-0.117.0.dist-info → cartography-0.119.0.dist-info}/entry_points.txt +0 -0
- {cartography-0.117.0.dist-info → cartography-0.119.0.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.117.0.dist-info → cartography-0.119.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
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.nodes import ExtraNodeLabels
|
|
7
|
+
from cartography.models.core.relationships import CartographyRelProperties
|
|
8
|
+
from cartography.models.core.relationships import CartographyRelSchema
|
|
9
|
+
from cartography.models.core.relationships import LinkDirection
|
|
10
|
+
from cartography.models.core.relationships import make_source_node_matcher
|
|
11
|
+
from cartography.models.core.relationships import make_target_node_matcher
|
|
12
|
+
from cartography.models.core.relationships import OtherRelationships
|
|
13
|
+
from cartography.models.core.relationships import SourceNodeMatcher
|
|
14
|
+
from cartography.models.core.relationships import TargetNodeMatcher
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True)
|
|
18
|
+
class GSuiteGroupNodeProperties(CartographyNodeProperties):
|
|
19
|
+
"""
|
|
20
|
+
GSuite group node properties
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
id: PropertyRef = PropertyRef("id")
|
|
24
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
25
|
+
|
|
26
|
+
# Group identifiers and basic info
|
|
27
|
+
group_id: PropertyRef = PropertyRef("id") # Alias for id
|
|
28
|
+
email: PropertyRef = PropertyRef("email", extra_index=True)
|
|
29
|
+
name: PropertyRef = PropertyRef("name")
|
|
30
|
+
description: PropertyRef = PropertyRef("description")
|
|
31
|
+
|
|
32
|
+
# Group settings
|
|
33
|
+
admin_created: PropertyRef = PropertyRef("adminCreated")
|
|
34
|
+
direct_members_count: PropertyRef = PropertyRef("directMembersCount")
|
|
35
|
+
|
|
36
|
+
# Metadata
|
|
37
|
+
etag: PropertyRef = PropertyRef("etag")
|
|
38
|
+
kind: PropertyRef = PropertyRef("kind")
|
|
39
|
+
|
|
40
|
+
# Tenant relationship
|
|
41
|
+
customer_id: PropertyRef = PropertyRef("CUSTOMER_ID", set_in_kwargs=True)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class GSuiteGroupToTenantRelProperties(CartographyRelProperties):
|
|
46
|
+
"""
|
|
47
|
+
Properties for GSuite group to tenant relationship
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class GSuiteGroupToTenantRel(CartographyRelSchema):
|
|
55
|
+
"""
|
|
56
|
+
Relationship from GSuite group to GSuite tenant
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
target_node_label: str = "GSuiteTenant"
|
|
60
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
61
|
+
{
|
|
62
|
+
"id": PropertyRef("CUSTOMER_ID", set_in_kwargs=True),
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
66
|
+
rel_label: str = "RESOURCE"
|
|
67
|
+
properties: GSuiteGroupToTenantRelProperties = GSuiteGroupToTenantRelProperties()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass(frozen=True)
|
|
71
|
+
class GSuiteGroupToMemberRelProperties(CartographyRelProperties):
|
|
72
|
+
"""
|
|
73
|
+
Properties for GSuite group to member relationship
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass(frozen=True)
|
|
80
|
+
class GSuiteGroupToMemberRel(CartographyRelSchema):
|
|
81
|
+
"""
|
|
82
|
+
Relationship from GSuite group to its members (users or groups)
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
target_node_label: str = "GSuiteUser" # or GSuiteGroup for subgroup relationships
|
|
86
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
87
|
+
{
|
|
88
|
+
"id": PropertyRef("member_ids", one_to_many=True),
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
92
|
+
rel_label: str = "MEMBER_GSUITE_GROUP"
|
|
93
|
+
properties: GSuiteGroupToMemberRelProperties = GSuiteGroupToMemberRelProperties()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass(frozen=True)
|
|
97
|
+
class GSuiteGroupToOwnerRelProperties(CartographyRelProperties):
|
|
98
|
+
"""
|
|
99
|
+
Properties for GSuite group to owner relationship
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@dataclass(frozen=True)
|
|
106
|
+
class GSuiteGroupToOwnerRel(CartographyRelSchema):
|
|
107
|
+
"""
|
|
108
|
+
Relationship from GSuite group to its owners (users)
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
target_node_label: str = "GSuiteUser"
|
|
112
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
113
|
+
{
|
|
114
|
+
"id": PropertyRef("owner_ids", one_to_many=True),
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
118
|
+
rel_label: str = "OWNER_GSUITE_GROUP"
|
|
119
|
+
properties: GSuiteGroupToOwnerRelProperties = GSuiteGroupToOwnerRelProperties()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass(frozen=True)
|
|
123
|
+
class GSuiteGroupSchema(CartographyNodeSchema):
|
|
124
|
+
"""
|
|
125
|
+
GSuite group node schema
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
label: str = "GSuiteGroup"
|
|
129
|
+
properties: GSuiteGroupNodeProperties = GSuiteGroupNodeProperties()
|
|
130
|
+
sub_resource_relationship: GSuiteGroupToTenantRel = GSuiteGroupToTenantRel()
|
|
131
|
+
extra_node_labels: ExtraNodeLabels = ExtraNodeLabels(["GCPPrincipal"])
|
|
132
|
+
other_relationships = OtherRelationships(
|
|
133
|
+
[
|
|
134
|
+
GSuiteGroupToMemberRel(),
|
|
135
|
+
GSuiteGroupToOwnerRel(),
|
|
136
|
+
]
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# MatchLinks for Group => Group relationships
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dataclass(frozen=True)
|
|
144
|
+
class GSuiteGroupToGroupMemberRelProperties(CartographyRelProperties):
|
|
145
|
+
"""
|
|
146
|
+
Properties for GSuite group to group member relationship (MatchLink)
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
150
|
+
_sub_resource_label: PropertyRef = PropertyRef(
|
|
151
|
+
"_sub_resource_label", set_in_kwargs=True
|
|
152
|
+
)
|
|
153
|
+
_sub_resource_id: PropertyRef = PropertyRef("_sub_resource_id", set_in_kwargs=True)
|
|
154
|
+
role: PropertyRef = PropertyRef("role")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@dataclass(frozen=True)
|
|
158
|
+
class GSuiteGroupToGroupMemberRel(CartographyRelSchema):
|
|
159
|
+
"""
|
|
160
|
+
MatchLink relationship from GSuite parent group to member group
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
target_node_label: str = "GSuiteGroup"
|
|
164
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
165
|
+
{
|
|
166
|
+
"id": PropertyRef("subgroup_id"),
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
source_node_label: str = "GSuiteGroup"
|
|
170
|
+
source_node_matcher: SourceNodeMatcher = make_source_node_matcher(
|
|
171
|
+
{
|
|
172
|
+
"id": PropertyRef("parent_group_id"),
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
176
|
+
rel_label: str = "MEMBER_GSUITE_GROUP"
|
|
177
|
+
properties: GSuiteGroupToGroupMemberRelProperties = (
|
|
178
|
+
GSuiteGroupToGroupMemberRelProperties()
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@dataclass(frozen=True)
|
|
183
|
+
class GSuiteGroupToGroupOwnerRelProperties(CartographyRelProperties):
|
|
184
|
+
"""
|
|
185
|
+
Properties for GSuite group to group owner relationship (MatchLink)
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
189
|
+
_sub_resource_label: PropertyRef = PropertyRef(
|
|
190
|
+
"_sub_resource_label", set_in_kwargs=True
|
|
191
|
+
)
|
|
192
|
+
_sub_resource_id: PropertyRef = PropertyRef("_sub_resource_id", set_in_kwargs=True)
|
|
193
|
+
role: PropertyRef = PropertyRef("role")
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@dataclass(frozen=True)
|
|
197
|
+
class GSuiteGroupToGroupOwnerRel(CartographyRelSchema):
|
|
198
|
+
"""
|
|
199
|
+
MatchLink relationship from GSuite parent group to owner group
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
target_node_label: str = "GSuiteGroup"
|
|
203
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
204
|
+
{
|
|
205
|
+
"id": PropertyRef("subgroup_id"),
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
source_node_label: str = "GSuiteGroup"
|
|
209
|
+
source_node_matcher: SourceNodeMatcher = make_source_node_matcher(
|
|
210
|
+
{
|
|
211
|
+
"id": PropertyRef("parent_group_id"),
|
|
212
|
+
}
|
|
213
|
+
)
|
|
214
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
215
|
+
rel_label: str = "OWNER_GSUITE_GROUP"
|
|
216
|
+
properties: GSuiteGroupToGroupOwnerRelProperties = (
|
|
217
|
+
GSuiteGroupToGroupOwnerRelProperties()
|
|
218
|
+
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from cartography.models.core.common import PropertyRef
|
|
4
|
+
from cartography.models.core.nodes import CartographyNodeProperties
|
|
5
|
+
from cartography.models.core.nodes import CartographyNodeSchema
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class GSuiteTenantNodeProperties(CartographyNodeProperties):
|
|
10
|
+
"""
|
|
11
|
+
GSuite tenant (domain/customer) node properties
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
id: PropertyRef = PropertyRef("id")
|
|
15
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
16
|
+
|
|
17
|
+
# Customer/domain identifier - use id as the primary identifier
|
|
18
|
+
customer_id: PropertyRef = PropertyRef("id")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class GSuiteTenantSchema(CartographyNodeSchema):
|
|
23
|
+
"""
|
|
24
|
+
GSuite tenant (domain/customer) schema
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
label: str = "GSuiteTenant"
|
|
28
|
+
properties: GSuiteTenantNodeProperties = GSuiteTenantNodeProperties()
|
|
29
|
+
sub_resource_relationship: None = None # Tenant is the root level
|
|
@@ -0,0 +1,107 @@
|
|
|
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.nodes import ExtraNodeLabels
|
|
7
|
+
from cartography.models.core.relationships import CartographyRelProperties
|
|
8
|
+
from cartography.models.core.relationships import CartographyRelSchema
|
|
9
|
+
from cartography.models.core.relationships import LinkDirection
|
|
10
|
+
from cartography.models.core.relationships import make_target_node_matcher
|
|
11
|
+
from cartography.models.core.relationships import TargetNodeMatcher
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class GSuiteUserNodeProperties(CartographyNodeProperties):
|
|
16
|
+
"""
|
|
17
|
+
GSuite user node properties
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
id: PropertyRef = PropertyRef("id")
|
|
21
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
22
|
+
|
|
23
|
+
# User identifiers and basic info
|
|
24
|
+
user_id: PropertyRef = PropertyRef("id") # Alias for id
|
|
25
|
+
email: PropertyRef = PropertyRef("primaryEmail", extra_index=True)
|
|
26
|
+
primary_email: PropertyRef = PropertyRef("primaryEmail")
|
|
27
|
+
name: PropertyRef = PropertyRef("name")
|
|
28
|
+
family_name: PropertyRef = PropertyRef("family_name")
|
|
29
|
+
given_name: PropertyRef = PropertyRef("given_name")
|
|
30
|
+
|
|
31
|
+
# Account settings
|
|
32
|
+
agreed_to_terms: PropertyRef = PropertyRef("agreedToTerms")
|
|
33
|
+
archived: PropertyRef = PropertyRef("archived")
|
|
34
|
+
change_password_at_next_login: PropertyRef = PropertyRef(
|
|
35
|
+
"changePasswordAtNextLogin"
|
|
36
|
+
)
|
|
37
|
+
suspended: PropertyRef = PropertyRef("suspended")
|
|
38
|
+
|
|
39
|
+
# Admin and security settings
|
|
40
|
+
is_admin: PropertyRef = PropertyRef("isAdmin")
|
|
41
|
+
is_delegated_admin: PropertyRef = PropertyRef("isDelegatedAdmin")
|
|
42
|
+
is_enforced_in_2_sv: PropertyRef = PropertyRef("isEnforcedIn2Sv")
|
|
43
|
+
is_enrolled_in_2_sv: PropertyRef = PropertyRef("isEnrolledIn2Sv")
|
|
44
|
+
ip_whitelisted: PropertyRef = PropertyRef("ipWhitelisted")
|
|
45
|
+
|
|
46
|
+
# Organization and profile
|
|
47
|
+
org_unit_path: PropertyRef = PropertyRef("orgUnitPath")
|
|
48
|
+
include_in_global_address_list: PropertyRef = PropertyRef(
|
|
49
|
+
"includeInGlobalAddressList"
|
|
50
|
+
)
|
|
51
|
+
is_mailbox_setup: PropertyRef = PropertyRef("isMailboxSetup")
|
|
52
|
+
|
|
53
|
+
# Timestamps and metadata
|
|
54
|
+
creation_time: PropertyRef = PropertyRef("creationTime")
|
|
55
|
+
last_login_time: PropertyRef = PropertyRef("lastLoginTime")
|
|
56
|
+
etag: PropertyRef = PropertyRef("etag")
|
|
57
|
+
kind: PropertyRef = PropertyRef("kind")
|
|
58
|
+
|
|
59
|
+
# Photo information
|
|
60
|
+
thumbnail_photo_etag: PropertyRef = PropertyRef("thumbnailPhotoEtag")
|
|
61
|
+
thumbnail_photo_url: PropertyRef = PropertyRef("thumbnailPhotoUrl")
|
|
62
|
+
|
|
63
|
+
# Tenant relationship
|
|
64
|
+
customer_id: PropertyRef = PropertyRef("CUSTOMER_ID", set_in_kwargs=True)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(frozen=True)
|
|
68
|
+
class GSuiteUserToTenantRelProperties(CartographyRelProperties):
|
|
69
|
+
"""
|
|
70
|
+
Properties for GSuite user to tenant relationship
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass(frozen=True)
|
|
77
|
+
class GSuiteUserToTenantRel(CartographyRelSchema):
|
|
78
|
+
"""
|
|
79
|
+
Relationship from GSuite user to GSuite tenant
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
target_node_label: str = "GSuiteTenant"
|
|
83
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
84
|
+
{
|
|
85
|
+
"id": PropertyRef("CUSTOMER_ID", set_in_kwargs=True),
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
89
|
+
rel_label: str = "RESOURCE"
|
|
90
|
+
properties: GSuiteUserToTenantRelProperties = GSuiteUserToTenantRelProperties()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass(frozen=True)
|
|
94
|
+
class GSuiteUserSchema(CartographyNodeSchema):
|
|
95
|
+
"""
|
|
96
|
+
GSuite user node schema
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
label: str = "GSuiteUser"
|
|
100
|
+
properties: GSuiteUserNodeProperties = GSuiteUserNodeProperties()
|
|
101
|
+
sub_resource_relationship: GSuiteUserToTenantRel = GSuiteUserToTenantRel()
|
|
102
|
+
extra_node_labels: ExtraNodeLabels = ExtraNodeLabels(
|
|
103
|
+
[
|
|
104
|
+
"GCPPrincipal",
|
|
105
|
+
"UserAccount",
|
|
106
|
+
] # UserAccount label is used for ontology mapping
|
|
107
|
+
)
|
|
@@ -14,9 +14,8 @@ from cartography.models.core.relationships import TargetNodeMatcher
|
|
|
14
14
|
class KandjiDeviceNodeProperties(CartographyNodeProperties):
|
|
15
15
|
id: PropertyRef = PropertyRef("id")
|
|
16
16
|
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
17
|
-
|
|
18
17
|
device_id: PropertyRef = PropertyRef("device_id")
|
|
19
|
-
device_name: PropertyRef = PropertyRef("device_name")
|
|
18
|
+
device_name: PropertyRef = PropertyRef("device_name", extra_index=True)
|
|
20
19
|
last_check_in: PropertyRef = PropertyRef("last_check_in")
|
|
21
20
|
model: PropertyRef = PropertyRef("model")
|
|
22
21
|
os_version: PropertyRef = PropertyRef("os_version")
|
|
@@ -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
|
|
@@ -47,5 +48,8 @@ class KeycloakUserToRealmRel(CartographyRelSchema):
|
|
|
47
48
|
@dataclass(frozen=True)
|
|
48
49
|
class KeycloakUserSchema(CartographyNodeSchema):
|
|
49
50
|
label: str = "KeycloakUser"
|
|
51
|
+
extra_node_labels: ExtraNodeLabels = ExtraNodeLabels(
|
|
52
|
+
["UserAccount"]
|
|
53
|
+
) # UserAccount label is used for ontology mapping
|
|
50
54
|
properties: KeycloakUserNodeProperties = KeycloakUserNodeProperties()
|
|
51
55
|
sub_resource_relationship: KeycloakUserToRealmRel = KeycloakUserToRealmRel()
|
|
@@ -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
|
|
@@ -73,6 +74,9 @@ class LastpassTenantToUserRel(CartographyRelSchema):
|
|
|
73
74
|
@dataclass(frozen=True)
|
|
74
75
|
class LastpassUserSchema(CartographyNodeSchema):
|
|
75
76
|
label: str = "LastpassUser"
|
|
77
|
+
extra_node_labels: ExtraNodeLabels = ExtraNodeLabels(
|
|
78
|
+
["UserAccount"]
|
|
79
|
+
) # UserAccount label is used for ontology mapping
|
|
76
80
|
properties: LastpassUserNodeProperties = LastpassUserNodeProperties()
|
|
77
81
|
other_relationships: OtherRelationships = OtherRelationships(
|
|
78
82
|
rels=[LastpassHumanToUserRel()],
|
|
File without changes
|
|
@@ -0,0 +1,125 @@
|
|
|
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.nodes import ExtraNodeLabels
|
|
7
|
+
from cartography.models.core.relationships import CartographyRelProperties
|
|
8
|
+
from cartography.models.core.relationships import CartographyRelSchema
|
|
9
|
+
from cartography.models.core.relationships import LinkDirection
|
|
10
|
+
from cartography.models.core.relationships import make_target_node_matcher
|
|
11
|
+
from cartography.models.core.relationships import OtherRelationships
|
|
12
|
+
from cartography.models.core.relationships import TargetNodeMatcher
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class DeviceNodeProperties(CartographyNodeProperties):
|
|
17
|
+
id: PropertyRef = PropertyRef("hostname")
|
|
18
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
19
|
+
hostname: PropertyRef = PropertyRef("hostname", extra_index=True)
|
|
20
|
+
os: PropertyRef = PropertyRef("os")
|
|
21
|
+
os_version: PropertyRef = PropertyRef("os_version")
|
|
22
|
+
model: PropertyRef = PropertyRef("model")
|
|
23
|
+
platform: PropertyRef = PropertyRef("platform")
|
|
24
|
+
serial_number: PropertyRef = PropertyRef("serial_number", extra_index=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class DeviceToNodeRelProperties(CartographyRelProperties):
|
|
29
|
+
lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# (:Device)-[:OBSERVED_AS]->(:DuoEndpoint)
|
|
33
|
+
class DeviceToDuoEndpointRel(CartographyRelSchema):
|
|
34
|
+
target_node_label: str = "DuoEndpoint"
|
|
35
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
36
|
+
{"device_name": PropertyRef("hostname")},
|
|
37
|
+
)
|
|
38
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
39
|
+
rel_label: str = "OBSERVED_AS"
|
|
40
|
+
properties: DeviceToNodeRelProperties = DeviceToNodeRelProperties()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# (:Device)-[:OBSERVED_AS]->(:DuoPhone)
|
|
44
|
+
class DeviceToDuoPhoneRel(CartographyRelSchema):
|
|
45
|
+
target_node_label: str = "DuoPhone"
|
|
46
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
47
|
+
{"name": PropertyRef("hostname")},
|
|
48
|
+
)
|
|
49
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
50
|
+
rel_label: str = "OBSERVED_AS"
|
|
51
|
+
properties: DeviceToNodeRelProperties = DeviceToNodeRelProperties()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# (:Device)-[:OBSERVED_AS]->(:KandjiDevice)
|
|
55
|
+
class DeviceToKandjiDeviceRel(CartographyRelSchema):
|
|
56
|
+
target_node_label: str = "KandjiDevice"
|
|
57
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
58
|
+
{"device_name": PropertyRef("hostname")},
|
|
59
|
+
)
|
|
60
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
61
|
+
rel_label: str = "OBSERVED_AS"
|
|
62
|
+
properties: DeviceToNodeRelProperties = DeviceToNodeRelProperties()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# (:Device)-[:OBSERVED_AS]->(:SnipeitAsset)
|
|
66
|
+
class DeviceToSnipeitAssetRel(CartographyRelSchema):
|
|
67
|
+
target_node_label: str = "SnipeitAsset"
|
|
68
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
69
|
+
{"name": PropertyRef("hostname")},
|
|
70
|
+
)
|
|
71
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
72
|
+
rel_label: str = "OBSERVED_AS"
|
|
73
|
+
properties: DeviceToNodeRelProperties = DeviceToNodeRelProperties()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# (:Device)-[:OBSERVED_AS]->(:TailscaleDevice)
|
|
77
|
+
class DeviceToTailscaleDeviceRel(CartographyRelSchema):
|
|
78
|
+
target_node_label: str = "TailscaleDevice"
|
|
79
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
80
|
+
{"hostname": PropertyRef("hostname")},
|
|
81
|
+
)
|
|
82
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
83
|
+
rel_label: str = "OBSERVED_AS"
|
|
84
|
+
properties: DeviceToNodeRelProperties = DeviceToNodeRelProperties()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# (:Device)-[:OBSERVED_AS]->(:CrowdstrikeHost)
|
|
88
|
+
class DeviceToCrowdstrikeHostRel(CartographyRelSchema):
|
|
89
|
+
target_node_label: str = "CrowdstrikeHost"
|
|
90
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
91
|
+
{"hostname": PropertyRef("hostname")},
|
|
92
|
+
)
|
|
93
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
94
|
+
rel_label: str = "OBSERVED_AS"
|
|
95
|
+
properties: DeviceToNodeRelProperties = DeviceToNodeRelProperties()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# (:Device)-[:OBSERVED_AS]->(:BigfixComputer)
|
|
99
|
+
class DeviceToBigfixComputerRel(CartographyRelSchema):
|
|
100
|
+
target_node_label: str = "BigfixComputer"
|
|
101
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
102
|
+
{"computername": PropertyRef("hostname")},
|
|
103
|
+
)
|
|
104
|
+
direction: LinkDirection = LinkDirection.OUTWARD
|
|
105
|
+
rel_label: str = "OBSERVED_AS"
|
|
106
|
+
properties: DeviceToNodeRelProperties = DeviceToNodeRelProperties()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass(frozen=True)
|
|
110
|
+
class DeviceSchema(CartographyNodeSchema):
|
|
111
|
+
label: str = "Device"
|
|
112
|
+
extra_node_labels: ExtraNodeLabels = ExtraNodeLabels(["Ontology"])
|
|
113
|
+
properties: DeviceNodeProperties = DeviceNodeProperties()
|
|
114
|
+
scoped_cleanup: bool = False
|
|
115
|
+
other_relationships: OtherRelationships = OtherRelationships(
|
|
116
|
+
rels=[
|
|
117
|
+
DeviceToDuoEndpointRel(),
|
|
118
|
+
DeviceToDuoPhoneRel(),
|
|
119
|
+
DeviceToKandjiDeviceRel(),
|
|
120
|
+
DeviceToSnipeitAssetRel(),
|
|
121
|
+
DeviceToTailscaleDeviceRel(),
|
|
122
|
+
DeviceToCrowdstrikeHostRel(),
|
|
123
|
+
DeviceToBigfixComputerRel(),
|
|
124
|
+
],
|
|
125
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from cartography.models.core.nodes import CartographyNodeSchema
|
|
2
|
+
from cartography.models.ontology.device import DeviceSchema
|
|
3
|
+
from cartography.models.ontology.mapping.data.devices import DEVICES_ONTOLOGY_MAPPING
|
|
4
|
+
from cartography.models.ontology.mapping.data.users import USERS_ONTOLOGY_MAPPING
|
|
5
|
+
from cartography.models.ontology.mapping.specs import OntologyMapping
|
|
6
|
+
from cartography.models.ontology.user import UserSchema
|
|
7
|
+
|
|
8
|
+
ONTOLOGY_MAPPING: dict[str, dict[str, OntologyMapping]] = {
|
|
9
|
+
"users": USERS_ONTOLOGY_MAPPING,
|
|
10
|
+
"devices": DEVICES_ONTOLOGY_MAPPING,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
ONTOLOGY_MODELS: dict[str, type[CartographyNodeSchema]] = {
|
|
14
|
+
"users": UserSchema,
|
|
15
|
+
"devices": DeviceSchema,
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Ontology mapping data files
|