cartography 0.104.0rc2__py3-none-any.whl → 0.123.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.
Files changed (642) hide show
  1. cartography/_version.py +16 -3
  2. cartography/cli.py +466 -5
  3. cartography/client/aws/__init__.py +19 -0
  4. cartography/client/aws/ecr.py +51 -0
  5. cartography/client/core/tx.py +357 -8
  6. cartography/config.py +153 -0
  7. cartography/data/azure_permission_relationships.yaml +20 -0
  8. cartography/data/gcp_permission_relationships.yaml +21 -0
  9. cartography/data/indexes.cypher +0 -186
  10. cartography/data/jobs/analysis/aws_ec2_keypair_analysis.json +2 -2
  11. cartography/data/jobs/analysis/keycloak_inheritance.json +30 -0
  12. cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json +0 -12
  13. cartography/data/jobs/cleanup/github_repos_cleanup.json +2 -0
  14. cartography/driftdetect/cli.py +3 -2
  15. cartography/graph/cleanupbuilder.py +198 -41
  16. cartography/graph/job.py +54 -6
  17. cartography/graph/querybuilder.py +528 -27
  18. cartography/graph/statement.py +5 -1
  19. cartography/intel/airbyte/__init__.py +105 -0
  20. cartography/intel/airbyte/connections.py +120 -0
  21. cartography/intel/airbyte/destinations.py +81 -0
  22. cartography/intel/airbyte/organizations.py +59 -0
  23. cartography/intel/airbyte/sources.py +78 -0
  24. cartography/intel/airbyte/tags.py +64 -0
  25. cartography/intel/airbyte/users.py +106 -0
  26. cartography/intel/airbyte/util.py +122 -0
  27. cartography/intel/airbyte/workspaces.py +63 -0
  28. cartography/intel/aws/__init__.py +24 -9
  29. cartography/intel/aws/acm.py +124 -0
  30. cartography/intel/aws/apigateway.py +253 -22
  31. cartography/intel/aws/apigatewayv2.py +116 -0
  32. cartography/intel/aws/cloudtrail.py +17 -39
  33. cartography/intel/aws/cloudtrail_management_events.py +962 -0
  34. cartography/intel/aws/cloudwatch.py +150 -4
  35. cartography/intel/aws/codebuild.py +132 -0
  36. cartography/intel/aws/cognito.py +201 -0
  37. cartography/intel/aws/config.py +7 -3
  38. cartography/intel/aws/ec2/elastic_ip_addresses.py +3 -1
  39. cartography/intel/aws/ec2/instances.py +25 -1
  40. cartography/intel/aws/ec2/internet_gateways.py +4 -2
  41. cartography/intel/aws/ec2/load_balancer_v2s.py +11 -5
  42. cartography/intel/aws/ec2/network_interfaces.py +5 -1
  43. cartography/intel/aws/ec2/reserved_instances.py +3 -1
  44. cartography/intel/aws/ec2/security_groups.py +140 -122
  45. cartography/intel/aws/ec2/snapshots.py +47 -84
  46. cartography/intel/aws/ec2/subnets.py +37 -63
  47. cartography/intel/aws/ec2/tgw.py +11 -5
  48. cartography/intel/aws/ec2/volumes.py +1 -1
  49. cartography/intel/aws/ec2/vpc.py +140 -124
  50. cartography/intel/aws/ec2/vpc_peerings.py +262 -125
  51. cartography/intel/aws/ecr.py +269 -98
  52. cartography/intel/aws/ecr_image_layers.py +923 -0
  53. cartography/intel/aws/ecs.py +251 -380
  54. cartography/intel/aws/efs.py +179 -11
  55. cartography/intel/aws/elasticache.py +102 -79
  56. cartography/intel/aws/elasticsearch.py +13 -4
  57. cartography/intel/aws/eventbridge.py +164 -0
  58. cartography/intel/aws/glue.py +181 -0
  59. cartography/intel/aws/guardduty.py +443 -0
  60. cartography/intel/aws/iam.py +750 -493
  61. cartography/intel/aws/identitycenter.py +605 -83
  62. cartography/intel/aws/inspector.py +221 -105
  63. cartography/intel/aws/kms.py +173 -201
  64. cartography/intel/aws/lambda_function.py +272 -189
  65. cartography/intel/aws/organizations.py +10 -9
  66. cartography/intel/aws/permission_relationships.py +10 -20
  67. cartography/intel/aws/rds.py +337 -446
  68. cartography/intel/aws/redshift.py +9 -4
  69. cartography/intel/aws/resourcegroupstaggingapi.py +78 -19
  70. cartography/intel/aws/resources.py +18 -0
  71. cartography/intel/aws/route53.py +386 -332
  72. cartography/intel/aws/s3.py +322 -14
  73. cartography/intel/aws/secretsmanager.py +81 -49
  74. cartography/intel/aws/securityhub.py +3 -1
  75. cartography/intel/aws/sns.py +62 -2
  76. cartography/intel/aws/sqs.py +36 -90
  77. cartography/intel/aws/ssm.py +3 -5
  78. cartography/intel/azure/__init__.py +202 -48
  79. cartography/intel/azure/aks.py +175 -0
  80. cartography/intel/azure/app_service.py +105 -0
  81. cartography/intel/azure/compute.py +59 -112
  82. cartography/intel/azure/container_instances.py +95 -0
  83. cartography/intel/azure/cosmosdb.py +222 -361
  84. cartography/intel/azure/data_factory.py +85 -0
  85. cartography/intel/azure/data_factory_dataset.py +128 -0
  86. cartography/intel/azure/data_factory_linked_service.py +119 -0
  87. cartography/intel/azure/data_factory_pipeline.py +142 -0
  88. cartography/intel/azure/data_lake.py +124 -0
  89. cartography/intel/azure/event_grid.py +94 -0
  90. cartography/intel/azure/functions.py +124 -0
  91. cartography/intel/azure/load_balancers.py +263 -0
  92. cartography/intel/azure/logic_apps.py +101 -0
  93. cartography/intel/azure/monitor.py +105 -0
  94. cartography/intel/azure/network.py +467 -0
  95. cartography/intel/azure/permission_relationships.py +466 -0
  96. cartography/intel/azure/rbac.py +309 -0
  97. cartography/intel/azure/resource_groups.py +82 -0
  98. cartography/intel/azure/security_center.py +106 -0
  99. cartography/intel/azure/sql.py +145 -292
  100. cartography/intel/azure/storage.py +185 -262
  101. cartography/intel/azure/subscription.py +21 -43
  102. cartography/intel/azure/tenant.py +39 -30
  103. cartography/intel/azure/util/common.py +13 -0
  104. cartography/intel/azure/util/credentials.py +49 -174
  105. cartography/intel/azure/util/tag.py +41 -0
  106. cartography/intel/create_indexes.py +2 -1
  107. cartography/intel/crowdstrike/spotlight.py +5 -2
  108. cartography/intel/dns.py +5 -2
  109. cartography/intel/entra/__init__.py +100 -1
  110. cartography/intel/entra/app_role_assignments.py +284 -0
  111. cartography/intel/entra/applications.py +182 -0
  112. cartography/intel/entra/federation/__init__.py +0 -0
  113. cartography/intel/entra/federation/aws_identity_center.py +77 -0
  114. cartography/intel/entra/groups.py +198 -0
  115. cartography/intel/entra/ou.py +48 -24
  116. cartography/intel/entra/service_principals.py +217 -0
  117. cartography/intel/entra/users.py +105 -57
  118. cartography/intel/gcp/__init__.py +334 -396
  119. cartography/intel/gcp/bigtable_app_profile.py +101 -0
  120. cartography/intel/gcp/bigtable_backup.py +91 -0
  121. cartography/intel/gcp/bigtable_cluster.py +93 -0
  122. cartography/intel/gcp/bigtable_instance.py +86 -0
  123. cartography/intel/gcp/bigtable_table.py +87 -0
  124. cartography/intel/gcp/cai.py +292 -0
  125. cartography/intel/gcp/clients.py +112 -0
  126. cartography/intel/gcp/compute.py +128 -119
  127. cartography/intel/gcp/crm/__init__.py +0 -0
  128. cartography/intel/gcp/crm/folders.py +114 -0
  129. cartography/intel/gcp/crm/orgs.py +70 -0
  130. cartography/intel/gcp/crm/projects.py +120 -0
  131. cartography/intel/gcp/dns.py +83 -169
  132. cartography/intel/gcp/gke.py +72 -113
  133. cartography/intel/gcp/iam.py +111 -91
  134. cartography/intel/gcp/permission_relationships.py +394 -0
  135. cartography/intel/gcp/policy_bindings.py +225 -0
  136. cartography/intel/gcp/storage.py +75 -159
  137. cartography/intel/github/__init__.py +62 -25
  138. cartography/intel/github/commits.py +423 -0
  139. cartography/intel/github/repos.py +463 -85
  140. cartography/intel/github/teams.py +3 -3
  141. cartography/intel/github/users.py +5 -0
  142. cartography/intel/github/util.py +12 -0
  143. cartography/intel/googleworkspace/__init__.py +193 -0
  144. cartography/intel/googleworkspace/devices.py +254 -0
  145. cartography/intel/googleworkspace/groups.py +568 -0
  146. cartography/intel/googleworkspace/oauth_apps.py +259 -0
  147. cartography/intel/googleworkspace/tenant.py +85 -0
  148. cartography/intel/googleworkspace/users.py +138 -0
  149. cartography/intel/gsuite/__init__.py +17 -9
  150. cartography/intel/gsuite/groups.py +291 -0
  151. cartography/intel/gsuite/users.py +142 -0
  152. cartography/intel/jamf/computers.py +7 -1
  153. cartography/intel/keycloak/__init__.py +153 -0
  154. cartography/intel/keycloak/authenticationexecutions.py +322 -0
  155. cartography/intel/keycloak/authenticationflows.py +77 -0
  156. cartography/intel/keycloak/clients.py +187 -0
  157. cartography/intel/keycloak/groups.py +126 -0
  158. cartography/intel/keycloak/identityproviders.py +94 -0
  159. cartography/intel/keycloak/organizations.py +163 -0
  160. cartography/intel/keycloak/realms.py +61 -0
  161. cartography/intel/keycloak/roles.py +202 -0
  162. cartography/intel/keycloak/scopes.py +73 -0
  163. cartography/intel/keycloak/users.py +70 -0
  164. cartography/intel/keycloak/util.py +47 -0
  165. cartography/intel/kubernetes/__init__.py +60 -14
  166. cartography/intel/kubernetes/clusters.py +86 -0
  167. cartography/intel/kubernetes/eks.py +402 -0
  168. cartography/intel/kubernetes/namespaces.py +59 -57
  169. cartography/intel/kubernetes/pods.py +168 -75
  170. cartography/intel/kubernetes/rbac.py +597 -0
  171. cartography/intel/kubernetes/secrets.py +95 -45
  172. cartography/intel/kubernetes/services.py +131 -67
  173. cartography/intel/kubernetes/util.py +142 -14
  174. cartography/intel/oci/iam.py +23 -9
  175. cartography/intel/oci/organizations.py +3 -1
  176. cartography/intel/oci/utils.py +28 -5
  177. cartography/intel/okta/applications.py +15 -5
  178. cartography/intel/okta/awssaml.py +14 -10
  179. cartography/intel/okta/factors.py +3 -1
  180. cartography/intel/okta/groups.py +5 -2
  181. cartography/intel/okta/organization.py +3 -1
  182. cartography/intel/okta/origins.py +3 -1
  183. cartography/intel/okta/roles.py +5 -2
  184. cartography/intel/okta/users.py +10 -2
  185. cartography/intel/ontology/__init__.py +44 -0
  186. cartography/intel/ontology/devices.py +54 -0
  187. cartography/intel/ontology/users.py +54 -0
  188. cartography/intel/ontology/utils.py +176 -0
  189. cartography/intel/pagerduty/escalation_policies.py +13 -6
  190. cartography/intel/pagerduty/schedules.py +9 -4
  191. cartography/intel/pagerduty/services.py +7 -3
  192. cartography/intel/pagerduty/teams.py +5 -2
  193. cartography/intel/pagerduty/users.py +3 -1
  194. cartography/intel/pagerduty/vendors.py +3 -1
  195. cartography/intel/scaleway/__init__.py +127 -0
  196. cartography/intel/scaleway/iam/__init__.py +0 -0
  197. cartography/intel/scaleway/iam/apikeys.py +71 -0
  198. cartography/intel/scaleway/iam/applications.py +71 -0
  199. cartography/intel/scaleway/iam/groups.py +71 -0
  200. cartography/intel/scaleway/iam/users.py +71 -0
  201. cartography/intel/scaleway/instances/__init__.py +0 -0
  202. cartography/intel/scaleway/instances/flexibleips.py +86 -0
  203. cartography/intel/scaleway/instances/instances.py +92 -0
  204. cartography/intel/scaleway/projects.py +79 -0
  205. cartography/intel/scaleway/storage/__init__.py +0 -0
  206. cartography/intel/scaleway/storage/snapshots.py +86 -0
  207. cartography/intel/scaleway/storage/volumes.py +84 -0
  208. cartography/intel/scaleway/utils.py +37 -0
  209. cartography/intel/sentinelone/__init__.py +75 -0
  210. cartography/intel/sentinelone/account.py +140 -0
  211. cartography/intel/sentinelone/agent.py +139 -0
  212. cartography/intel/sentinelone/api.py +124 -0
  213. cartography/intel/sentinelone/application.py +248 -0
  214. cartography/intel/sentinelone/cve.py +119 -0
  215. cartography/intel/sentinelone/utils.py +28 -0
  216. cartography/intel/slack/__init__.py +78 -0
  217. cartography/intel/slack/channels.py +80 -0
  218. cartography/intel/slack/groups.py +90 -0
  219. cartography/intel/slack/teams.py +65 -0
  220. cartography/intel/slack/users.py +57 -0
  221. cartography/intel/slack/utils.py +29 -0
  222. cartography/intel/spacelift/__init__.py +161 -0
  223. cartography/intel/spacelift/account.py +73 -0
  224. cartography/intel/spacelift/ec2_ownership.py +280 -0
  225. cartography/intel/spacelift/runs.py +463 -0
  226. cartography/intel/spacelift/spaces.py +112 -0
  227. cartography/intel/spacelift/stacks.py +119 -0
  228. cartography/intel/spacelift/util.py +122 -0
  229. cartography/intel/spacelift/workerpools.py +131 -0
  230. cartography/intel/spacelift/workers.py +128 -0
  231. cartography/intel/trivy/__init__.py +272 -0
  232. cartography/intel/trivy/scanner.py +386 -0
  233. cartography/models/airbyte/__init__.py +0 -0
  234. cartography/models/airbyte/connection.py +138 -0
  235. cartography/models/airbyte/destination.py +75 -0
  236. cartography/models/airbyte/organization.py +19 -0
  237. cartography/models/airbyte/source.py +75 -0
  238. cartography/models/airbyte/stream.py +74 -0
  239. cartography/models/airbyte/tag.py +69 -0
  240. cartography/models/airbyte/user.py +115 -0
  241. cartography/models/airbyte/workspace.py +46 -0
  242. cartography/models/anthropic/apikey.py +4 -0
  243. cartography/models/anthropic/user.py +4 -0
  244. cartography/models/aws/acm/__init__.py +0 -0
  245. cartography/models/aws/acm/certificate.py +75 -0
  246. cartography/models/aws/apigateway/__init__.py +0 -0
  247. cartography/models/aws/apigateway/apigatewaydeployment.py +74 -0
  248. cartography/models/aws/apigateway/apigatewayintegration.py +79 -0
  249. cartography/models/aws/apigateway/apigatewaymethod.py +74 -0
  250. cartography/models/aws/apigatewayv2/__init__.py +0 -0
  251. cartography/models/aws/apigatewayv2/apigatewayv2.py +53 -0
  252. cartography/models/aws/cloudtrail/management_events.py +153 -0
  253. cartography/models/aws/cloudtrail/trail.py +45 -0
  254. cartography/models/aws/cloudwatch/log_metric_filter.py +79 -0
  255. cartography/models/aws/cloudwatch/metric_alarm.py +53 -0
  256. cartography/models/aws/codebuild/__init__.py +0 -0
  257. cartography/models/aws/codebuild/project.py +49 -0
  258. cartography/models/aws/cognito/__init__.py +0 -0
  259. cartography/models/aws/cognito/identity_pool.py +70 -0
  260. cartography/models/aws/cognito/user_pool.py +47 -0
  261. cartography/models/aws/dynamodb/tables.py +2 -0
  262. cartography/models/aws/ec2/instances.py +25 -1
  263. cartography/models/aws/ec2/networkinterfaces.py +4 -0
  264. cartography/models/aws/ec2/security_group_rules.py +109 -0
  265. cartography/models/aws/ec2/security_groups.py +90 -0
  266. cartography/models/aws/ec2/snapshots.py +58 -0
  267. cartography/models/aws/ec2/subnet_instance.py +2 -0
  268. cartography/models/aws/ec2/subnet_networkinterface.py +2 -0
  269. cartography/models/aws/ec2/subnets.py +65 -0
  270. cartography/models/aws/ec2/volumes.py +20 -0
  271. cartography/models/aws/ec2/vpc.py +46 -0
  272. cartography/models/aws/ec2/vpc_cidr.py +102 -0
  273. cartography/models/aws/ec2/vpc_peering.py +157 -0
  274. cartography/models/aws/ecr/__init__.py +0 -0
  275. cartography/models/aws/ecr/image.py +146 -0
  276. cartography/models/aws/ecr/image_layer.py +107 -0
  277. cartography/models/aws/ecr/repository.py +72 -0
  278. cartography/models/aws/ecr/repository_image.py +95 -0
  279. cartography/models/aws/ecs/__init__.py +0 -0
  280. cartography/models/aws/ecs/clusters.py +64 -0
  281. cartography/models/aws/ecs/container_definitions.py +93 -0
  282. cartography/models/aws/ecs/container_instances.py +84 -0
  283. cartography/models/aws/ecs/containers.py +101 -0
  284. cartography/models/aws/ecs/services.py +134 -0
  285. cartography/models/aws/ecs/task_definitions.py +135 -0
  286. cartography/models/aws/ecs/tasks.py +134 -0
  287. cartography/models/aws/efs/access_point.py +77 -0
  288. cartography/models/aws/efs/file_system.py +60 -0
  289. cartography/models/aws/efs/mount_target.py +29 -2
  290. cartography/models/aws/elasticache/__init__.py +0 -0
  291. cartography/models/aws/elasticache/cluster.py +65 -0
  292. cartography/models/aws/elasticache/topic.py +67 -0
  293. cartography/models/aws/eventbridge/__init__.py +0 -0
  294. cartography/models/aws/eventbridge/rule.py +77 -0
  295. cartography/models/aws/eventbridge/target.py +71 -0
  296. cartography/models/aws/glue/__init__.py +0 -0
  297. cartography/models/aws/glue/connection.py +51 -0
  298. cartography/models/aws/glue/job.py +69 -0
  299. cartography/models/aws/guardduty/__init__.py +1 -0
  300. cartography/models/aws/guardduty/detectors.py +50 -0
  301. cartography/models/aws/guardduty/findings.py +121 -0
  302. cartography/models/aws/iam/access_key.py +103 -0
  303. cartography/models/aws/iam/account_role.py +24 -0
  304. cartography/models/aws/iam/federated_principal.py +60 -0
  305. cartography/models/aws/iam/group.py +60 -0
  306. cartography/models/aws/iam/group_membership.py +27 -0
  307. cartography/models/aws/iam/inline_policy.py +78 -0
  308. cartography/models/aws/iam/managed_policy.py +51 -0
  309. cartography/models/aws/iam/policy_statement.py +57 -0
  310. cartography/models/aws/iam/role.py +83 -0
  311. cartography/models/aws/iam/root_principal.py +52 -0
  312. cartography/models/aws/iam/service_principal.py +30 -0
  313. cartography/models/aws/iam/sts_assumerole_allow.py +38 -0
  314. cartography/models/aws/iam/user.py +59 -0
  315. cartography/models/aws/identitycenter/awsidentitycenter.py +1 -0
  316. cartography/models/aws/identitycenter/awspermissionset.py +70 -0
  317. cartography/models/aws/identitycenter/awssogroup.py +70 -0
  318. cartography/models/aws/identitycenter/awsssouser.py +49 -9
  319. cartography/models/aws/inspector/findings.py +37 -0
  320. cartography/models/aws/inspector/packages.py +1 -31
  321. cartography/models/aws/kms/__init__.py +0 -0
  322. cartography/models/aws/kms/aliases.py +86 -0
  323. cartography/models/aws/kms/grants.py +65 -0
  324. cartography/models/aws/kms/keys.py +88 -0
  325. cartography/models/aws/lambda_function/__init__.py +0 -0
  326. cartography/models/aws/lambda_function/alias.py +74 -0
  327. cartography/models/aws/lambda_function/event_source_mapping.py +88 -0
  328. cartography/models/aws/lambda_function/lambda_function.py +91 -0
  329. cartography/models/aws/lambda_function/layer.py +72 -0
  330. cartography/models/aws/rds/__init__.py +0 -0
  331. cartography/models/aws/rds/cluster.py +91 -0
  332. cartography/models/aws/rds/event_subscription.py +146 -0
  333. cartography/models/aws/rds/instance.py +156 -0
  334. cartography/models/aws/rds/snapshot.py +108 -0
  335. cartography/models/aws/rds/subnet_group.py +101 -0
  336. cartography/models/aws/route53/__init__.py +0 -0
  337. cartography/models/aws/route53/dnsrecord.py +235 -0
  338. cartography/models/aws/route53/nameserver.py +63 -0
  339. cartography/models/aws/route53/subzone.py +40 -0
  340. cartography/models/aws/route53/zone.py +47 -0
  341. cartography/models/aws/s3/notification.py +24 -0
  342. cartography/models/aws/secretsmanager/secret.py +106 -0
  343. cartography/models/aws/secretsmanager/secret_version.py +0 -2
  344. cartography/models/aws/sns/topic_subscription.py +74 -0
  345. cartography/models/aws/sqs/__init__.py +0 -0
  346. cartography/models/aws/sqs/queue.py +89 -0
  347. cartography/models/azure/__init__.py +0 -0
  348. cartography/models/azure/aks_cluster.py +54 -0
  349. cartography/models/azure/aks_nodepool.py +54 -0
  350. cartography/models/azure/app_service.py +59 -0
  351. cartography/models/azure/container_instance.py +57 -0
  352. cartography/models/azure/cosmosdb/__init__.py +0 -0
  353. cartography/models/azure/cosmosdb/account.py +77 -0
  354. cartography/models/azure/cosmosdb/accountfailoverpolicy.py +77 -0
  355. cartography/models/azure/cosmosdb/cassandrakeyspace.py +82 -0
  356. cartography/models/azure/cosmosdb/cassandratable.py +81 -0
  357. cartography/models/azure/cosmosdb/corspolicy.py +74 -0
  358. cartography/models/azure/cosmosdb/dblocation.py +120 -0
  359. cartography/models/azure/cosmosdb/mongodbcollection.py +82 -0
  360. cartography/models/azure/cosmosdb/mongodbdatabase.py +78 -0
  361. cartography/models/azure/cosmosdb/privateendpointconnection.py +81 -0
  362. cartography/models/azure/cosmosdb/sqlcontainer.py +88 -0
  363. cartography/models/azure/cosmosdb/sqldatabase.py +78 -0
  364. cartography/models/azure/cosmosdb/tableresource.py +76 -0
  365. cartography/models/azure/cosmosdb/virtualnetworkrule.py +78 -0
  366. cartography/models/azure/data_factory/__init__.py +0 -0
  367. cartography/models/azure/data_factory/data_factory.py +51 -0
  368. cartography/models/azure/data_factory/data_factory_dataset.py +94 -0
  369. cartography/models/azure/data_factory/data_factory_linked_service.py +78 -0
  370. cartography/models/azure/data_factory/data_factory_pipeline.py +93 -0
  371. cartography/models/azure/data_lake_filesystem.py +51 -0
  372. cartography/models/azure/event_grid_topic.py +57 -0
  373. cartography/models/azure/function_app.py +59 -0
  374. cartography/models/azure/load_balancer/__init__.py +0 -0
  375. cartography/models/azure/load_balancer/load_balancer.py +49 -0
  376. cartography/models/azure/load_balancer/load_balancer_backend_pool.py +73 -0
  377. cartography/models/azure/load_balancer/load_balancer_frontend_ip.py +75 -0
  378. cartography/models/azure/load_balancer/load_balancer_inbound_nat_rule.py +78 -0
  379. cartography/models/azure/load_balancer/load_balancer_rule.py +108 -0
  380. cartography/models/azure/logic_apps.py +56 -0
  381. cartography/models/azure/monitor.py +54 -0
  382. cartography/models/azure/network_interface.py +112 -0
  383. cartography/models/azure/network_security_group.py +50 -0
  384. cartography/models/azure/permission_relationships.py +60 -0
  385. cartography/models/azure/principal.py +41 -0
  386. cartography/models/azure/public_ip_address.py +50 -0
  387. cartography/models/azure/rbac.py +268 -0
  388. cartography/models/azure/resource_groups.py +52 -0
  389. cartography/models/azure/security_center.py +50 -0
  390. cartography/models/azure/sql/__init__.py +0 -0
  391. cartography/models/azure/sql/databasethreatdetectionpolicy.py +85 -0
  392. cartography/models/azure/sql/elasticpool.py +77 -0
  393. cartography/models/azure/sql/failovergroup.py +73 -0
  394. cartography/models/azure/sql/recoverabledatabase.py +75 -0
  395. cartography/models/azure/sql/replicationlink.py +81 -0
  396. cartography/models/azure/sql/restorabledroppeddatabase.py +82 -0
  397. cartography/models/azure/sql/restorepoint.py +74 -0
  398. cartography/models/azure/sql/serveradadministrator.py +74 -0
  399. cartography/models/azure/sql/serverdnsalias.py +71 -0
  400. cartography/models/azure/sql/sqldatabase.py +85 -0
  401. cartography/models/azure/sql/sqlserver.py +50 -0
  402. cartography/models/azure/sql/transparentdataencryption.py +76 -0
  403. cartography/models/azure/storage/__init__.py +0 -0
  404. cartography/models/azure/storage/account.py +59 -0
  405. cartography/models/azure/storage/blobcontainer.py +85 -0
  406. cartography/models/azure/storage/blobservice.py +71 -0
  407. cartography/models/azure/storage/fileservice.py +71 -0
  408. cartography/models/azure/storage/fileshare.py +82 -0
  409. cartography/models/azure/storage/queue.py +71 -0
  410. cartography/models/azure/storage/queueservice.py +73 -0
  411. cartography/models/azure/storage/table.py +72 -0
  412. cartography/models/azure/storage/tableservice.py +73 -0
  413. cartography/models/azure/subnet.py +101 -0
  414. cartography/models/azure/subscription.py +47 -0
  415. cartography/models/azure/tags/__init__.py +0 -0
  416. cartography/models/azure/tags/storage_tag.py +40 -0
  417. cartography/models/azure/tags/tag.py +37 -0
  418. cartography/models/azure/tenant.py +17 -0
  419. cartography/models/azure/virtual_network.py +49 -0
  420. cartography/models/azure/vm/__init__.py +0 -0
  421. cartography/models/azure/vm/datadisk.py +80 -0
  422. cartography/models/azure/vm/disk.py +55 -0
  423. cartography/models/azure/vm/snapshot.py +56 -0
  424. cartography/models/azure/vm/virtualmachine.py +59 -0
  425. cartography/models/bigfix/bigfix_computer.py +1 -1
  426. cartography/models/cloudflare/member.py +4 -0
  427. cartography/models/core/common.py +1 -0
  428. cartography/models/core/nodes.py +15 -2
  429. cartography/models/core/relationships.py +44 -0
  430. cartography/models/crowdstrike/hosts.py +1 -1
  431. cartography/models/digitalocean/droplet.py +2 -0
  432. cartography/models/duo/endpoint.py +1 -1
  433. cartography/models/duo/phone.py +2 -2
  434. cartography/models/duo/user.py +4 -0
  435. cartography/models/entra/app_role_assignment.py +115 -0
  436. cartography/models/entra/application.py +49 -0
  437. cartography/models/entra/entra_user_to_aws_sso.py +41 -0
  438. cartography/models/entra/group.py +117 -0
  439. cartography/models/entra/service_principal.py +104 -0
  440. cartography/models/entra/user.py +42 -51
  441. cartography/models/gcp/__init__.py +0 -0
  442. cartography/models/gcp/bigtable/__init__.py +0 -0
  443. cartography/models/gcp/bigtable/app_profile.py +94 -0
  444. cartography/models/gcp/bigtable/backup.py +91 -0
  445. cartography/models/gcp/bigtable/cluster.py +73 -0
  446. cartography/models/gcp/bigtable/instance.py +52 -0
  447. cartography/models/gcp/bigtable/table.py +69 -0
  448. cartography/models/gcp/compute/__init__.py +0 -0
  449. cartography/models/gcp/compute/subnet.py +74 -0
  450. cartography/models/gcp/compute/vpc.py +50 -0
  451. cartography/models/gcp/crm/__init__.py +0 -0
  452. cartography/models/gcp/crm/folders.py +98 -0
  453. cartography/models/gcp/crm/organizations.py +21 -0
  454. cartography/models/gcp/crm/projects.py +100 -0
  455. cartography/models/gcp/dns.py +109 -0
  456. cartography/models/gcp/gke.py +69 -0
  457. cartography/models/gcp/iam.py +3 -0
  458. cartography/models/gcp/permission_relationships.py +61 -0
  459. cartography/models/gcp/policy_bindings.py +93 -0
  460. cartography/models/gcp/storage/__init__.py +0 -0
  461. cartography/models/gcp/storage/bucket.py +119 -0
  462. cartography/models/github/commits.py +63 -0
  463. cartography/models/github/dependencies.py +73 -0
  464. cartography/models/github/manifests.py +49 -0
  465. cartography/models/github/users.py +10 -0
  466. cartography/models/googleworkspace/__init__.py +0 -0
  467. cartography/models/googleworkspace/device.py +132 -0
  468. cartography/models/googleworkspace/group.py +382 -0
  469. cartography/models/googleworkspace/oauth_app.py +124 -0
  470. cartography/models/googleworkspace/tenant.py +30 -0
  471. cartography/models/googleworkspace/user.py +113 -0
  472. cartography/models/gsuite/__init__.py +0 -0
  473. cartography/models/gsuite/group.py +218 -0
  474. cartography/models/gsuite/tenant.py +29 -0
  475. cartography/models/gsuite/user.py +107 -0
  476. cartography/models/kandji/device.py +1 -2
  477. cartography/models/keycloak/__init__.py +0 -0
  478. cartography/models/keycloak/authenticationexecution.py +160 -0
  479. cartography/models/keycloak/authenticationflow.py +54 -0
  480. cartography/models/keycloak/client.py +179 -0
  481. cartography/models/keycloak/group.py +101 -0
  482. cartography/models/keycloak/identityprovider.py +89 -0
  483. cartography/models/keycloak/organization.py +116 -0
  484. cartography/models/keycloak/organizationdomain.py +73 -0
  485. cartography/models/keycloak/realm.py +173 -0
  486. cartography/models/keycloak/role.py +126 -0
  487. cartography/models/keycloak/scope.py +73 -0
  488. cartography/models/keycloak/user.py +55 -0
  489. cartography/models/kubernetes/__init__.py +0 -0
  490. cartography/models/kubernetes/clusterrolebindings.py +138 -0
  491. cartography/models/kubernetes/clusterroles.py +52 -0
  492. cartography/models/kubernetes/clusters.py +26 -0
  493. cartography/models/kubernetes/containers.py +133 -0
  494. cartography/models/kubernetes/groups.py +107 -0
  495. cartography/models/kubernetes/namespaces.py +51 -0
  496. cartography/models/kubernetes/oidc.py +51 -0
  497. cartography/models/kubernetes/pods.py +80 -0
  498. cartography/models/kubernetes/rolebindings.py +159 -0
  499. cartography/models/kubernetes/roles.py +76 -0
  500. cartography/models/kubernetes/secrets.py +79 -0
  501. cartography/models/kubernetes/serviceaccounts.py +77 -0
  502. cartography/models/kubernetes/services.py +108 -0
  503. cartography/models/kubernetes/users.py +105 -0
  504. cartography/models/lastpass/user.py +4 -0
  505. cartography/models/ontology/__init__.py +0 -0
  506. cartography/models/ontology/device.py +137 -0
  507. cartography/models/ontology/mapping/__init__.py +76 -0
  508. cartography/models/ontology/mapping/data/__init__.py +0 -0
  509. cartography/models/ontology/mapping/data/apikeys.py +93 -0
  510. cartography/models/ontology/mapping/data/computeinstance.py +95 -0
  511. cartography/models/ontology/mapping/data/containers.py +88 -0
  512. cartography/models/ontology/mapping/data/databases.py +182 -0
  513. cartography/models/ontology/mapping/data/devices.py +194 -0
  514. cartography/models/ontology/mapping/data/thirdpartyapps.py +140 -0
  515. cartography/models/ontology/mapping/data/useraccounts.py +416 -0
  516. cartography/models/ontology/mapping/data/users.py +63 -0
  517. cartography/models/ontology/mapping/specs.py +85 -0
  518. cartography/models/ontology/user.py +51 -0
  519. cartography/models/openai/adminapikey.py +4 -0
  520. cartography/models/openai/apikey.py +4 -0
  521. cartography/models/openai/user.py +4 -0
  522. cartography/models/scaleway/__init__.py +0 -0
  523. cartography/models/scaleway/iam/__init__.py +0 -0
  524. cartography/models/scaleway/iam/apikey.py +100 -0
  525. cartography/models/scaleway/iam/application.py +52 -0
  526. cartography/models/scaleway/iam/group.py +95 -0
  527. cartography/models/scaleway/iam/user.py +64 -0
  528. cartography/models/scaleway/instance/__init__.py +0 -0
  529. cartography/models/scaleway/instance/flexibleip.py +52 -0
  530. cartography/models/scaleway/instance/instance.py +120 -0
  531. cartography/models/scaleway/organization.py +19 -0
  532. cartography/models/scaleway/project.py +48 -0
  533. cartography/models/scaleway/storage/__init__.py +0 -0
  534. cartography/models/scaleway/storage/snapshot.py +78 -0
  535. cartography/models/scaleway/storage/volume.py +51 -0
  536. cartography/models/sentinelone/__init__.py +1 -0
  537. cartography/models/sentinelone/account.py +40 -0
  538. cartography/models/sentinelone/agent.py +50 -0
  539. cartography/models/sentinelone/application.py +44 -0
  540. cartography/models/sentinelone/application_version.py +96 -0
  541. cartography/models/sentinelone/cve.py +73 -0
  542. cartography/models/slack/__init__.py +0 -0
  543. cartography/models/slack/channels.py +92 -0
  544. cartography/models/slack/group.py +129 -0
  545. cartography/models/slack/team.py +22 -0
  546. cartography/models/slack/user.py +62 -0
  547. cartography/models/snipeit/asset.py +2 -0
  548. cartography/models/snipeit/user.py +4 -0
  549. cartography/models/spacelift/__init__.py +0 -0
  550. cartography/models/spacelift/cloudtrailevent.py +120 -0
  551. cartography/models/spacelift/run.py +162 -0
  552. cartography/models/spacelift/space.py +131 -0
  553. cartography/models/spacelift/spaceliftaccount.py +31 -0
  554. cartography/models/spacelift/spaceliftgitcommit.py +157 -0
  555. cartography/models/spacelift/stack.py +96 -0
  556. cartography/models/spacelift/user.py +63 -0
  557. cartography/models/spacelift/worker.py +97 -0
  558. cartography/models/spacelift/workerpool.py +90 -0
  559. cartography/models/tailscale/device.py +2 -1
  560. cartography/models/tailscale/user.py +6 -1
  561. cartography/models/trivy/__init__.py +0 -0
  562. cartography/models/trivy/findings.py +66 -0
  563. cartography/models/trivy/fix.py +66 -0
  564. cartography/models/trivy/package.py +71 -0
  565. cartography/rules/README.md +1 -0
  566. cartography/rules/__init__.py +0 -0
  567. cartography/rules/cli.py +261 -0
  568. cartography/rules/data/__init__.py +0 -0
  569. cartography/rules/data/rules/__init__.py +46 -0
  570. cartography/rules/data/rules/cloud_security_product_deactivated.py +49 -0
  571. cartography/rules/data/rules/compute_instance_exposed.py +51 -0
  572. cartography/rules/data/rules/database_instance_exposed.py +53 -0
  573. cartography/rules/data/rules/delegation_boundary_modifiable.py +90 -0
  574. cartography/rules/data/rules/identity_administration_privileges.py +100 -0
  575. cartography/rules/data/rules/inactive_user_active_accounts.py +48 -0
  576. cartography/rules/data/rules/malicious_npm_dependencies_shai_hulud.py +2222 -0
  577. cartography/rules/data/rules/mfa_missing.py +46 -0
  578. cartography/rules/data/rules/object_storage_public.py +100 -0
  579. cartography/rules/data/rules/policy_administration_privileges.py +104 -0
  580. cartography/rules/data/rules/unmanaged_accounts.py +43 -0
  581. cartography/rules/data/rules/workload_identity_admin_capabilities.py +193 -0
  582. cartography/rules/formatters.py +108 -0
  583. cartography/rules/runners.py +216 -0
  584. cartography/rules/spec/__init__.py +0 -0
  585. cartography/rules/spec/model.py +267 -0
  586. cartography/rules/spec/result.py +38 -0
  587. cartography/sync.py +25 -5
  588. cartography/util.py +101 -31
  589. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/METADATA +61 -22
  590. cartography-0.123.0.dist-info/RECORD +856 -0
  591. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/entry_points.txt +1 -0
  592. cartography/data/jobs/cleanup/aws_dns_cleanup.json +0 -65
  593. cartography/data/jobs/cleanup/aws_import_account_access_key_cleanup.json +0 -17
  594. cartography/data/jobs/cleanup/aws_import_ec2_security_groupinfo_cleanup.json +0 -24
  595. cartography/data/jobs/cleanup/aws_import_groups_cleanup.json +0 -13
  596. cartography/data/jobs/cleanup/aws_import_identity_center_cleanup.json +0 -16
  597. cartography/data/jobs/cleanup/aws_import_lambda_cleanup.json +0 -50
  598. cartography/data/jobs/cleanup/aws_import_principals_cleanup.json +0 -30
  599. cartography/data/jobs/cleanup/aws_import_rds_clusters_cleanup.json +0 -23
  600. cartography/data/jobs/cleanup/aws_import_rds_instances_cleanup.json +0 -47
  601. cartography/data/jobs/cleanup/aws_import_rds_snapshots_cleanup.json +0 -23
  602. cartography/data/jobs/cleanup/aws_import_roles_cleanup.json +0 -13
  603. cartography/data/jobs/cleanup/aws_import_secrets_cleanup.json +0 -8
  604. cartography/data/jobs/cleanup/aws_import_snapshots_cleanup.json +0 -30
  605. cartography/data/jobs/cleanup/aws_import_users_cleanup.json +0 -8
  606. cartography/data/jobs/cleanup/aws_import_vpc_cleanup.json +0 -23
  607. cartography/data/jobs/cleanup/aws_import_vpc_peering_cleanup.json +0 -45
  608. cartography/data/jobs/cleanup/aws_kms_details.json +0 -10
  609. cartography/data/jobs/cleanup/azure_cosmosdb_cassandra_keyspace_cleanup.json +0 -25
  610. cartography/data/jobs/cleanup/azure_cosmosdb_cors_details.json +0 -15
  611. cartography/data/jobs/cleanup/azure_cosmosdb_mongodb_database_cleanup.json +0 -25
  612. cartography/data/jobs/cleanup/azure_cosmosdb_sql_database_cleanup.json +0 -25
  613. cartography/data/jobs/cleanup/azure_cosmosdb_table_resources_cleanup.json +0 -15
  614. cartography/data/jobs/cleanup/azure_database_account_cleanup.json +0 -85
  615. cartography/data/jobs/cleanup/azure_import_disks_cleanup.json +0 -15
  616. cartography/data/jobs/cleanup/azure_import_snapshots_cleanup.json +0 -15
  617. cartography/data/jobs/cleanup/azure_import_virtual_machines_cleanup.json +0 -25
  618. cartography/data/jobs/cleanup/azure_sql_server_cleanup.json +0 -125
  619. cartography/data/jobs/cleanup/azure_storage_account_cleanup.json +0 -95
  620. cartography/data/jobs/cleanup/azure_subscriptions_cleanup.json +0 -14
  621. cartography/data/jobs/cleanup/azure_tenant_cleanup.json +0 -9
  622. cartography/data/jobs/cleanup/gcp_compute_vpc_subnet_cleanup.json +0 -35
  623. cartography/data/jobs/cleanup/gcp_crm_folder_cleanup.json +0 -23
  624. cartography/data/jobs/cleanup/gcp_crm_organization_cleanup.json +0 -17
  625. cartography/data/jobs/cleanup/gcp_crm_project_cleanup.json +0 -23
  626. cartography/data/jobs/cleanup/gcp_dns_cleanup.json +0 -29
  627. cartography/data/jobs/cleanup/gcp_gke_cluster_cleanup.json +0 -17
  628. cartography/data/jobs/cleanup/gcp_storage_bucket_cleanup.json +0 -29
  629. cartography/data/jobs/cleanup/gsuite_ingest_groups_cleanup.json +0 -23
  630. cartography/data/jobs/cleanup/gsuite_ingest_users_cleanup.json +0 -11
  631. cartography/data/jobs/cleanup/kubernetes_import_cleanup.json +0 -70
  632. cartography/intel/gcp/crm.py +0 -355
  633. cartography/intel/gsuite/api.py +0 -342
  634. cartography-0.104.0rc2.dist-info/RECORD +0 -455
  635. /cartography/data/jobs/{analysis → scoped_analysis}/aws_s3acl_analysis.json +0 -0
  636. /cartography/models/aws/{apigateway.py → apigateway/apigateway.py} +0 -0
  637. /cartography/models/aws/{apigatewaycertificate.py → apigateway/apigatewaycertificate.py} +0 -0
  638. /cartography/models/aws/{apigatewayresource.py → apigateway/apigatewayresource.py} +0 -0
  639. /cartography/models/aws/{apigatewaystage.py → apigateway/apigatewaystage.py} +0 -0
  640. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/WHEEL +0 -0
  641. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/licenses/LICENSE +0 -0
  642. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,140 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import neo4j
5
+
6
+ from cartography.client.core.tx import load
7
+ from cartography.intel.sentinelone.api import call_sentinelone_api
8
+ from cartography.models.sentinelone.account import S1AccountSchema
9
+ from cartography.util import timeit
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ @timeit
15
+ def get_accounts(
16
+ api_url: str, api_token: str, account_ids: list[str] | None = None
17
+ ) -> list[dict[str, Any]]:
18
+ """
19
+ Get account data from SentinelOne API
20
+ :param api_url: The SentinelOne API URL
21
+ :param api_token: The SentinelOne API token
22
+ :param account_ids: Optional list of account IDs to filter for
23
+ :return: Raw account data from API
24
+ """
25
+ logger.info("Retrieving SentinelOne account data")
26
+
27
+ # Get accounts info
28
+ response = call_sentinelone_api(
29
+ api_url=api_url,
30
+ endpoint="web/api/v2.1/accounts",
31
+ api_token=api_token,
32
+ )
33
+
34
+ accounts_data = response.get("data", [])
35
+
36
+ # Filter accounts by ID if specified
37
+ if account_ids:
38
+ accounts_data = [
39
+ account for account in accounts_data if account.get("id") in account_ids
40
+ ]
41
+ logger.info(f"Filtered accounts data to {len(accounts_data)} matching accounts")
42
+
43
+ if accounts_data:
44
+ logger.info(
45
+ f"Retrieved SentinelOne account data: {len(accounts_data)} accounts"
46
+ )
47
+ else:
48
+ logger.warning("No SentinelOne accounts retrieved")
49
+
50
+ return accounts_data
51
+
52
+
53
+ def transform_accounts(accounts_data: list[dict[str, Any]]) -> list[dict[str, Any]]:
54
+ """
55
+ Transform raw account data into standardized format for Neo4j ingestion
56
+ :param accounts_data: Raw account data from API
57
+ :return: List of transformed account data
58
+ """
59
+ result: list[dict[str, Any]] = []
60
+
61
+ for account in accounts_data:
62
+ transformed_account = {
63
+ # Required fields - use direct access (will raise KeyError if missing)
64
+ "id": account["id"],
65
+ # Optional fields - use .get() with None default
66
+ "name": account.get("name"),
67
+ "account_type": account.get("accountType"),
68
+ "active_agents": account.get("activeAgents"),
69
+ "created_at": account.get("createdAt"),
70
+ "expiration": account.get("expiration"),
71
+ "number_of_sites": account.get("numberOfSites"),
72
+ "state": account.get("state"),
73
+ }
74
+ result.append(transformed_account)
75
+
76
+ return result
77
+
78
+
79
+ def load_accounts(
80
+ neo4j_session: neo4j.Session,
81
+ accounts_data: list[dict[str, Any]],
82
+ update_tag: int,
83
+ ) -> None:
84
+ """
85
+ Load SentinelOne account data into Neo4j using the data model
86
+ :param neo4j_session: Neo4j session
87
+ :param accounts_data: List of account data to load
88
+ :param update_tag: Update tag for tracking data freshness
89
+ """
90
+ if not accounts_data:
91
+ logger.warning("No account data provided to load_accounts")
92
+ return
93
+
94
+ load(
95
+ neo4j_session,
96
+ S1AccountSchema(),
97
+ accounts_data,
98
+ lastupdated=update_tag,
99
+ firstseen=update_tag,
100
+ )
101
+
102
+ logger.info(f"Loaded {len(accounts_data)} SentinelOne account nodes")
103
+
104
+
105
+ @timeit
106
+ def sync_accounts(
107
+ neo4j_session: neo4j.Session,
108
+ common_job_parameters: dict[str, Any],
109
+ account_ids: list[str] | None = None,
110
+ ) -> list[str]:
111
+ """
112
+ Sync SentinelOne account data using the modern sync pattern
113
+ :param neo4j_session: Neo4j session
114
+ :param api_url: SentinelOne API URL
115
+ :param api_token: SentinelOne API token
116
+ :param update_tag: Update tag for tracking data freshness
117
+ :param common_job_parameters: Job parameters for cleanup
118
+ :param account_ids: Optional list of account IDs to filter for
119
+ :return: List of synced account IDs
120
+ """
121
+ # 1. GET - Fetch data from API
122
+ accounts_raw_data = get_accounts(
123
+ common_job_parameters["API_URL"],
124
+ common_job_parameters["API_TOKEN"],
125
+ account_ids,
126
+ )
127
+
128
+ # 2. TRANSFORM - Shape data for ingestion
129
+ transformed_accounts = transform_accounts(accounts_raw_data)
130
+
131
+ # 3. LOAD - Ingest to Neo4j using data model
132
+ load_accounts(
133
+ neo4j_session,
134
+ transformed_accounts,
135
+ common_job_parameters["UPDATE_TAG"],
136
+ )
137
+
138
+ synced_account_ids = [account["id"] for account in transformed_accounts]
139
+ logger.info(f"Synced {len(synced_account_ids)} SentinelOne accounts")
140
+ return synced_account_ids
@@ -0,0 +1,139 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import neo4j
5
+
6
+ from cartography.client.core.tx import load
7
+ from cartography.graph.job import GraphJob
8
+ from cartography.intel.sentinelone.api import get_paginated_results
9
+ from cartography.models.sentinelone.agent import S1AgentSchema
10
+ from cartography.util import timeit
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ @timeit
16
+ def get_agents(api_url: str, api_token: str, account_id: str) -> list[dict[str, Any]]:
17
+ """
18
+ Get agent data from SentinelOne API
19
+ :param api_url: The SentinelOne API URL
20
+ :param api_token: The SentinelOne API token
21
+ :param account_id: The SentinelOne account ID
22
+ :return: Raw agent data from API
23
+ """
24
+ logger.info(f"Retrieving SentinelOne agent data for account {account_id}")
25
+
26
+ agents = get_paginated_results(
27
+ api_url=api_url,
28
+ endpoint="web/api/v2.1/agents",
29
+ api_token=api_token,
30
+ params={
31
+ "accountIds": account_id,
32
+ "limit": 1000,
33
+ },
34
+ )
35
+
36
+ logger.info(f"Retrieved {len(agents)} agents from SentinelOne account {account_id}")
37
+ return agents
38
+
39
+
40
+ @timeit
41
+ def transform_agents(agent_list: list[dict[str, Any]]) -> list[dict[str, Any]]:
42
+ """
43
+ Transform SentinelOne agent data for loading into Neo4j
44
+ :param agent_list: Raw agent data from the API
45
+ :return: Transformed agent data
46
+ """
47
+ result: list[dict[str, Any]] = []
48
+
49
+ for agent in agent_list:
50
+ transformed_agent = {
51
+ # Required fields - use direct access (will raise KeyError if missing)
52
+ "id": agent["id"],
53
+ # Optional fields - use .get() with None default
54
+ "uuid": agent.get("uuid"),
55
+ "computer_name": agent.get("computerName"),
56
+ "firewall_enabled": agent.get("firewallEnabled"),
57
+ "os_name": agent.get("osName"),
58
+ "os_revision": agent.get("osRevision"),
59
+ "domain": agent.get("domain"),
60
+ "last_active": agent.get("lastActiveDate"),
61
+ "last_successful_scan": agent.get("lastSuccessfulScanDate"),
62
+ "scan_status": agent.get("scanStatus"),
63
+ "serial_number": agent.get("serialNumber"),
64
+ }
65
+ result.append(transformed_agent)
66
+
67
+ return result
68
+
69
+
70
+ @timeit
71
+ def load_agents(
72
+ neo4j_session: neo4j.Session,
73
+ data: list[dict[str, Any]],
74
+ account_id: str,
75
+ update_tag: int,
76
+ ) -> None:
77
+ """
78
+ Load SentinelOne agent data into Neo4j
79
+ :param neo4j_session: Neo4j session
80
+ :param data: The transformed agent data
81
+ :param account_id: The SentinelOne account ID
82
+ :param update_tag: Update tag for tracking data freshness
83
+ :return: None
84
+ """
85
+ logger.info(
86
+ f"Loading {len(data)} SentinelOne agents into Neo4j for account {account_id}"
87
+ )
88
+ load(
89
+ neo4j_session,
90
+ S1AgentSchema(),
91
+ data,
92
+ lastupdated=update_tag,
93
+ S1_ACCOUNT_ID=account_id,
94
+ )
95
+
96
+
97
+ @timeit
98
+ def cleanup(
99
+ neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
100
+ ) -> None:
101
+ """
102
+ Remove stale SentinelOne agent data from Neo4j
103
+ :param neo4j_session: Neo4j session
104
+ :param common_job_parameters: Common job parameters for cleanup
105
+ :return: None
106
+ """
107
+ logger.debug("Running S1Agent cleanup job")
108
+ GraphJob.from_node_schema(S1AgentSchema(), common_job_parameters).run(neo4j_session)
109
+
110
+
111
+ @timeit
112
+ def sync(
113
+ neo4j_session: neo4j.Session,
114
+ common_job_parameters: dict[str, Any],
115
+ ) -> None:
116
+ """
117
+ Sync SentinelOne agents using the standard sync pattern
118
+ :param neo4j_session: Neo4j session
119
+ :param common_job_parameters: Common job parameters containing API_URL, API_TOKEN, S1_ACCOUNT_ID, UPDATE_TAG
120
+ :return: None
121
+ """
122
+ api_url = common_job_parameters["API_URL"]
123
+ api_token = common_job_parameters["API_TOKEN"]
124
+ account_id = common_job_parameters["S1_ACCOUNT_ID"]
125
+ update_tag = common_job_parameters["UPDATE_TAG"]
126
+
127
+ logger.info(f"Syncing SentinelOne agent data for account {account_id}")
128
+
129
+ # 1. GET - Fetch data from API
130
+ agents_raw_data = get_agents(api_url, api_token, account_id)
131
+
132
+ # 2. TRANSFORM - Shape data for ingestion
133
+ transformed_data = transform_agents(agents_raw_data)
134
+
135
+ # 3. LOAD - Ingest to Neo4j using data model
136
+ load_agents(neo4j_session, transformed_data, account_id, update_tag)
137
+
138
+ # 4. CLEANUP - Remove stale data
139
+ cleanup(neo4j_session, common_job_parameters)
@@ -0,0 +1,124 @@
1
+ from typing import Any
2
+
3
+ import requests
4
+
5
+ from cartography.util import backoff_handler
6
+ from cartography.util import retries_with_backoff
7
+
8
+ # Connect and read timeouts of 60 seconds each
9
+ _TIMEOUT = (60, 60)
10
+
11
+
12
+ def _call_sentinelone_api_base(
13
+ api_url: str,
14
+ endpoint: str,
15
+ api_token: str,
16
+ method: str = "GET",
17
+ params: dict[str, Any] | None = None,
18
+ data: dict[str, Any] | None = None,
19
+ ) -> dict[str, Any]:
20
+ """
21
+ Call the SentinelOne API
22
+ :param api_url: The base URL for the SentinelOne API
23
+ :param endpoint: The API endpoint to call
24
+ :param api_token: The API token for authentication
25
+ :param method: The HTTP method to use (default is GET)
26
+ :param params: Query parameters to include in the request
27
+ :param data: Data to include in the request body for POST/PUT methods
28
+ :return: The JSON response from the API
29
+ """
30
+ full_url = f"{api_url.rstrip('/')}/{endpoint.lstrip('/')}"
31
+
32
+ headers = {
33
+ "Accept": "application/json",
34
+ "Authorization": f"ApiToken {api_token}",
35
+ "Content-Type": "application/json",
36
+ }
37
+
38
+ response = requests.request(
39
+ method=method,
40
+ url=full_url,
41
+ headers=headers,
42
+ params=params,
43
+ json=data,
44
+ timeout=_TIMEOUT,
45
+ )
46
+
47
+ # Raise an exception for HTTP errors (this will be caught by backoff wrapper)
48
+ response.raise_for_status()
49
+
50
+ return response.json()
51
+
52
+
53
+ def call_sentinelone_api(
54
+ api_url: str,
55
+ endpoint: str,
56
+ api_token: str,
57
+ method: str = "GET",
58
+ params: dict[str, Any] | None = None,
59
+ data: dict[str, Any] | None = None,
60
+ ) -> dict[str, Any]:
61
+ """
62
+ Call the SentinelOne API with backoff functionality
63
+ :param api_url: The base URL for the SentinelOne API
64
+ :param endpoint: The API endpoint to call
65
+ :param api_token: The API token for authentication
66
+ :param method: The HTTP method to use (default is GET)
67
+ :param params: Query parameters to include in the request
68
+ :param data: Data to include in the request body for POST/PUT methods
69
+ :return: The JSON response from the API
70
+ """
71
+ wrapped_func = retries_with_backoff(
72
+ func=_call_sentinelone_api_base,
73
+ exception_type=requests.exceptions.RequestException, # Covers Timeout and HTTPError as subclasses
74
+ max_tries=5, # Maximum number of retry attempts
75
+ on_backoff=backoff_handler,
76
+ )
77
+ return wrapped_func(api_url, endpoint, api_token, method, params, data)
78
+
79
+
80
+ def get_paginated_results(
81
+ api_url: str,
82
+ endpoint: str,
83
+ api_token: str,
84
+ params: dict[str, Any] | None = None,
85
+ ) -> list[dict[str, Any]]:
86
+ """
87
+ Handle cursor-based pagination for SentinelOne API requests
88
+ :param api_url: The base URL for the SentinelOne API
89
+ :param endpoint: The API endpoint to call
90
+ :param api_token: The API token for authentication
91
+ :param params: Query parameters to include in the request
92
+ :return: A list of all items from all pages
93
+ """
94
+ query_params = params or {}
95
+
96
+ # Set default pagination parameters if not provided
97
+ if "limit" not in query_params:
98
+ query_params["limit"] = 100
99
+
100
+ next_cursor = None
101
+ total_items = []
102
+
103
+ while True:
104
+ if next_cursor:
105
+ query_params["cursor"] = next_cursor
106
+
107
+ response = call_sentinelone_api(
108
+ api_url=api_url,
109
+ endpoint=endpoint,
110
+ api_token=api_token,
111
+ params=query_params,
112
+ )
113
+
114
+ items = response.get("data", [])
115
+ if not items:
116
+ break
117
+
118
+ total_items.extend(items)
119
+ pagination = response.get("pagination", {})
120
+ next_cursor = pagination.get("nextCursor")
121
+ if not next_cursor:
122
+ break
123
+
124
+ return total_items
@@ -0,0 +1,248 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import neo4j
5
+
6
+ from cartography.client.core.tx import load
7
+ from cartography.graph.job import GraphJob
8
+ from cartography.intel.sentinelone.api import get_paginated_results
9
+ from cartography.intel.sentinelone.utils import get_application_id
10
+ from cartography.intel.sentinelone.utils import get_application_version_id
11
+ from cartography.models.sentinelone.application import S1ApplicationSchema
12
+ from cartography.models.sentinelone.application_version import (
13
+ S1ApplicationVersionSchema,
14
+ )
15
+ from cartography.util import timeit
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ @timeit
21
+ def get_application_data(
22
+ account_id: str, api_url: str, api_token: str
23
+ ) -> list[dict[str, Any]]:
24
+ """
25
+ Get application data from SentinelOne API
26
+ :param account_id: SentinelOne account ID
27
+ :param api_url: SentinelOne API URL
28
+ :param api_token: SentinelOne API token
29
+ :return: A list of application data dictionaries
30
+ """
31
+ logger.info(f"Retrieving SentinelOne application data for account {account_id}")
32
+ applications = get_paginated_results(
33
+ api_url=api_url,
34
+ endpoint="/web/api/v2.1/application-management/inventory",
35
+ api_token=api_token,
36
+ params={
37
+ "accountIds": account_id,
38
+ "limit": 1000,
39
+ },
40
+ )
41
+
42
+ logger.info(f"Retrieved {len(applications)} applications from SentinelOne")
43
+ return applications
44
+
45
+
46
+ @timeit
47
+ def get_application_installs(
48
+ app_inventory: list[dict[str, Any]], account_id: str, api_url: str, api_token: str
49
+ ) -> list[dict[str, Any]]:
50
+ """
51
+ Get application installs from SentinelOne API
52
+ :param app_inventory: List of applications to get installs for
53
+ :param account_id: SentinelOne account ID
54
+ :param api_url: SentinelOne API URL
55
+ :param api_token: SentinelOne API token
56
+ :return: A list of application installs data dictionaries
57
+ """
58
+ logger.info(
59
+ f"Retrieving SentinelOne application installs for "
60
+ f"{len(app_inventory)} applications in account "
61
+ f"{account_id}",
62
+ )
63
+
64
+ application_installs = []
65
+ for i, app in enumerate(app_inventory):
66
+ logger.info(
67
+ f"Retrieving SentinelOne installs for {app.get('applicationName')} "
68
+ f"{app.get('applicationVendor')} ({i + 1}/{len(app_inventory)})",
69
+ )
70
+ name = app["applicationName"]
71
+ vendor = app["applicationVendor"]
72
+ app_installs = get_paginated_results(
73
+ api_url=api_url,
74
+ endpoint="/web/api/v2.1/application-management/inventory/endpoints",
75
+ api_token=api_token,
76
+ params={
77
+ "accountIds": account_id,
78
+ "limit": 1000,
79
+ "applicationName": name,
80
+ "applicationVendor": vendor,
81
+ },
82
+ )
83
+
84
+ # Replace applicationVendor and applicationName with original values
85
+ # for consistency with the application data
86
+ for app_install in app_installs:
87
+ app_install["applicationVendor"] = vendor
88
+ app_install["applicationName"] = name
89
+ application_installs.extend(app_installs)
90
+
91
+ return application_installs
92
+
93
+
94
+ def transform_applications(
95
+ applications_list: list[dict[str, Any]],
96
+ ) -> list[dict[str, Any]]:
97
+ """
98
+ Transform SentinelOne application data for loading into Neo4j
99
+ :param applications_list: Raw application data from the API
100
+ :return: Transformed application data
101
+ """
102
+ transformed_data = []
103
+ for app in applications_list:
104
+ vendor = app["applicationVendor"].strip()
105
+ name = app["applicationName"].strip()
106
+ app_id = get_application_id(name, vendor)
107
+ transformed_app = {
108
+ "id": app_id,
109
+ "name": name,
110
+ "vendor": vendor,
111
+ }
112
+ transformed_data.append(transformed_app)
113
+
114
+ return transformed_data
115
+
116
+
117
+ def transform_application_versions(
118
+ application_installs_list: list[dict[str, Any]],
119
+ ) -> list[dict[str, Any]]:
120
+ """
121
+ Transform SentinelOne application installs for loading into Neo4j
122
+ :param application_installs_list: Raw application installs data from the API
123
+ :return: Transformed application installs data
124
+ """
125
+ transformed_data = []
126
+ for installed_version in application_installs_list:
127
+ app_name = installed_version["applicationName"]
128
+ app_vendor = installed_version["applicationVendor"]
129
+ version = installed_version.get("version") or "unknown"
130
+
131
+ transformed_version = {
132
+ "id": get_application_version_id(
133
+ app_name,
134
+ app_vendor,
135
+ version,
136
+ ),
137
+ "application_id": get_application_id(
138
+ app_name,
139
+ app_vendor,
140
+ ),
141
+ "application_name": app_name,
142
+ "application_vendor": app_vendor,
143
+ "agent_uuid": installed_version.get("endpointUuid"),
144
+ "installation_path": installed_version.get("applicationInstallationPath"),
145
+ "installed_dt": installed_version.get("applicationInstallationDate"),
146
+ "version": version,
147
+ }
148
+ transformed_data.append(transformed_version)
149
+
150
+ return transformed_data
151
+
152
+
153
+ @timeit
154
+ def load_application_data(
155
+ neo4j_session: neo4j.Session,
156
+ data: list[dict[str, Any]],
157
+ account_id: str,
158
+ update_tag: int,
159
+ ) -> None:
160
+ """
161
+ Load SentinelOne application data into Neo4j
162
+ :param neo4j_session: Neo4j session
163
+ :param data: The transformed application data
164
+ :param account_id: The SentinelOne account ID
165
+ :param update_tag: Update tag to set on the nodes
166
+ :return: None
167
+ """
168
+ logger.info(f"Loading {len(data)} SentinelOne applications into Neo4j")
169
+ load(
170
+ neo4j_session,
171
+ S1ApplicationSchema(),
172
+ data,
173
+ lastupdated=update_tag,
174
+ S1_ACCOUNT_ID=account_id,
175
+ )
176
+
177
+
178
+ @timeit
179
+ def load_application_versions(
180
+ neo4j_session: neo4j.Session,
181
+ data: list[dict[str, Any]],
182
+ account_id: str,
183
+ update_tag: int,
184
+ ) -> None:
185
+ logger.info(f"Loading {len(data)} SentinelOne application versions into Neo4j")
186
+ load(
187
+ neo4j_session,
188
+ S1ApplicationVersionSchema(),
189
+ data,
190
+ lastupdated=update_tag,
191
+ S1_ACCOUNT_ID=account_id,
192
+ )
193
+
194
+
195
+ @timeit
196
+ def cleanup(
197
+ neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
198
+ ) -> None:
199
+ logger.debug("Running SentinelOne S1Application cleanup")
200
+ GraphJob.from_node_schema(S1ApplicationSchema(), common_job_parameters).run(
201
+ neo4j_session
202
+ )
203
+ logger.debug("Running SentinelOne S1ApplicationVersion cleanup")
204
+ GraphJob.from_node_schema(S1ApplicationVersionSchema(), common_job_parameters).run(
205
+ neo4j_session
206
+ )
207
+
208
+
209
+ @timeit
210
+ def sync(
211
+ neo4j_session: neo4j.Session,
212
+ common_job_parameters: dict[str, Any],
213
+ ) -> None:
214
+ """
215
+ Sync SentinelOne applications
216
+ :param neo4j_session: Neo4j session
217
+ :param common_job_parameters: Common job parameters containing API_URL, API_TOKEN, etc.
218
+ :return: None
219
+ """
220
+ logger.info("Syncing SentinelOne application data")
221
+ account_id = str(common_job_parameters["S1_ACCOUNT_ID"])
222
+ api_url = str(common_job_parameters["API_URL"])
223
+ api_token = str(common_job_parameters["API_TOKEN"])
224
+
225
+ applications = get_application_data(account_id, api_url, api_token)
226
+ application_versions = get_application_installs(
227
+ applications, account_id, api_url, api_token
228
+ )
229
+ transformed_applications = transform_applications(applications)
230
+ transformed_application_versions = transform_application_versions(
231
+ application_versions
232
+ )
233
+
234
+ load_application_data(
235
+ neo4j_session,
236
+ transformed_applications,
237
+ account_id,
238
+ common_job_parameters["UPDATE_TAG"],
239
+ )
240
+
241
+ load_application_versions(
242
+ neo4j_session,
243
+ transformed_application_versions,
244
+ account_id,
245
+ common_job_parameters["UPDATE_TAG"],
246
+ )
247
+
248
+ cleanup(neo4j_session, common_job_parameters)