cartography 0.102.0rc1__py3-none-any.whl → 0.103.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 (297) hide show
  1. cartography/__main__.py +1 -2
  2. cartography/_version.py +2 -2
  3. cartography/cli.py +376 -249
  4. cartography/client/core/tx.py +39 -18
  5. cartography/config.py +28 -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/cloudwatch.py +93 -0
  23. cartography/intel/aws/config.py +56 -20
  24. cartography/intel/aws/dynamodb.py +108 -40
  25. cartography/intel/aws/ec2/__init__.py +2 -2
  26. cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
  27. cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
  28. cartography/intel/aws/ec2/images.py +49 -20
  29. cartography/intel/aws/ec2/instances.py +234 -136
  30. cartography/intel/aws/ec2/internet_gateways.py +40 -11
  31. cartography/intel/aws/ec2/key_pairs.py +44 -20
  32. cartography/intel/aws/ec2/launch_templates.py +101 -59
  33. cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
  34. cartography/intel/aws/ec2/load_balancers.py +82 -42
  35. cartography/intel/aws/ec2/network_acls.py +89 -65
  36. cartography/intel/aws/ec2/network_interfaces.py +146 -87
  37. cartography/intel/aws/ec2/reserved_instances.py +45 -16
  38. cartography/intel/aws/ec2/route_tables.py +327 -0
  39. cartography/intel/aws/ec2/security_groups.py +71 -21
  40. cartography/intel/aws/ec2/snapshots.py +61 -22
  41. cartography/intel/aws/ec2/subnets.py +54 -18
  42. cartography/intel/aws/ec2/tgw.py +100 -34
  43. cartography/intel/aws/ec2/util.py +1 -1
  44. cartography/intel/aws/ec2/volumes.py +69 -41
  45. cartography/intel/aws/ec2/vpc.py +37 -12
  46. cartography/intel/aws/ec2/vpc_peerings.py +83 -24
  47. cartography/intel/aws/ecr.py +88 -32
  48. cartography/intel/aws/ecs.py +83 -47
  49. cartography/intel/aws/efs.py +93 -0
  50. cartography/intel/aws/eks.py +55 -29
  51. cartography/intel/aws/elasticache.py +42 -18
  52. cartography/intel/aws/elasticsearch.py +57 -20
  53. cartography/intel/aws/emr.py +61 -23
  54. cartography/intel/aws/iam.py +401 -145
  55. cartography/intel/aws/iam_instance_profiles.py +22 -22
  56. cartography/intel/aws/identitycenter.py +71 -37
  57. cartography/intel/aws/inspector.py +159 -89
  58. cartography/intel/aws/kms.py +92 -38
  59. cartography/intel/aws/lambda_function.py +103 -34
  60. cartography/intel/aws/organizations.py +30 -10
  61. cartography/intel/aws/permission_relationships.py +133 -51
  62. cartography/intel/aws/rds.py +249 -85
  63. cartography/intel/aws/redshift.py +107 -46
  64. cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
  65. cartography/intel/aws/resources.py +57 -44
  66. cartography/intel/aws/route53.py +108 -61
  67. cartography/intel/aws/s3.py +168 -83
  68. cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
  69. cartography/intel/aws/secretsmanager.py +24 -12
  70. cartography/intel/aws/securityhub.py +20 -9
  71. cartography/intel/aws/sns.py +166 -0
  72. cartography/intel/aws/sqs.py +60 -28
  73. cartography/intel/aws/ssm.py +70 -30
  74. cartography/intel/aws/util/arns.py +7 -7
  75. cartography/intel/aws/util/common.py +31 -4
  76. cartography/intel/azure/__init__.py +78 -19
  77. cartography/intel/azure/compute.py +101 -27
  78. cartography/intel/azure/cosmosdb.py +496 -170
  79. cartography/intel/azure/sql.py +296 -105
  80. cartography/intel/azure/storage.py +322 -113
  81. cartography/intel/azure/subscription.py +39 -23
  82. cartography/intel/azure/tenant.py +13 -4
  83. cartography/intel/azure/util/credentials.py +95 -55
  84. cartography/intel/bigfix/__init__.py +2 -2
  85. cartography/intel/bigfix/computers.py +93 -65
  86. cartography/intel/cloudflare/__init__.py +74 -0
  87. cartography/intel/cloudflare/accounts.py +57 -0
  88. cartography/intel/cloudflare/dnsrecords.py +64 -0
  89. cartography/intel/cloudflare/members.py +75 -0
  90. cartography/intel/cloudflare/roles.py +65 -0
  91. cartography/intel/cloudflare/zones.py +64 -0
  92. cartography/intel/create_indexes.py +3 -2
  93. cartography/intel/crowdstrike/__init__.py +11 -9
  94. cartography/intel/crowdstrike/endpoints.py +5 -1
  95. cartography/intel/crowdstrike/spotlight.py +8 -3
  96. cartography/intel/cve/__init__.py +46 -13
  97. cartography/intel/cve/feed.py +48 -12
  98. cartography/intel/digitalocean/__init__.py +22 -13
  99. cartography/intel/digitalocean/compute.py +75 -108
  100. cartography/intel/digitalocean/management.py +44 -80
  101. cartography/intel/digitalocean/platform.py +48 -43
  102. cartography/intel/dns.py +36 -10
  103. cartography/intel/duo/__init__.py +21 -16
  104. cartography/intel/duo/api_host.py +14 -9
  105. cartography/intel/duo/endpoints.py +50 -45
  106. cartography/intel/duo/groups.py +18 -14
  107. cartography/intel/duo/phones.py +37 -34
  108. cartography/intel/duo/tokens.py +26 -23
  109. cartography/intel/duo/users.py +54 -50
  110. cartography/intel/duo/web_authn_credentials.py +30 -25
  111. cartography/intel/entra/__init__.py +25 -7
  112. cartography/intel/entra/ou.py +112 -0
  113. cartography/intel/entra/users.py +69 -63
  114. cartography/intel/gcp/__init__.py +185 -49
  115. cartography/intel/gcp/compute.py +418 -231
  116. cartography/intel/gcp/crm.py +96 -43
  117. cartography/intel/gcp/dns.py +60 -19
  118. cartography/intel/gcp/gke.py +72 -38
  119. cartography/intel/gcp/iam.py +61 -41
  120. cartography/intel/gcp/storage.py +84 -55
  121. cartography/intel/github/__init__.py +13 -11
  122. cartography/intel/github/repos.py +270 -137
  123. cartography/intel/github/teams.py +170 -88
  124. cartography/intel/github/users.py +70 -39
  125. cartography/intel/github/util.py +36 -34
  126. cartography/intel/gsuite/__init__.py +47 -26
  127. cartography/intel/gsuite/api.py +73 -30
  128. cartography/intel/jamf/__init__.py +19 -1
  129. cartography/intel/jamf/computers.py +30 -7
  130. cartography/intel/jamf/util.py +7 -2
  131. cartography/intel/kandji/__init__.py +6 -3
  132. cartography/intel/kandji/devices.py +14 -8
  133. cartography/intel/kubernetes/namespaces.py +7 -4
  134. cartography/intel/kubernetes/pods.py +7 -4
  135. cartography/intel/kubernetes/services.py +8 -4
  136. cartography/intel/lastpass/__init__.py +2 -2
  137. cartography/intel/lastpass/users.py +23 -12
  138. cartography/intel/oci/__init__.py +44 -11
  139. cartography/intel/oci/iam.py +134 -38
  140. cartography/intel/oci/organizations.py +13 -6
  141. cartography/intel/oci/utils.py +43 -20
  142. cartography/intel/okta/__init__.py +66 -15
  143. cartography/intel/okta/applications.py +42 -20
  144. cartography/intel/okta/awssaml.py +93 -33
  145. cartography/intel/okta/factors.py +16 -4
  146. cartography/intel/okta/groups.py +56 -29
  147. cartography/intel/okta/organization.py +5 -1
  148. cartography/intel/okta/origins.py +6 -2
  149. cartography/intel/okta/roles.py +15 -5
  150. cartography/intel/okta/users.py +20 -8
  151. cartography/intel/okta/utils.py +6 -4
  152. cartography/intel/openai/__init__.py +86 -0
  153. cartography/intel/openai/adminapikeys.py +90 -0
  154. cartography/intel/openai/apikeys.py +96 -0
  155. cartography/intel/openai/projects.py +94 -0
  156. cartography/intel/openai/serviceaccounts.py +82 -0
  157. cartography/intel/openai/users.py +78 -0
  158. cartography/intel/openai/util.py +29 -0
  159. cartography/intel/pagerduty/__init__.py +8 -7
  160. cartography/intel/pagerduty/escalation_policies.py +18 -6
  161. cartography/intel/pagerduty/schedules.py +12 -4
  162. cartography/intel/pagerduty/services.py +11 -4
  163. cartography/intel/pagerduty/teams.py +8 -3
  164. cartography/intel/pagerduty/users.py +3 -1
  165. cartography/intel/pagerduty/vendors.py +3 -1
  166. cartography/intel/semgrep/__init__.py +24 -6
  167. cartography/intel/semgrep/dependencies.py +50 -28
  168. cartography/intel/semgrep/deployment.py +3 -1
  169. cartography/intel/semgrep/findings.py +42 -18
  170. cartography/intel/snipeit/__init__.py +17 -3
  171. cartography/intel/snipeit/asset.py +12 -6
  172. cartography/intel/snipeit/user.py +8 -5
  173. cartography/intel/snipeit/util.py +9 -4
  174. cartography/intel/tailscale/__init__.py +77 -0
  175. cartography/intel/tailscale/acls.py +146 -0
  176. cartography/intel/tailscale/devices.py +127 -0
  177. cartography/intel/tailscale/postureintegrations.py +81 -0
  178. cartography/intel/tailscale/tailnets.py +76 -0
  179. cartography/intel/tailscale/users.py +80 -0
  180. cartography/intel/tailscale/utils.py +132 -0
  181. cartography/models/aws/apigateway.py +21 -17
  182. cartography/models/aws/apigatewaycertificate.py +28 -22
  183. cartography/models/aws/apigatewayresource.py +28 -20
  184. cartography/models/aws/apigatewaystage.py +33 -25
  185. cartography/models/aws/cloudtrail/__init__.py +0 -0
  186. cartography/models/aws/cloudtrail/trail.py +61 -0
  187. cartography/models/aws/cloudwatch/__init__.py +0 -0
  188. cartography/models/aws/cloudwatch/loggroup.py +52 -0
  189. cartography/models/aws/dynamodb/gsi.py +30 -22
  190. cartography/models/aws/dynamodb/tables.py +25 -17
  191. cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
  192. cartography/models/aws/ec2/images.py +36 -34
  193. cartography/models/aws/ec2/instances.py +51 -45
  194. cartography/models/aws/ec2/keypair.py +21 -16
  195. cartography/models/aws/ec2/keypair_instance.py +28 -21
  196. cartography/models/aws/ec2/launch_configurations.py +30 -26
  197. cartography/models/aws/ec2/launch_template_versions.py +48 -38
  198. cartography/models/aws/ec2/launch_templates.py +21 -17
  199. cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
  200. cartography/models/aws/ec2/load_balancers.py +47 -37
  201. cartography/models/aws/ec2/network_acl_rules.py +38 -30
  202. cartography/models/aws/ec2/network_acls.py +38 -29
  203. cartography/models/aws/ec2/networkinterface_instance.py +52 -39
  204. cartography/models/aws/ec2/networkinterfaces.py +53 -37
  205. cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
  206. cartography/models/aws/ec2/reservations.py +18 -14
  207. cartography/models/aws/ec2/route_table_associations.py +97 -0
  208. cartography/models/aws/ec2/route_tables.py +128 -0
  209. cartography/models/aws/ec2/routes.py +85 -0
  210. cartography/models/aws/ec2/securitygroup_instance.py +29 -20
  211. cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
  212. cartography/models/aws/ec2/subnet_instance.py +24 -19
  213. cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
  214. cartography/models/aws/ec2/volumes.py +47 -40
  215. cartography/models/aws/efs/__init__.py +0 -0
  216. cartography/models/aws/efs/mount_target.py +52 -0
  217. cartography/models/aws/eks/clusters.py +23 -21
  218. cartography/models/aws/emr.py +32 -30
  219. cartography/models/aws/iam/instanceprofile.py +33 -24
  220. cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
  221. cartography/models/aws/identitycenter/awspermissionset.py +37 -29
  222. cartography/models/aws/identitycenter/awsssouser.py +23 -21
  223. cartography/models/aws/inspector/findings.py +77 -65
  224. cartography/models/aws/inspector/packages.py +35 -29
  225. cartography/models/aws/s3/__init__.py +0 -0
  226. cartography/models/aws/s3/account_public_access_block.py +51 -0
  227. cartography/models/aws/sns/__init__.py +0 -0
  228. cartography/models/aws/sns/topic.py +50 -0
  229. cartography/models/aws/ssm/instance_information.py +51 -39
  230. cartography/models/aws/ssm/instance_patch.py +32 -26
  231. cartography/models/bigfix/bigfix_computer.py +42 -38
  232. cartography/models/bigfix/bigfix_root.py +3 -3
  233. cartography/models/cloudflare/__init__.py +0 -0
  234. cartography/models/cloudflare/account.py +25 -0
  235. cartography/models/cloudflare/dnsrecord.py +55 -0
  236. cartography/models/cloudflare/member.py +82 -0
  237. cartography/models/cloudflare/role.py +44 -0
  238. cartography/models/cloudflare/zone.py +59 -0
  239. cartography/models/core/common.py +12 -10
  240. cartography/models/core/nodes.py +5 -2
  241. cartography/models/core/relationships.py +14 -6
  242. cartography/models/crowdstrike/hosts.py +37 -35
  243. cartography/models/cve/cve.py +34 -32
  244. cartography/models/cve/cve_feed.py +6 -6
  245. cartography/models/digitalocean/__init__.py +0 -0
  246. cartography/models/digitalocean/account.py +21 -0
  247. cartography/models/digitalocean/droplet.py +56 -0
  248. cartography/models/digitalocean/project.py +48 -0
  249. cartography/models/duo/api_host.py +3 -3
  250. cartography/models/duo/endpoint.py +43 -41
  251. cartography/models/duo/group.py +14 -14
  252. cartography/models/duo/phone.py +27 -27
  253. cartography/models/duo/token.py +16 -16
  254. cartography/models/duo/user.py +46 -44
  255. cartography/models/duo/web_authn_credential.py +27 -19
  256. cartography/models/entra/ou.py +48 -0
  257. cartography/models/entra/tenant.py +24 -18
  258. cartography/models/entra/user.py +64 -48
  259. cartography/models/gcp/iam.py +23 -23
  260. cartography/models/github/orgs.py +5 -4
  261. cartography/models/github/teams.py +37 -31
  262. cartography/models/github/users.py +34 -23
  263. cartography/models/kandji/device.py +22 -16
  264. cartography/models/kandji/tenant.py +6 -4
  265. cartography/models/lastpass/tenant.py +3 -3
  266. cartography/models/lastpass/user.py +32 -28
  267. cartography/models/openai/__init__.py +0 -0
  268. cartography/models/openai/adminapikey.py +90 -0
  269. cartography/models/openai/apikey.py +84 -0
  270. cartography/models/openai/organization.py +17 -0
  271. cartography/models/openai/project.py +70 -0
  272. cartography/models/openai/serviceaccount.py +50 -0
  273. cartography/models/openai/user.py +49 -0
  274. cartography/models/semgrep/dependencies.py +36 -24
  275. cartography/models/semgrep/deployment.py +5 -5
  276. cartography/models/semgrep/findings.py +58 -42
  277. cartography/models/semgrep/locations.py +27 -21
  278. cartography/models/snipeit/asset.py +30 -21
  279. cartography/models/snipeit/tenant.py +6 -4
  280. cartography/models/snipeit/user.py +19 -12
  281. cartography/models/tailscale/__init__.py +0 -0
  282. cartography/models/tailscale/device.py +95 -0
  283. cartography/models/tailscale/group.py +86 -0
  284. cartography/models/tailscale/postureintegration.py +58 -0
  285. cartography/models/tailscale/tag.py +102 -0
  286. cartography/models/tailscale/tailnet.py +29 -0
  287. cartography/models/tailscale/user.py +52 -0
  288. cartography/stats.py +3 -3
  289. cartography/sync.py +113 -31
  290. cartography/util.py +84 -62
  291. {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/METADATA +8 -15
  292. cartography-0.103.0.dist-info/RECORD +442 -0
  293. {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/WHEEL +1 -1
  294. cartography-0.102.0rc1.dist-info/RECORD +0 -377
  295. {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/entry_points.txt +0 -0
  296. {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/licenses/LICENSE +0 -0
  297. {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/top_level.txt +0 -0
cartography/util.py CHANGED
@@ -30,7 +30,6 @@ from cartography.graph.statement import get_job_shortname
30
30
  from cartography.stats import get_stats_client
31
31
  from cartography.stats import ScopedStatsClient
32
32
 
33
-
34
33
  logger = logging.getLogger(__name__)
35
34
 
36
35
 
@@ -44,7 +43,7 @@ def run_analysis_job(
44
43
  filename: str,
45
44
  neo4j_session: neo4j.Session,
46
45
  common_job_parameters: Dict,
47
- package: str = 'cartography.data.jobs.analysis',
46
+ package: str = "cartography.data.jobs.analysis",
48
47
  ) -> None:
49
48
  """
50
49
  Enriches existing graph data with analysis jobs. This is designed for use with the sync stage
@@ -66,11 +65,11 @@ def run_analysis_job(
66
65
 
67
66
 
68
67
  def run_analysis_and_ensure_deps(
69
- analysis_job_name: str,
70
- resource_dependencies: Set[str],
71
- requested_syncs: Set[str],
72
- common_job_parameters: Dict[str, Any],
73
- neo4j_session: neo4j.Session,
68
+ analysis_job_name: str,
69
+ resource_dependencies: Set[str],
70
+ requested_syncs: Set[str],
71
+ common_job_parameters: Dict[str, Any],
72
+ neo4j_session: neo4j.Session,
74
73
  ) -> None:
75
74
  """
76
75
  Runs analysis job only if the given set of resource dependencies was included in the requested_syncs.
@@ -100,7 +99,7 @@ def run_scoped_analysis_job(
100
99
  filename: str,
101
100
  neo4j_session: neo4j.Session,
102
101
  common_job_parameters: Dict,
103
- package: str = 'cartography.data.jobs.scoped_analysis',
102
+ package: str = "cartography.data.jobs.scoped_analysis",
104
103
  ) -> None:
105
104
  """
106
105
  Enriches existing graph data scoped to a given sub resource - e.g. the current AWS account.
@@ -116,8 +115,10 @@ def run_scoped_analysis_job(
116
115
 
117
116
 
118
117
  def run_cleanup_job(
119
- filename: str, neo4j_session: neo4j.Session, common_job_parameters: Dict,
120
- package: str = 'cartography.data.jobs.cleanup',
118
+ filename: str,
119
+ neo4j_session: neo4j.Session,
120
+ common_job_parameters: Dict,
121
+ package: str = "cartography.data.jobs.cleanup",
121
122
  ) -> None:
122
123
  GraphJob.run_from_json(
123
124
  neo4j_session,
@@ -138,7 +139,7 @@ def merge_module_sync_metadata(
138
139
  update_tag: int,
139
140
  stat_handler: ScopedStatsClient,
140
141
  ) -> None:
141
- '''
142
+ """
142
143
  This creates `ModuleSyncMetadata` nodes when called from each of the individual modules or sub-modules.
143
144
  The 'types' used here should be actual node labels. For example, if we did sync a particular AWSAccount's S3Buckets,
144
145
  the `grouptype` is 'AWSAccount', the `groupid` is the particular account's `id`, and the `syncedtype` is 'S3Bucket'.
@@ -148,8 +149,9 @@ def merge_module_sync_metadata(
148
149
  :param group_id: The parent module's id
149
150
  :param synced_type: The sub-module's type
150
151
  :param update_tag: Timestamp used to determine data freshness
151
- '''
152
- template = Template("""
152
+ """
153
+ template = Template(
154
+ """
153
155
  MERGE (n:ModuleSyncMetadata{id:'${group_type}_${group_id}_${synced_type}'})
154
156
  ON CREATE SET
155
157
  n:SyncMetadata, n.firstseen=timestamp()
@@ -157,20 +159,25 @@ def merge_module_sync_metadata(
157
159
  n.grouptype='${group_type}',
158
160
  n.groupid='${group_id}',
159
161
  n.lastupdated=$UPDATE_TAG
160
- """)
162
+ """,
163
+ )
161
164
  neo4j_session.run(
162
- template.safe_substitute(group_type=group_type, group_id=group_id, synced_type=synced_type),
165
+ template.safe_substitute(
166
+ group_type=group_type,
167
+ group_id=group_id,
168
+ synced_type=synced_type,
169
+ ),
163
170
  UPDATE_TAG=update_tag,
164
171
  )
165
- stat_handler.incr(f'{group_type}_{group_id}_{synced_type}_lastupdated', update_tag)
172
+ stat_handler.incr(f"{group_type}_{group_id}_{synced_type}_lastupdated", update_tag)
166
173
 
167
174
 
168
175
  def load_resource_binary(package: str, resource_name: str) -> BinaryIO:
169
176
  return open_binary(package, resource_name)
170
177
 
171
178
 
172
- R = TypeVar('R')
173
- F = TypeVar('F', bound=Callable[..., Any])
179
+ R = TypeVar("R")
180
+ F = TypeVar("F", bound=Callable[..., Any])
174
181
 
175
182
 
176
183
  def timeit(method: F) -> F:
@@ -179,6 +186,7 @@ def timeit(method: F) -> F:
179
186
  This is only active if config.statsd_enabled is True.
180
187
  :param method: The function to measure execution
181
188
  """
189
+
182
190
  # Allow access via `inspect` to the wrapped function. This is used in integration tests to standardize param names.
183
191
  @wraps(method)
184
192
  def timed(*args, **kwargs): # type: ignore
@@ -202,40 +210,44 @@ def aws_paginate(
202
210
  object_name: str,
203
211
  **kwargs: Any,
204
212
  ) -> List[Dict]:
205
- '''
213
+ """
206
214
  Helper method for boilerplate boto3 pagination
207
215
  The **kwargs will be forwarded to the paginator
208
- '''
216
+ """
209
217
  paginator = client.get_paginator(method_name)
210
218
  items = []
211
219
  i = 0
212
220
  for i, page in enumerate(paginator.paginate(**kwargs), start=1):
213
221
  if i % 100 == 0:
214
- logger.info(f'fetching page number {i}')
222
+ logger.info(f"fetching page number {i}")
215
223
  if object_name in page:
216
224
  items.extend(page[object_name])
217
225
  else:
218
226
  logger.warning(
219
- f'''aws_paginate: Key "{object_name}" is not present, check if this is a typo.
220
- If not, then the AWS datatype somehow does not have this key.''',
227
+ f"""aws_paginate: Key "{object_name}" is not present, check if this is a typo.
228
+ If not, then the AWS datatype somehow does not have this key.""",
221
229
  )
222
230
  return items
223
231
 
224
232
 
225
- AWSGetFunc = TypeVar('AWSGetFunc', bound=Callable[..., Iterable])
233
+ AWSGetFunc = TypeVar("AWSGetFunc", bound=Callable[..., Iterable])
226
234
 
227
235
  # fix for AWS TooManyRequestsException
228
- # https://github.com/lyft/cartography/issues/297
229
- # https://github.com/lyft/cartography/issues/243
230
- # https://github.com/lyft/cartography/issues/65
231
- # https://github.com/lyft/cartography/issues/25
236
+ # https://github.com/cartography-cncf/cartography/issues/297
237
+ # https://github.com/cartography-cncf/cartography/issues/243
238
+ # https://github.com/cartography-cncf/cartography/issues/65
239
+ # https://github.com/cartography-cncf/cartography/issues/25
232
240
 
233
241
 
234
242
  def backoff_handler(details: Dict) -> None:
235
243
  """
236
244
  Handler that will be executed on exception by backoff mechanism
237
245
  """
238
- logger.warning("Backing off {wait:0.1f} seconds after {tries} tries. Calling function {target}".format(**details))
246
+ logger.warning(
247
+ "Backing off {wait:0.1f} seconds after {tries} tries. Calling function {target}".format(
248
+ **details,
249
+ ),
250
+ )
239
251
 
240
252
 
241
253
  # TODO Move this to cartography.intel.aws.util.common
@@ -250,21 +262,21 @@ def aws_handle_regions(func: AWSGetFunc) -> AWSGetFunc:
250
262
  This should be used on `get_` functions that normally return a list of items.
251
263
  """
252
264
  ERROR_CODES = [
253
- 'AccessDenied',
254
- 'AccessDeniedException',
255
- 'AuthFailure',
256
- 'InvalidClientTokenId',
257
- 'UnauthorizedOperation',
258
- 'UnrecognizedClientException',
259
- 'InternalServerErrorException',
265
+ "AccessDenied",
266
+ "AccessDeniedException",
267
+ "AuthFailure",
268
+ "InvalidClientTokenId",
269
+ "UnauthorizedOperation",
270
+ "UnrecognizedClientException",
271
+ "InternalServerErrorException",
260
272
  ]
261
273
 
262
274
  @wraps(func)
263
275
  # fix for AWS TooManyRequestsException
264
- # https://github.com/lyft/cartography/issues/297
265
- # https://github.com/lyft/cartography/issues/243
266
- # https://github.com/lyft/cartography/issues/65
267
- # https://github.com/lyft/cartography/issues/25
276
+ # https://github.com/cartography-cncf/cartography/issues/297
277
+ # https://github.com/cartography-cncf/cartography/issues/243
278
+ # https://github.com/cartography-cncf/cartography/issues/65
279
+ # https://github.com/cartography-cncf/cartography/issues/25
268
280
  @backoff.on_exception(
269
281
  backoff.expo,
270
282
  botocore.exceptions.ClientError,
@@ -277,23 +289,29 @@ def aws_handle_regions(func: AWSGetFunc) -> AWSGetFunc:
277
289
  except botocore.exceptions.ClientError as e:
278
290
  # The account is not authorized to use this service in this region
279
291
  # so we can continue without raising an exception
280
- if e.response['Error']['Code'] in ERROR_CODES:
281
- logger.warning("{} in this region. Skipping...".format(e.response['Error']['Message']))
292
+ if e.response["Error"]["Code"] in ERROR_CODES:
293
+ logger.warning(
294
+ "{} in this region. Skipping...".format(
295
+ e.response["Error"]["Message"],
296
+ ),
297
+ )
282
298
  return []
283
299
  else:
284
300
  raise
301
+
285
302
  return cast(AWSGetFunc, inner_function)
286
303
 
287
304
 
288
305
  def retries_with_backoff(
289
- func: Callable,
290
- exception_type: Type[Exception],
291
- max_tries: int,
292
- on_backoff: Callable,
306
+ func: Callable,
307
+ exception_type: Type[Exception],
308
+ max_tries: int,
309
+ on_backoff: Callable,
293
310
  ) -> Callable:
294
311
  """
295
312
  Adds retry with backoff to the given function. (Could expand the possible input parameters as needed.)
296
313
  """
314
+
297
315
  @wraps(func)
298
316
  @backoff.on_exception(
299
317
  backoff.expo,
@@ -303,6 +321,7 @@ def retries_with_backoff(
303
321
  )
304
322
  def inner_function(*args, **kwargs): # type: ignore
305
323
  return func(*args, **kwargs)
324
+
306
325
  return cast(Callable, inner_function)
307
326
 
308
327
 
@@ -331,32 +350,29 @@ def dict_date_to_epoch(obj: Dict, key: str) -> Optional[int]:
331
350
 
332
351
 
333
352
  def camel_to_snake(name: str) -> str:
334
- return re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
353
+ return re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()
335
354
 
336
355
 
337
356
  def batch(items: Iterable, size: int = DEFAULT_BATCH_SIZE) -> List[List]:
338
- '''
357
+ """
339
358
  Takes an Iterable of items and returns a list of lists of the same items,
340
359
  batched into chunks of the provided `size`.
341
360
 
342
361
  Use:
343
362
  x = [1,2,3,4,5,6,7,8]
344
363
  batch(x, size=3) -> [[1, 2, 3], [4, 5, 6], [7, 8]]
345
- '''
364
+ """
346
365
  items = list(items)
347
- return [
348
- items[i: i + size]
349
- for i in range(0, len(items), size)
350
- ]
366
+ return [items[i : i + size] for i in range(0, len(items), size)]
351
367
 
352
368
 
353
369
  def is_throttling_exception(exc: Exception) -> bool:
354
- '''
370
+ """
355
371
  Returns True if the exception is caused by a client libraries throttling mechanism
356
- '''
372
+ """
357
373
  # https://boto3.amazonaws.com/v1/documentation/api/1.19.9/guide/error-handling.html
358
374
  if isinstance(exc, botocore.exceptions.ClientError):
359
- if exc.response['Error']['Code'] in ['LimitExceededException', 'Throttling']:
375
+ if exc.response["Error"]["Code"] in ["LimitExceededException", "Throttling"]:
360
376
  return True
361
377
  # add other exceptions here, if needed, like:
362
378
  # https://cloud.google.com/python/docs/reference/storage/1.39.0/retry_timeout#configuring-retries
@@ -366,7 +382,7 @@ def is_throttling_exception(exc: Exception) -> bool:
366
382
 
367
383
 
368
384
  def to_asynchronous(func: Callable[..., R], *args: Any, **kwargs: Any) -> Awaitable[R]:
369
- '''
385
+ """
370
386
  Returns a Future that will run a function and its arguments in the default threadpool.
371
387
  Helper until we start using python 3.9's asyncio.to_thread
372
388
 
@@ -396,8 +412,12 @@ def to_asynchronous(func: Callable[..., R], *args: Any, **kwargs: Any) -> Awaita
396
412
  NOTE: to use this in a Jupyter notebook, you need to do:
397
413
  # import nest_asyncio
398
414
  # nest_asyncio.apply()
399
- '''
400
- CartographyThrottlingException = type('CartographyThrottlingException', (Exception,), {})
415
+ """
416
+ CartographyThrottlingException = type(
417
+ "CartographyThrottlingException",
418
+ (Exception,),
419
+ {},
420
+ )
401
421
 
402
422
  @wraps(func)
403
423
  def wrapper(*args: Any, **kwargs: Any) -> R:
@@ -409,13 +429,15 @@ def to_asynchronous(func: Callable[..., R], *args: Any, **kwargs: Any) -> Awaita
409
429
  raise
410
430
 
411
431
  # don't use @backoff as decorator, to preserve typing
412
- wrapped = backoff.on_exception(backoff.expo, CartographyThrottlingException)(wrapper)
432
+ wrapped = backoff.on_exception(backoff.expo, CartographyThrottlingException)(
433
+ wrapper,
434
+ )
413
435
  call = partial(wrapped, *args, **kwargs)
414
436
  return asyncio.get_event_loop().run_in_executor(None, call)
415
437
 
416
438
 
417
439
  def to_synchronous(*awaitables: Awaitable[Any]) -> List[Any]:
418
- '''
440
+ """
419
441
  Synchronously waits for the Awaitable(s) to complete and returns their result(s).
420
442
  See https://docs.python.org/3.8/library/asyncio-task.html#asyncio-awaitables
421
443
 
@@ -437,5 +459,5 @@ def to_synchronous(*awaitables: Awaitable[Any]) -> List[Any]:
437
459
  future_2 = another_async_func(2)
438
460
 
439
461
  results = to_synchronous(future_1, future_2)
440
- '''
462
+ """
441
463
  return asyncio.get_event_loop().run_until_complete(asyncio.gather(*awaitables))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cartography
3
- Version: 0.102.0rc1
3
+ Version: 0.103.0
4
4
  Summary: Explore assets and their relationships across your technical infrastructure.
5
5
  Maintainer: Cartography Contributors
6
6
  License: apache2
@@ -54,17 +54,7 @@ Requires-Dist: crowdstrike-falconpy>=0.5.1
54
54
  Requires-Dist: python-dateutil
55
55
  Requires-Dist: xmltodict
56
56
  Requires-Dist: duo-client
57
- Provides-Extra: dev
58
- Requires-Dist: backoff>=2.1.2; extra == "dev"
59
- Requires-Dist: moto; extra == "dev"
60
- Requires-Dist: pre-commit; extra == "dev"
61
- Requires-Dist: pytest>=6.2.4; extra == "dev"
62
- Requires-Dist: pytest-mock; extra == "dev"
63
- Requires-Dist: pytest-cov==6.1.1; extra == "dev"
64
- Requires-Dist: pytest-rerunfailures; extra == "dev"
65
- Requires-Dist: pytest-asyncio; extra == "dev"
66
- Requires-Dist: types-PyYAML; extra == "dev"
67
- Requires-Dist: types-requests<2.32.0.20250329; extra == "dev"
57
+ Requires-Dist: cloudflare<5.0.0,>=4.1.0
68
58
  Dynamic: license-file
69
59
 
70
60
  ![Cartography](docs/root/images/logo-horizontal.png)
@@ -91,10 +81,10 @@ You can learn more about the story behind Cartography in our [presentation at BS
91
81
 
92
82
  ## Supported platforms
93
83
 
94
- - [Amazon Web Services](https://cartography-cncf.github.io/cartography/modules/aws/index.html) - API Gateway, Config, EC2, ECS, ECR, Elasticsearch, Elastic Kubernetes Service (EKS), DynamoDB, IAM, Inspector, KMS, Lambda, RDS, Redshift, Route53, S3, Secrets Manager, Security Hub, SQS, SSM, STS, Tags
84
+ - [Amazon Web Services](https://cartography-cncf.github.io/cartography/modules/aws/index.html) - API Gateway, CloudWatch, Config, EC2, ECS, ECR, Elasticsearch, Elastic Kubernetes Service (EKS), DynamoDB, IAM, Inspector, KMS, Lambda, RDS, Redshift, Route53, S3, Secrets Manager, Security Hub, SQS, SSM, STS, Tags
95
85
  - [Google Cloud Platform](https://cartography-cncf.github.io/cartography/modules/gcp/index.html) - Cloud Resource Manager, Compute, DNS, Storage, Google Kubernetes Engine
96
86
  - [Google GSuite](https://cartography-cncf.github.io/cartography/modules/gsuite/index.html) - users, groups
97
- - [Oracle Cloud Infrastructure](docs/setup/config/oci.md) - IAM
87
+ - [Oracle Cloud Infrastructure](https://cartography-cncf.github.io/cartography/modules/oci/index.html) - IAM
98
88
  - [Okta](https://cartography-cncf.github.io/cartography/modules/okta/index.html) - users, groups, organizations, roles, applications, factors, trusted origins, reply URIs
99
89
  - [GitHub](https://cartography-cncf.github.io/cartography/modules/github/index.html) - repos, branches, users, teams
100
90
  - [DigitalOcean](https://cartography-cncf.github.io/cartography/modules/digitalocean/index.html)
@@ -109,6 +99,9 @@ You can learn more about the story behind Cartography in our [presentation at BS
109
99
  - [Duo](https://cartography-cncf.github.io/cartography/modules/duo/index.html) - Users, Groups, Endpoints
110
100
  - [Kandji](https://cartography-cncf.github.io/cartography/modules/kandji/index.html) - Devices
111
101
  - [SnipeIT](https://cartography-cncf.github.io/cartography/modules/snipeit/index.html) - Users, Assets
102
+ - [Tailscale](https://cartography-cncf.github.io/cartography/modules/tailscale/index.html) - Tailnet, Users, Devices, Groups, Tags, PostureIntegrations
103
+ - [Cloudflare](https://cartography-cncf.github.io/cartography/modules/cloudflare/index.html) - Account, Role, Member, Zone, DNSRecord
104
+ - [OpenAI](https://cartography-cncf.github.io/cartography/modules/openai/index.html) - - Organization, AdminApiKey, User, Project, ProjectServiceAccount, ProjectApiKey
112
105
 
113
106
 
114
107
  ## Philosophy
@@ -172,7 +165,7 @@ Thank you for considering contributing to Cartography!
172
165
  All contributors and participants of this project must follow the [CNCF code of conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md).
173
166
 
174
167
  ### Bug reports and feature requests and discussions
175
- Submit a GitHub issue to report a bug or request a new feature. If we decide that the issue needs more discussion - usually because the scope is too large or we need to make careful decision - we will convert the issue to a [GitHub Discussion](https://github.com/lyft/cartography/discussions).
168
+ Submit a GitHub issue to report a bug or request a new feature. If we decide that the issue needs more discussion - usually because the scope is too large or we need to make careful decision - we will convert the issue to a [GitHub Discussion](https://github.com/cartography-cncf/cartography/discussions).
176
169
 
177
170
  ### Developing Cartography
178
171