cartography 0.102.0rc2__py3-none-any.whl → 0.103.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 (251) hide show
  1. cartography/__main__.py +1 -2
  2. cartography/_version.py +2 -2
  3. cartography/cli.py +302 -253
  4. cartography/client/core/tx.py +39 -18
  5. cartography/config.py +4 -0
  6. cartography/driftdetect/__main__.py +1 -2
  7. cartography/driftdetect/add_shortcut.py +10 -2
  8. cartography/driftdetect/cli.py +71 -75
  9. cartography/driftdetect/detect_deviations.py +7 -3
  10. cartography/driftdetect/get_states.py +20 -8
  11. cartography/driftdetect/model.py +5 -5
  12. cartography/driftdetect/serializers.py +8 -6
  13. cartography/driftdetect/storage.py +2 -2
  14. cartography/graph/cleanupbuilder.py +35 -15
  15. cartography/graph/job.py +46 -17
  16. cartography/graph/querybuilder.py +165 -80
  17. cartography/graph/statement.py +35 -26
  18. cartography/intel/analysis.py +4 -1
  19. cartography/intel/aws/__init__.py +114 -55
  20. cartography/intel/aws/apigateway.py +134 -63
  21. cartography/intel/aws/cloudtrail.py +127 -0
  22. cartography/intel/aws/config.py +56 -20
  23. cartography/intel/aws/dynamodb.py +108 -40
  24. cartography/intel/aws/ec2/__init__.py +2 -2
  25. cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
  26. cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
  27. cartography/intel/aws/ec2/images.py +49 -20
  28. cartography/intel/aws/ec2/instances.py +234 -136
  29. cartography/intel/aws/ec2/internet_gateways.py +40 -11
  30. cartography/intel/aws/ec2/key_pairs.py +44 -20
  31. cartography/intel/aws/ec2/launch_templates.py +101 -59
  32. cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
  33. cartography/intel/aws/ec2/load_balancers.py +82 -42
  34. cartography/intel/aws/ec2/network_acls.py +89 -65
  35. cartography/intel/aws/ec2/network_interfaces.py +146 -87
  36. cartography/intel/aws/ec2/reserved_instances.py +45 -16
  37. cartography/intel/aws/ec2/route_tables.py +138 -98
  38. cartography/intel/aws/ec2/security_groups.py +71 -21
  39. cartography/intel/aws/ec2/snapshots.py +61 -22
  40. cartography/intel/aws/ec2/subnets.py +54 -18
  41. cartography/intel/aws/ec2/tgw.py +100 -34
  42. cartography/intel/aws/ec2/util.py +1 -1
  43. cartography/intel/aws/ec2/volumes.py +69 -41
  44. cartography/intel/aws/ec2/vpc.py +37 -12
  45. cartography/intel/aws/ec2/vpc_peerings.py +83 -24
  46. cartography/intel/aws/ecr.py +88 -32
  47. cartography/intel/aws/ecs.py +83 -47
  48. cartography/intel/aws/eks.py +55 -29
  49. cartography/intel/aws/elasticache.py +42 -18
  50. cartography/intel/aws/elasticsearch.py +57 -20
  51. cartography/intel/aws/emr.py +61 -23
  52. cartography/intel/aws/iam.py +401 -145
  53. cartography/intel/aws/iam_instance_profiles.py +22 -22
  54. cartography/intel/aws/identitycenter.py +71 -37
  55. cartography/intel/aws/inspector.py +159 -89
  56. cartography/intel/aws/kms.py +92 -38
  57. cartography/intel/aws/lambda_function.py +103 -34
  58. cartography/intel/aws/organizations.py +30 -10
  59. cartography/intel/aws/permission_relationships.py +133 -51
  60. cartography/intel/aws/rds.py +249 -85
  61. cartography/intel/aws/redshift.py +107 -46
  62. cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
  63. cartography/intel/aws/resources.py +53 -46
  64. cartography/intel/aws/route53.py +108 -61
  65. cartography/intel/aws/s3.py +168 -83
  66. cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
  67. cartography/intel/aws/secretsmanager.py +24 -12
  68. cartography/intel/aws/securityhub.py +20 -9
  69. cartography/intel/aws/sns.py +166 -0
  70. cartography/intel/aws/sqs.py +60 -28
  71. cartography/intel/aws/ssm.py +70 -30
  72. cartography/intel/aws/util/arns.py +7 -7
  73. cartography/intel/aws/util/common.py +31 -4
  74. cartography/intel/azure/__init__.py +78 -19
  75. cartography/intel/azure/compute.py +101 -27
  76. cartography/intel/azure/cosmosdb.py +496 -170
  77. cartography/intel/azure/sql.py +296 -105
  78. cartography/intel/azure/storage.py +322 -113
  79. cartography/intel/azure/subscription.py +39 -23
  80. cartography/intel/azure/tenant.py +13 -4
  81. cartography/intel/azure/util/credentials.py +95 -55
  82. cartography/intel/bigfix/__init__.py +2 -2
  83. cartography/intel/bigfix/computers.py +93 -65
  84. cartography/intel/create_indexes.py +3 -2
  85. cartography/intel/crowdstrike/__init__.py +11 -9
  86. cartography/intel/crowdstrike/endpoints.py +5 -1
  87. cartography/intel/crowdstrike/spotlight.py +8 -3
  88. cartography/intel/cve/__init__.py +46 -13
  89. cartography/intel/cve/feed.py +48 -12
  90. cartography/intel/digitalocean/__init__.py +22 -13
  91. cartography/intel/digitalocean/compute.py +75 -108
  92. cartography/intel/digitalocean/management.py +44 -80
  93. cartography/intel/digitalocean/platform.py +48 -43
  94. cartography/intel/dns.py +36 -10
  95. cartography/intel/duo/__init__.py +21 -16
  96. cartography/intel/duo/api_host.py +14 -9
  97. cartography/intel/duo/endpoints.py +50 -45
  98. cartography/intel/duo/groups.py +18 -14
  99. cartography/intel/duo/phones.py +37 -34
  100. cartography/intel/duo/tokens.py +26 -23
  101. cartography/intel/duo/users.py +54 -50
  102. cartography/intel/duo/web_authn_credentials.py +30 -25
  103. cartography/intel/entra/__init__.py +25 -7
  104. cartography/intel/entra/ou.py +112 -0
  105. cartography/intel/entra/users.py +69 -63
  106. cartography/intel/gcp/__init__.py +185 -49
  107. cartography/intel/gcp/compute.py +418 -231
  108. cartography/intel/gcp/crm.py +96 -43
  109. cartography/intel/gcp/dns.py +60 -19
  110. cartography/intel/gcp/gke.py +72 -38
  111. cartography/intel/gcp/iam.py +61 -41
  112. cartography/intel/gcp/storage.py +84 -55
  113. cartography/intel/github/__init__.py +13 -11
  114. cartography/intel/github/repos.py +270 -137
  115. cartography/intel/github/teams.py +170 -88
  116. cartography/intel/github/users.py +70 -39
  117. cartography/intel/github/util.py +36 -34
  118. cartography/intel/gsuite/__init__.py +47 -26
  119. cartography/intel/gsuite/api.py +73 -30
  120. cartography/intel/jamf/__init__.py +19 -1
  121. cartography/intel/jamf/computers.py +30 -7
  122. cartography/intel/jamf/util.py +7 -2
  123. cartography/intel/kandji/__init__.py +6 -3
  124. cartography/intel/kandji/devices.py +14 -8
  125. cartography/intel/kubernetes/namespaces.py +7 -4
  126. cartography/intel/kubernetes/pods.py +7 -4
  127. cartography/intel/kubernetes/services.py +8 -4
  128. cartography/intel/lastpass/__init__.py +2 -2
  129. cartography/intel/lastpass/users.py +23 -12
  130. cartography/intel/oci/__init__.py +44 -11
  131. cartography/intel/oci/iam.py +134 -38
  132. cartography/intel/oci/organizations.py +13 -6
  133. cartography/intel/oci/utils.py +43 -20
  134. cartography/intel/okta/__init__.py +66 -15
  135. cartography/intel/okta/applications.py +42 -20
  136. cartography/intel/okta/awssaml.py +93 -33
  137. cartography/intel/okta/factors.py +16 -4
  138. cartography/intel/okta/groups.py +56 -29
  139. cartography/intel/okta/organization.py +5 -1
  140. cartography/intel/okta/origins.py +6 -2
  141. cartography/intel/okta/roles.py +15 -5
  142. cartography/intel/okta/users.py +20 -8
  143. cartography/intel/okta/utils.py +6 -4
  144. cartography/intel/pagerduty/__init__.py +8 -7
  145. cartography/intel/pagerduty/escalation_policies.py +18 -6
  146. cartography/intel/pagerduty/schedules.py +12 -4
  147. cartography/intel/pagerduty/services.py +11 -4
  148. cartography/intel/pagerduty/teams.py +8 -3
  149. cartography/intel/pagerduty/users.py +3 -1
  150. cartography/intel/pagerduty/vendors.py +3 -1
  151. cartography/intel/semgrep/__init__.py +24 -6
  152. cartography/intel/semgrep/dependencies.py +50 -28
  153. cartography/intel/semgrep/deployment.py +3 -1
  154. cartography/intel/semgrep/findings.py +42 -18
  155. cartography/intel/snipeit/__init__.py +17 -3
  156. cartography/intel/snipeit/asset.py +12 -6
  157. cartography/intel/snipeit/user.py +8 -5
  158. cartography/intel/snipeit/util.py +9 -4
  159. cartography/models/aws/apigateway.py +21 -17
  160. cartography/models/aws/apigatewaycertificate.py +28 -22
  161. cartography/models/aws/apigatewayresource.py +28 -20
  162. cartography/models/aws/apigatewaystage.py +33 -25
  163. cartography/models/aws/cloudtrail/__init__.py +0 -0
  164. cartography/models/aws/cloudtrail/trail.py +61 -0
  165. cartography/models/aws/dynamodb/gsi.py +30 -22
  166. cartography/models/aws/dynamodb/tables.py +25 -17
  167. cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
  168. cartography/models/aws/ec2/images.py +36 -34
  169. cartography/models/aws/ec2/instances.py +51 -45
  170. cartography/models/aws/ec2/keypair.py +21 -16
  171. cartography/models/aws/ec2/keypair_instance.py +28 -21
  172. cartography/models/aws/ec2/launch_configurations.py +30 -26
  173. cartography/models/aws/ec2/launch_template_versions.py +48 -38
  174. cartography/models/aws/ec2/launch_templates.py +21 -17
  175. cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
  176. cartography/models/aws/ec2/load_balancers.py +47 -37
  177. cartography/models/aws/ec2/network_acl_rules.py +38 -30
  178. cartography/models/aws/ec2/network_acls.py +38 -29
  179. cartography/models/aws/ec2/networkinterface_instance.py +52 -39
  180. cartography/models/aws/ec2/networkinterfaces.py +53 -37
  181. cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
  182. cartography/models/aws/ec2/reservations.py +18 -14
  183. cartography/models/aws/ec2/route_table_associations.py +44 -34
  184. cartography/models/aws/ec2/route_tables.py +50 -43
  185. cartography/models/aws/ec2/routes.py +45 -37
  186. cartography/models/aws/ec2/securitygroup_instance.py +29 -20
  187. cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
  188. cartography/models/aws/ec2/subnet_instance.py +24 -19
  189. cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
  190. cartography/models/aws/ec2/volumes.py +47 -40
  191. cartography/models/aws/eks/clusters.py +23 -21
  192. cartography/models/aws/emr.py +32 -30
  193. cartography/models/aws/iam/instanceprofile.py +33 -24
  194. cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
  195. cartography/models/aws/identitycenter/awspermissionset.py +37 -29
  196. cartography/models/aws/identitycenter/awsssouser.py +23 -21
  197. cartography/models/aws/inspector/findings.py +77 -65
  198. cartography/models/aws/inspector/packages.py +35 -29
  199. cartography/models/aws/s3/__init__.py +0 -0
  200. cartography/models/aws/s3/account_public_access_block.py +51 -0
  201. cartography/models/aws/sns/__init__.py +0 -0
  202. cartography/models/aws/sns/topic.py +50 -0
  203. cartography/models/aws/ssm/instance_information.py +51 -39
  204. cartography/models/aws/ssm/instance_patch.py +32 -26
  205. cartography/models/bigfix/bigfix_computer.py +42 -38
  206. cartography/models/bigfix/bigfix_root.py +3 -3
  207. cartography/models/core/common.py +12 -10
  208. cartography/models/core/nodes.py +5 -2
  209. cartography/models/core/relationships.py +14 -6
  210. cartography/models/crowdstrike/hosts.py +37 -35
  211. cartography/models/cve/cve.py +34 -32
  212. cartography/models/cve/cve_feed.py +6 -6
  213. cartography/models/digitalocean/__init__.py +0 -0
  214. cartography/models/digitalocean/account.py +21 -0
  215. cartography/models/digitalocean/droplet.py +56 -0
  216. cartography/models/digitalocean/project.py +48 -0
  217. cartography/models/duo/api_host.py +3 -3
  218. cartography/models/duo/endpoint.py +43 -41
  219. cartography/models/duo/group.py +14 -14
  220. cartography/models/duo/phone.py +27 -27
  221. cartography/models/duo/token.py +16 -16
  222. cartography/models/duo/user.py +46 -44
  223. cartography/models/duo/web_authn_credential.py +27 -19
  224. cartography/models/entra/ou.py +48 -0
  225. cartography/models/entra/tenant.py +24 -18
  226. cartography/models/entra/user.py +64 -48
  227. cartography/models/gcp/iam.py +23 -23
  228. cartography/models/github/orgs.py +5 -4
  229. cartography/models/github/teams.py +37 -31
  230. cartography/models/github/users.py +34 -23
  231. cartography/models/kandji/device.py +22 -16
  232. cartography/models/kandji/tenant.py +6 -4
  233. cartography/models/lastpass/tenant.py +3 -3
  234. cartography/models/lastpass/user.py +32 -28
  235. cartography/models/semgrep/dependencies.py +36 -24
  236. cartography/models/semgrep/deployment.py +5 -5
  237. cartography/models/semgrep/findings.py +58 -42
  238. cartography/models/semgrep/locations.py +27 -21
  239. cartography/models/snipeit/asset.py +30 -21
  240. cartography/models/snipeit/tenant.py +6 -4
  241. cartography/models/snipeit/user.py +19 -12
  242. cartography/stats.py +3 -3
  243. cartography/sync.py +107 -31
  244. cartography/util.py +84 -62
  245. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/METADATA +3 -14
  246. cartography-0.103.0rc1.dist-info/RECORD +396 -0
  247. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/WHEEL +1 -1
  248. cartography-0.102.0rc2.dist-info/RECORD +0 -381
  249. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/entry_points.txt +0 -0
  250. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/licenses/LICENSE +0 -0
  251. {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/top_level.txt +0 -0
@@ -20,7 +20,9 @@ DESCRIBE_SLEEP = 1
20
20
 
21
21
 
22
22
  @timeit
23
- def get_gcp_service_accounts(iam_client: Resource, project_id: str) -> List[Dict[str, Any]]:
23
+ def get_gcp_service_accounts(
24
+ iam_client: Resource, project_id: str
25
+ ) -> List[Dict[str, Any]]:
24
26
  """
25
27
  Retrieve a list of GCP service accounts for a given project.
26
28
 
@@ -30,19 +32,29 @@ def get_gcp_service_accounts(iam_client: Resource, project_id: str) -> List[Dict
30
32
  """
31
33
  service_accounts: List[Dict[str, Any]] = []
32
34
  try:
33
- request = iam_client.projects().serviceAccounts().list(
34
- name=f'projects/{project_id}',
35
+ request = (
36
+ iam_client.projects()
37
+ .serviceAccounts()
38
+ .list(
39
+ name=f"projects/{project_id}",
40
+ )
35
41
  )
36
42
  while request is not None:
37
43
  response = request.execute()
38
- if 'accounts' in response:
39
- service_accounts.extend(response['accounts'])
40
- request = iam_client.projects().serviceAccounts().list_next(
41
- previous_request=request,
42
- previous_response=response,
44
+ if "accounts" in response:
45
+ service_accounts.extend(response["accounts"])
46
+ request = (
47
+ iam_client.projects()
48
+ .serviceAccounts()
49
+ .list_next(
50
+ previous_request=request,
51
+ previous_response=response,
52
+ )
43
53
  )
44
54
  except Exception as e:
45
- logger.warning(f"Error retrieving service accounts for project {project_id}: {e}")
55
+ logger.warning(
56
+ f"Error retrieving service accounts for project {project_id}: {e}"
57
+ )
46
58
  return service_accounts
47
59
 
48
60
 
@@ -59,17 +71,17 @@ def get_gcp_roles(iam_client: Resource, project_id: str) -> List[Dict]:
59
71
  roles = []
60
72
 
61
73
  # Get custom roles
62
- custom_req = iam_client.projects().roles().list(parent=f'projects/{project_id}')
74
+ custom_req = iam_client.projects().roles().list(parent=f"projects/{project_id}")
63
75
  while custom_req is not None:
64
76
  resp = custom_req.execute()
65
- roles.extend(resp.get('roles', []))
77
+ roles.extend(resp.get("roles", []))
66
78
  custom_req = iam_client.projects().roles().list_next(custom_req, resp)
67
79
 
68
80
  # Get predefined roles
69
- predefined_req = iam_client.roles().list(view='FULL')
81
+ predefined_req = iam_client.roles().list(view="FULL")
70
82
  while predefined_req is not None:
71
83
  resp = predefined_req.execute()
72
- roles.extend(resp.get('roles', []))
84
+ roles.extend(resp.get("roles", []))
73
85
  predefined_req = iam_client.roles().list_next(predefined_req, resp)
74
86
 
75
87
  return roles
@@ -93,17 +105,19 @@ def load_gcp_service_accounts(
93
105
  :param project_id: The GCP Project ID associated with the service accounts.
94
106
  :param gcp_update_tag: The timestamp of the current sync run.
95
107
  """
96
- logger.debug(f"Loading {len(service_accounts)} service accounts for project {project_id}")
108
+ logger.debug(
109
+ f"Loading {len(service_accounts)} service accounts for project {project_id}"
110
+ )
97
111
  transformed_service_accounts = []
98
112
  for sa in service_accounts:
99
113
  transformed_sa = {
100
- 'id': sa['uniqueId'],
101
- 'email': sa.get('email'),
102
- 'displayName': sa.get('displayName'),
103
- 'oauth2ClientId': sa.get('oauth2ClientId'),
104
- 'uniqueId': sa.get('uniqueId'),
105
- 'disabled': sa.get('disabled', False),
106
- 'projectId': project_id,
114
+ "id": sa["uniqueId"],
115
+ "email": sa.get("email"),
116
+ "displayName": sa.get("displayName"),
117
+ "oauth2ClientId": sa.get("oauth2ClientId"),
118
+ "uniqueId": sa.get("uniqueId"),
119
+ "disabled": sa.get("disabled", False),
120
+ "projectId": project_id,
107
121
  }
108
122
  transformed_service_accounts.append(transformed_sa)
109
123
 
@@ -113,7 +127,7 @@ def load_gcp_service_accounts(
113
127
  transformed_service_accounts,
114
128
  lastupdated=gcp_update_tag,
115
129
  projectId=project_id,
116
- additional_labels=['GCPPrincipal'],
130
+ additional_labels=["GCPPrincipal"],
117
131
  )
118
132
 
119
133
 
@@ -135,25 +149,25 @@ def load_gcp_roles(
135
149
  logger.debug(f"Loading {len(roles)} roles for project {project_id}")
136
150
  transformed_roles = []
137
151
  for role in roles:
138
- role_name = role['name']
139
- if role_name.startswith('roles/'):
140
- if role_name in ['roles/owner', 'roles/editor', 'roles/viewer']:
141
- role_type = 'BASIC'
152
+ role_name = role["name"]
153
+ if role_name.startswith("roles/"):
154
+ if role_name in ["roles/owner", "roles/editor", "roles/viewer"]:
155
+ role_type = "BASIC"
142
156
  else:
143
- role_type = 'PREDEFINED'
157
+ role_type = "PREDEFINED"
144
158
  else:
145
- role_type = 'CUSTOM'
159
+ role_type = "CUSTOM"
146
160
 
147
161
  transformed_role = {
148
- 'id': role_name,
149
- 'name': role_name,
150
- 'title': role.get('title'),
151
- 'description': role.get('description'),
152
- 'deleted': role.get('deleted', False),
153
- 'etag': role.get('etag'),
154
- 'includedPermissions': role.get('includedPermissions', []),
155
- 'roleType': role_type,
156
- 'projectId': project_id,
162
+ "id": role_name,
163
+ "name": role_name,
164
+ "title": role.get("title"),
165
+ "description": role.get("description"),
166
+ "deleted": role.get("deleted", False),
167
+ "etag": role.get("etag"),
168
+ "includedPermissions": role.get("includedPermissions", []),
169
+ "roleType": role_type,
170
+ "projectId": project_id,
157
171
  }
158
172
  transformed_roles.append(transformed_role)
159
173
 
@@ -167,7 +181,9 @@ def load_gcp_roles(
167
181
 
168
182
 
169
183
  @timeit
170
- def cleanup(neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]) -> None:
184
+ def cleanup(
185
+ neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]
186
+ ) -> None:
171
187
  """
172
188
  Run cleanup jobs for GCP IAM data in Neo4j.
173
189
 
@@ -177,7 +193,7 @@ def cleanup(neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any])
177
193
  logger.debug("Running GCP IAM cleanup job")
178
194
  job_params = {
179
195
  **common_job_parameters,
180
- 'projectId': common_job_parameters.get('PROJECT_ID'),
196
+ "projectId": common_job_parameters.get("PROJECT_ID"),
181
197
  }
182
198
 
183
199
  cleanup_jobs = [
@@ -210,8 +226,12 @@ def sync(
210
226
 
211
227
  # Get and load service accounts
212
228
  service_accounts = get_gcp_service_accounts(iam_client, project_id)
213
- logger.info(f"Found {len(service_accounts)} service accounts in project {project_id}")
214
- load_gcp_service_accounts(neo4j_session, service_accounts, project_id, gcp_update_tag)
229
+ logger.info(
230
+ f"Found {len(service_accounts)} service accounts in project {project_id}"
231
+ )
232
+ load_gcp_service_accounts(
233
+ neo4j_session, service_accounts, project_id, gcp_update_tag
234
+ )
215
235
 
216
236
  # Get and load roles
217
237
  roles = get_gcp_roles(iam_client, project_id)
@@ -33,7 +33,7 @@ def get_gcp_buckets(storage: Resource, project_id: str) -> Dict:
33
33
  return res
34
34
  except HttpError as e:
35
35
  reason = compute._get_error_reason(e)
36
- if reason == 'invalid':
36
+ if reason == "invalid":
37
37
  logger.warning(
38
38
  (
39
39
  "The project %s is invalid - returned a 400 invalid error."
@@ -43,12 +43,15 @@ def get_gcp_buckets(storage: Resource, project_id: str) -> Dict:
43
43
  e,
44
44
  )
45
45
  return {}
46
- elif reason == 'forbidden':
46
+ elif reason == "forbidden":
47
47
  logger.warning(
48
48
  (
49
49
  "You do not have storage.bucket.list access to the project %s. "
50
50
  "Full details: %s"
51
- ), project_id, e, )
51
+ ),
52
+ project_id,
53
+ e,
54
+ )
52
55
  return {}
53
56
  else:
54
57
  raise
@@ -56,7 +59,7 @@ def get_gcp_buckets(storage: Resource, project_id: str) -> Dict:
56
59
 
57
60
  @timeit
58
61
  def transform_gcp_buckets(bucket_res: Dict) -> List[Dict]:
59
- '''
62
+ """
60
63
  Transform the GCP Storage Bucket response object for Neo4j ingestion
61
64
 
62
65
  :type bucket_res: The GCP storage resource object (https://cloud.google.com/storage/docs/json_api/v1/buckets)
@@ -64,40 +67,52 @@ def transform_gcp_buckets(bucket_res: Dict) -> List[Dict]:
64
67
 
65
68
  :rtype: list
66
69
  :return: List of buckets ready for ingestion to Neo4j
67
- '''
70
+ """
68
71
 
69
72
  bucket_list = []
70
- for b in bucket_res.get('items', []):
73
+ for b in bucket_res.get("items", []):
71
74
  bucket = {}
72
- bucket['etag'] = b.get('etag')
73
- bucket['iam_config_bucket_policy_only'] = \
74
- b.get('iamConfiguration', {}).get('bucketPolicyOnly', {}).get('enabled', None)
75
- bucket['id'] = b['id']
76
- bucket['labels'] = [(key, val) for (key, val) in b.get('labels', {}).items()]
77
- bucket['owner_entity'] = b.get('owner', {}).get('entity')
78
- bucket['owner_entity_id'] = b.get('owner', {}).get('entityId')
79
- bucket['kind'] = b.get('kind')
80
- bucket['location'] = b.get('location')
81
- bucket['location_type'] = b.get('locationType')
82
- bucket['meta_generation'] = b.get('metageneration', None)
83
- bucket['project_number'] = b['projectNumber']
84
- bucket['self_link'] = b.get('selfLink')
85
- bucket['storage_class'] = b.get('storageClass')
86
- bucket['time_created'] = b.get('timeCreated')
87
- bucket['updated'] = b.get('updated')
88
- bucket['versioning_enabled'] = b.get('versioning', {}).get('enabled', None)
89
- bucket['default_event_based_hold'] = b.get('defaultEventBasedHold', None)
90
- bucket['retention_period'] = b.get('retentionPolicy', {}).get('retentionPeriod', None)
91
- bucket['default_kms_key_name'] = b.get('encryption', {}).get('defaultKmsKeyName')
92
- bucket['log_bucket'] = b.get('logging', {}).get('logBucket')
93
- bucket['requester_pays'] = b.get('billing', {}).get('requesterPays', None)
75
+ bucket["etag"] = b.get("etag")
76
+ bucket["iam_config_bucket_policy_only"] = (
77
+ b.get("iamConfiguration", {})
78
+ .get("bucketPolicyOnly", {})
79
+ .get("enabled", None)
80
+ )
81
+ bucket["id"] = b["id"]
82
+ bucket["labels"] = [(key, val) for (key, val) in b.get("labels", {}).items()]
83
+ bucket["owner_entity"] = b.get("owner", {}).get("entity")
84
+ bucket["owner_entity_id"] = b.get("owner", {}).get("entityId")
85
+ bucket["kind"] = b.get("kind")
86
+ bucket["location"] = b.get("location")
87
+ bucket["location_type"] = b.get("locationType")
88
+ bucket["meta_generation"] = b.get("metageneration", None)
89
+ bucket["project_number"] = b["projectNumber"]
90
+ bucket["self_link"] = b.get("selfLink")
91
+ bucket["storage_class"] = b.get("storageClass")
92
+ bucket["time_created"] = b.get("timeCreated")
93
+ bucket["updated"] = b.get("updated")
94
+ bucket["versioning_enabled"] = b.get("versioning", {}).get("enabled", None)
95
+ bucket["default_event_based_hold"] = b.get("defaultEventBasedHold", None)
96
+ bucket["retention_period"] = b.get("retentionPolicy", {}).get(
97
+ "retentionPeriod",
98
+ None,
99
+ )
100
+ bucket["default_kms_key_name"] = b.get("encryption", {}).get(
101
+ "defaultKmsKeyName",
102
+ )
103
+ bucket["log_bucket"] = b.get("logging", {}).get("logBucket")
104
+ bucket["requester_pays"] = b.get("billing", {}).get("requesterPays", None)
94
105
  bucket_list.append(bucket)
95
106
  return bucket_list
96
107
 
97
108
 
98
109
  @timeit
99
- def load_gcp_buckets(neo4j_session: neo4j.Session, buckets: List[Dict], gcp_update_tag: int) -> None:
100
- '''
110
+ def load_gcp_buckets(
111
+ neo4j_session: neo4j.Session,
112
+ buckets: List[Dict],
113
+ gcp_update_tag: int,
114
+ ) -> None:
115
+ """
101
116
  Ingest GCP Storage Buckets to Neo4j
102
117
 
103
118
  :type neo4j_session: Neo4j session object
@@ -111,7 +126,7 @@ def load_gcp_buckets(neo4j_session: neo4j.Session, buckets: List[Dict], gcp_upda
111
126
 
112
127
  :rtype: NoneType
113
128
  :return: Nothing
114
- '''
129
+ """
115
130
 
116
131
  query = """
117
132
  MERGE(p:GCPProject{projectnumber:$ProjectNumber})
@@ -146,30 +161,34 @@ def load_gcp_buckets(neo4j_session: neo4j.Session, buckets: List[Dict], gcp_upda
146
161
  for bucket in buckets:
147
162
  neo4j_session.run(
148
163
  query,
149
- ProjectNumber=bucket['project_number'],
150
- BucketId=bucket['id'],
151
- SelfLink=bucket['self_link'],
152
- Kind=bucket['kind'],
153
- Location=bucket['location'],
154
- LocationType=bucket['location_type'],
155
- MetaGeneration=bucket['meta_generation'],
156
- StorageClass=bucket['storage_class'],
157
- TimeCreated=bucket['time_created'],
158
- RetentionPeriod=bucket['retention_period'],
159
- IamConfigBucketPolicyOnly=bucket['iam_config_bucket_policy_only'],
160
- OwnerEntity=bucket['owner_entity'],
161
- OwnerEntityId=bucket['owner_entity_id'],
162
- VersioningEnabled=bucket['versioning_enabled'],
163
- LogBucket=bucket['log_bucket'],
164
- RequesterPays=bucket['requester_pays'],
165
- DefaultKmsKeyName=bucket['default_kms_key_name'],
164
+ ProjectNumber=bucket["project_number"],
165
+ BucketId=bucket["id"],
166
+ SelfLink=bucket["self_link"],
167
+ Kind=bucket["kind"],
168
+ Location=bucket["location"],
169
+ LocationType=bucket["location_type"],
170
+ MetaGeneration=bucket["meta_generation"],
171
+ StorageClass=bucket["storage_class"],
172
+ TimeCreated=bucket["time_created"],
173
+ RetentionPeriod=bucket["retention_period"],
174
+ IamConfigBucketPolicyOnly=bucket["iam_config_bucket_policy_only"],
175
+ OwnerEntity=bucket["owner_entity"],
176
+ OwnerEntityId=bucket["owner_entity_id"],
177
+ VersioningEnabled=bucket["versioning_enabled"],
178
+ LogBucket=bucket["log_bucket"],
179
+ RequesterPays=bucket["requester_pays"],
180
+ DefaultKmsKeyName=bucket["default_kms_key_name"],
166
181
  gcp_update_tag=gcp_update_tag,
167
182
  )
168
183
  _attach_gcp_bucket_labels(neo4j_session, bucket, gcp_update_tag)
169
184
 
170
185
 
171
186
  @timeit
172
- def _attach_gcp_bucket_labels(neo4j_session: neo4j.Session, bucket: Resource, gcp_update_tag: int) -> None:
187
+ def _attach_gcp_bucket_labels(
188
+ neo4j_session: neo4j.Session,
189
+ bucket: Resource,
190
+ gcp_update_tag: int,
191
+ ) -> None:
173
192
  """
174
193
  Attach GCP bucket labels to the bucket.
175
194
  :param neo4j_session: The neo4j session
@@ -189,19 +208,22 @@ def _attach_gcp_bucket_labels(neo4j_session: neo4j.Session, bucket: Resource, gc
189
208
  ON CREATE SET r.firstseen = timestamp()
190
209
  SET r.lastupdated = $gcp_update_tag
191
210
  """
192
- for (key, val) in bucket.get('labels', []):
211
+ for key, val in bucket.get("labels", []):
193
212
  neo4j_session.run(
194
213
  query,
195
214
  BucketLabelId=f"GCPBucket_{key}",
196
215
  Key=key,
197
216
  Value=val,
198
- BucketId=bucket['id'],
217
+ BucketId=bucket["id"],
199
218
  gcp_update_tag=gcp_update_tag,
200
219
  )
201
220
 
202
221
 
203
222
  @timeit
204
- def cleanup_gcp_buckets(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
223
+ def cleanup_gcp_buckets(
224
+ neo4j_session: neo4j.Session,
225
+ common_job_parameters: Dict,
226
+ ) -> None:
205
227
  """
206
228
  Delete out-of-date GCP Storage Bucket nodes and relationships
207
229
 
@@ -214,12 +236,19 @@ def cleanup_gcp_buckets(neo4j_session: neo4j.Session, common_job_parameters: Dic
214
236
  :rtype: NoneType
215
237
  :return: Nothing
216
238
  """
217
- run_cleanup_job('gcp_storage_bucket_cleanup.json', neo4j_session, common_job_parameters)
239
+ run_cleanup_job(
240
+ "gcp_storage_bucket_cleanup.json",
241
+ neo4j_session,
242
+ common_job_parameters,
243
+ )
218
244
 
219
245
 
220
246
  @timeit
221
247
  def sync_gcp_buckets(
222
- neo4j_session: neo4j.Session, storage: Resource, project_id: str, gcp_update_tag: int,
248
+ neo4j_session: neo4j.Session,
249
+ storage: Resource,
250
+ project_id: str,
251
+ gcp_update_tag: int,
223
252
  common_job_parameters: Dict,
224
253
  ) -> None:
225
254
  """
@@ -247,5 +276,5 @@ def sync_gcp_buckets(
247
276
  storage_res = get_gcp_buckets(storage, project_id)
248
277
  bucket_list = transform_gcp_buckets(storage_res)
249
278
  load_gcp_buckets(neo4j_session, bucket_list, gcp_update_tag)
250
- # TODO scope the cleanup to the current project - https://github.com/lyft/cartography/issues/381
279
+ # TODO scope the cleanup to the current project - https://github.com/cartography-cncf/cartography/issues/381
251
280
  cleanup_gcp_buckets(neo4j_session, common_job_parameters)
@@ -23,7 +23,9 @@ def start_github_ingestion(neo4j_session: neo4j.Session, config: Config) -> None
23
23
  :return: None
24
24
  """
25
25
  if not config.github_config:
26
- logger.info('GitHub import is not configured - skipping this module. See docs to configure.')
26
+ logger.info(
27
+ "GitHub import is not configured - skipping this module. See docs to configure.",
28
+ )
27
29
  return
28
30
 
29
31
  auth_tokens = json.loads(base64.b64decode(config.github_config).decode())
@@ -31,28 +33,28 @@ def start_github_ingestion(neo4j_session: neo4j.Session, config: Config) -> None
31
33
  "UPDATE_TAG": config.update_tag,
32
34
  }
33
35
  # run sync for the provided github tokens
34
- for auth_data in auth_tokens['organization']:
36
+ for auth_data in auth_tokens["organization"]:
35
37
  try:
36
38
  cartography.intel.github.users.sync(
37
39
  neo4j_session,
38
40
  common_job_parameters,
39
- auth_data['token'],
40
- auth_data['url'],
41
- auth_data['name'],
41
+ auth_data["token"],
42
+ auth_data["url"],
43
+ auth_data["name"],
42
44
  )
43
45
  cartography.intel.github.repos.sync(
44
46
  neo4j_session,
45
47
  common_job_parameters,
46
- auth_data['token'],
47
- auth_data['url'],
48
- auth_data['name'],
48
+ auth_data["token"],
49
+ auth_data["url"],
50
+ auth_data["name"],
49
51
  )
50
52
  cartography.intel.github.teams.sync_github_teams(
51
53
  neo4j_session,
52
54
  common_job_parameters,
53
- auth_data['token'],
54
- auth_data['url'],
55
- auth_data['name'],
55
+ auth_data["token"],
56
+ auth_data["url"],
57
+ auth_data["name"],
56
58
  )
57
59
  except exceptions.RequestException as e:
58
60
  logger.error("Could not complete request to the GitHub API: %s", e)