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
@@ -19,6 +19,7 @@
19
19
  "iterative": true,
20
20
  "iterationsize": 100
21
21
  },
22
+
22
23
  {
23
24
  "query": "MATCH (:GitHubBranch)-[r:BRANCH]->(:GitHubRepository) WHERE r.lastupdated <> $UPDATE_TAG WITH r LIMIT $LIMIT_SIZE DELETE (r)",
24
25
  "iterative": true,
@@ -39,6 +40,7 @@
39
40
  "iterative": true,
40
41
  "iterationsize": 100
41
42
  },
43
+
42
44
  {
43
45
  "query": "MATCH (:GitHubUser)-[r:OUTSIDE_COLLAB_ADMIN]->(:GitHubRepository) WHERE r.lastupdated <> $UPDATE_TAG WITH r LIMIT $LIMIT_SIZE DELETE (r)",
44
46
  "iterative": true,
@@ -63,8 +63,9 @@ class CLI:
63
63
  default="bolt://localhost:7687",
64
64
  help=(
65
65
  "A valid Neo4j URI to sync against. See "
66
- "https://neo4j.com/docs/api/python-driver/current/driver.html#uri for complete documentation on the "
67
- "structure of a Neo4j URI."
66
+ "https://neo4j.com/docs/browser-manual/current/operations/dbms-connection/#uri-scheme for "
67
+ "documentation on the structure of a Neo4j URI, and "
68
+ "https://neo4j.com/docs/api/python-driver/current/ for complete documentation on the Python driver."
68
69
  ),
69
70
  )
70
71
  parser_get_state.add_argument(
@@ -3,6 +3,7 @@ from string import Template
3
3
  from typing import Dict
4
4
  from typing import List
5
5
 
6
+ from cartography.graph.querybuilder import _asdict_with_validate_relprops
6
7
  from cartography.graph.querybuilder import _build_match_clause
7
8
  from cartography.graph.querybuilder import rel_present_on_node_schema
8
9
  from cartography.models.core.common import PropertyRef
@@ -15,33 +16,40 @@ from cartography.models.core.relationships import TargetNodeMatcher
15
16
  def build_cleanup_queries(node_schema: CartographyNodeSchema) -> List[str]:
16
17
  """
17
18
  Generates queries to clean up stale nodes and relationships from the given CartographyNodeSchema.
19
+ Properly handles cases where a node schema has a scoped cleanup or not.
18
20
  Note that auto-cleanups for a node with no relationships is not currently supported.
19
-
20
- Algorithm:
21
- 1. If node_schema has no relationships at all, return empty.
22
-
23
- Otherwise,
24
-
25
- 1. If node_schema doesn't have a sub_resource relationship, generate queries only to clean up its other
26
- relationships. No nodes will be cleaned up.
27
-
28
- Otherwise,
29
-
30
- 1. First delete all stale nodes attached to the node_schema's sub resource
31
- 2. Delete all stale node to sub resource relationships
32
- - We don't expect this to be very common (never for AWS resources, at least), but in case it is possible for an
33
- asset to change sub resources, we want to handle it properly.
34
- 3. For all relationships defined on the node schema, delete all stale ones.
35
21
  :param node_schema: The given CartographyNodeSchema
36
22
  :return: A list of Neo4j queries to clean up nodes and relationships.
37
23
  """
24
+ # If the node has no relationships, do not delete the node. Leave this behind for the user to manage.
25
+ # Oftentimes these are SyncMetadata nodes.
38
26
  if (
39
27
  not node_schema.sub_resource_relationship
40
28
  and not node_schema.other_relationships
41
29
  ):
42
30
  return []
43
31
 
44
- if not node_schema.sub_resource_relationship:
32
+ # Case 1 [Standard]: the node has a sub resource and scoped cleanup is true => clean up stale nodes
33
+ # of this type, scoped to the sub resource. Continue on to clean up the other_relationships too.
34
+ if node_schema.sub_resource_relationship and node_schema.scoped_cleanup:
35
+ queries = _build_cleanup_node_and_rel_queries(
36
+ node_schema,
37
+ node_schema.sub_resource_relationship,
38
+ )
39
+
40
+ # Case 2: The node has a sub resource but scoped cleanup is false => this does not make sense
41
+ # because if have a sub resource, we are implying that we are doing scoped cleanup.
42
+ elif node_schema.sub_resource_relationship and not node_schema.scoped_cleanup:
43
+ raise ValueError(
44
+ f"This is not expected: {node_schema.label} has a sub_resource_relationship but scoped_cleanup=False."
45
+ "Please check the class definition for this node schema. It doesn't make sense for a node to have a "
46
+ "sub resource relationship and an unscoped cleanup. Doing this will cause all stale nodes of this type "
47
+ "to be deleted regardless of the sub resource they are attached to."
48
+ )
49
+
50
+ # Case 3: The node has no sub resource but scoped cleanup is true => do not delete any nodes, but clean up stale relationships.
51
+ # Return early.
52
+ elif not node_schema.sub_resource_relationship and node_schema.scoped_cleanup:
45
53
  queries = []
46
54
  other_rels = (
47
55
  node_schema.other_relationships.rels
@@ -53,17 +61,20 @@ def build_cleanup_queries(node_schema: CartographyNodeSchema) -> List[str]:
53
61
  queries.append(query)
54
62
  return queries
55
63
 
56
- result = _build_cleanup_node_and_rel_queries(
57
- node_schema,
58
- node_schema.sub_resource_relationship,
59
- )
64
+ # Case 4: The node has no sub resource and scoped cleanup is false => clean up the stale nodes. Continue on to clean up the other_relationships too.
65
+ else:
66
+ queries = [_build_cleanup_node_query_unscoped(node_schema)]
67
+
60
68
  if node_schema.other_relationships:
61
69
  for rel in node_schema.other_relationships.rels:
62
- # [0] is the delete node query, [1] is the delete relationship query. We only want the latter.
63
- _, rel_query = _build_cleanup_node_and_rel_queries(node_schema, rel)
64
- result.append(rel_query)
70
+ if node_schema.scoped_cleanup:
71
+ # [0] is the delete node query, [1] is the delete relationship query. We only want the latter.
72
+ _, rel_query = _build_cleanup_node_and_rel_queries(node_schema, rel)
73
+ queries.append(rel_query)
74
+ else:
75
+ queries.append(_build_cleanup_rel_queries_unscoped(node_schema, rel))
65
76
 
66
- return result
77
+ return queries
67
78
 
68
79
 
69
80
  def _build_cleanup_rel_query_no_sub_resource(
@@ -94,6 +105,46 @@ def _build_cleanup_rel_query_no_sub_resource(
94
105
  )
95
106
 
96
107
 
108
+ def _build_match_statement_for_cleanup(node_schema: CartographyNodeSchema) -> str:
109
+ """
110
+ Helper function to build a MATCH statement for a given node schema for cleanup.
111
+ """
112
+ if not node_schema.sub_resource_relationship and not node_schema.scoped_cleanup:
113
+ template = Template("MATCH (n:$node_label)")
114
+ return template.safe_substitute(
115
+ node_label=node_schema.label,
116
+ )
117
+
118
+ # if it has a sub resource relationship defined, we need to match on the sub resource to make sure we only delete
119
+ # nodes that are attached to the sub resource.
120
+ template = Template(
121
+ "MATCH (n:$node_label)$sub_resource_link(:$sub_resource_label{$match_sub_res_clause})"
122
+ )
123
+ sub_resource_link = ""
124
+ sub_resource_label = ""
125
+ match_sub_res_clause = ""
126
+
127
+ if node_schema.sub_resource_relationship:
128
+ # Draw sub resource rel with correct direction
129
+ if node_schema.sub_resource_relationship.direction == LinkDirection.INWARD:
130
+ sub_resource_link_template = Template("<-[s:$SubResourceRelLabel]-")
131
+ else:
132
+ sub_resource_link_template = Template("-[s:$SubResourceRelLabel]->")
133
+ sub_resource_link = sub_resource_link_template.safe_substitute(
134
+ SubResourceRelLabel=node_schema.sub_resource_relationship.rel_label,
135
+ )
136
+ sub_resource_label = node_schema.sub_resource_relationship.target_node_label
137
+ match_sub_res_clause = _build_match_clause(
138
+ node_schema.sub_resource_relationship.target_node_matcher,
139
+ )
140
+ return template.safe_substitute(
141
+ node_label=node_schema.label,
142
+ sub_resource_link=sub_resource_link,
143
+ sub_resource_label=sub_resource_label,
144
+ match_sub_res_clause=match_sub_res_clause,
145
+ )
146
+
147
+
97
148
  def _build_cleanup_node_and_rel_queries(
98
149
  node_schema: CartographyNodeSchema,
99
150
  selected_relationship: CartographyRelSchema,
@@ -120,15 +171,6 @@ def _build_cleanup_node_and_rel_queries(
120
171
  "verify the node class definition for the relationships that it has.",
121
172
  )
122
173
 
123
- # Draw sub resource rel with correct direction
124
- if node_schema.sub_resource_relationship.direction == LinkDirection.INWARD:
125
- sub_resource_link_template = Template("<-[s:$SubResourceRelLabel]-")
126
- else:
127
- sub_resource_link_template = Template("-[s:$SubResourceRelLabel]->")
128
- sub_resource_link = sub_resource_link_template.safe_substitute(
129
- SubResourceRelLabel=node_schema.sub_resource_relationship.rel_label,
130
- )
131
-
132
174
  # The cleanup node query must always be before the cleanup rel query
133
175
  delete_action_clauses = [
134
176
  """
@@ -161,19 +203,14 @@ def _build_cleanup_node_and_rel_queries(
161
203
  # Ensure the node is attached to the sub resource and delete the node
162
204
  query_template = Template(
163
205
  """
164
- MATCH (n:$node_label)$sub_resource_link(:$sub_resource_label{$match_sub_res_clause})
206
+ $match_statement
165
207
  $selected_rel_clause
166
208
  $delete_action_clause
167
209
  """,
168
210
  )
169
211
  return [
170
212
  query_template.safe_substitute(
171
- node_label=node_schema.label,
172
- sub_resource_link=sub_resource_link,
173
- sub_resource_label=node_schema.sub_resource_relationship.target_node_label,
174
- match_sub_res_clause=_build_match_clause(
175
- node_schema.sub_resource_relationship.target_node_matcher,
176
- ),
213
+ match_statement=_build_match_statement_for_cleanup(node_schema),
177
214
  selected_rel_clause=(
178
215
  ""
179
216
  if selected_relationship == node_schema.sub_resource_relationship
@@ -185,6 +222,80 @@ def _build_cleanup_node_and_rel_queries(
185
222
  ]
186
223
 
187
224
 
225
+ def _build_cleanup_node_query_unscoped(
226
+ node_schema: CartographyNodeSchema,
227
+ ) -> str:
228
+ """
229
+ Generates a cleanup query for a node_schema to allow unscoped cleanup.
230
+ """
231
+ if node_schema.scoped_cleanup:
232
+ raise ValueError(
233
+ f"_build_cleanup_node_query_for_unscoped_cleanup() failed: '{node_schema.label}' does not have "
234
+ "scoped_cleanup=False, so we cannot generate a query to clean it up. Please verify that the class "
235
+ "definition is what you expect.",
236
+ )
237
+
238
+ # The cleanup node query must always be before the cleanup rel query
239
+ delete_action_clause = """
240
+ WHERE n.lastupdated <> $UPDATE_TAG
241
+ WITH n LIMIT $LIMIT_SIZE
242
+ DETACH DELETE n;
243
+ """
244
+
245
+ # Ensure the node is attached to the sub resource and delete the node
246
+ query_template = Template(
247
+ """
248
+ $match_statement
249
+ $delete_action_clause
250
+ """,
251
+ )
252
+ return query_template.safe_substitute(
253
+ match_statement=_build_match_statement_for_cleanup(node_schema),
254
+ delete_action_clause=delete_action_clause,
255
+ )
256
+
257
+
258
+ def _build_cleanup_rel_queries_unscoped(
259
+ node_schema: CartographyNodeSchema,
260
+ selected_relationship: CartographyRelSchema,
261
+ ) -> str:
262
+ """
263
+ Generates relationship cleanup query for a node_schema with scoped_cleanup=False.
264
+ """
265
+ if node_schema.scoped_cleanup:
266
+ raise ValueError(
267
+ f"_build_cleanup_node_and_rel_queries_unscoped() failed: '{node_schema.label}' does not have "
268
+ "scoped_cleanup=False, so we cannot generate a query to clean it up. Please verify that the class "
269
+ "definition is what you expect.",
270
+ )
271
+ if not rel_present_on_node_schema(node_schema, selected_relationship):
272
+ raise ValueError(
273
+ f"_build_cleanup_node_query(): Attempted to build cleanup query for node '{node_schema.label}' and "
274
+ f"relationship {selected_relationship.rel_label} but that relationship is not present on the node. Please "
275
+ "verify the node class definition for the relationships that it has.",
276
+ )
277
+
278
+ # The cleanup node query must always be before the cleanup rel query
279
+ delete_action_clause = """WHERE r.lastupdated <> $UPDATE_TAG
280
+ WITH r LIMIT $LIMIT_SIZE
281
+ DELETE r;
282
+ """
283
+
284
+ # Ensure the node is attached to the sub resource and delete the node
285
+ query_template = Template(
286
+ """
287
+ $match_statement
288
+ $selected_rel_clause
289
+ $delete_action_clause
290
+ """,
291
+ )
292
+ return query_template.safe_substitute(
293
+ match_statement=_build_match_statement_for_cleanup(node_schema),
294
+ selected_rel_clause=_build_selected_rel_clause(selected_relationship),
295
+ delete_action_clause=delete_action_clause,
296
+ )
297
+
298
+
188
299
  def _build_selected_rel_clause(selected_relationship: CartographyRelSchema) -> str:
189
300
  """
190
301
  Draw selected relationship with correct direction. Returns a string that looks like either
@@ -224,3 +335,49 @@ def _validate_target_node_matcher_for_cleanup_job(tgm: TargetNodeMatcher):
224
335
  f"{key} has set_in_kwargs=False, please check by reviewing the full stack trace to know which object"
225
336
  f"this message was raised from. Debug information: PropertyRef name = {prop_ref.name}.",
226
337
  )
338
+
339
+
340
+ def build_cleanup_query_for_matchlink(rel_schema: CartographyRelSchema) -> str:
341
+ """
342
+ Generates a cleanup query for a matchlink relationship.
343
+ :param rel_schema: The CartographyRelSchema object to generate a query. This CartographyRelSchema object
344
+ - Must have a source_node_matcher and source_node_label defined
345
+ - Must have a CartographyRelProperties object where _sub_resource_label and _sub_resource_id are defined
346
+ :return: A Neo4j query used to clean up stale matchlink relationships.
347
+ """
348
+ if not rel_schema.source_node_matcher:
349
+ raise ValueError(
350
+ f"No source node matcher found for {rel_schema.rel_label}; returning empty list."
351
+ )
352
+
353
+ query_template = Template(
354
+ """
355
+ MATCH (from:$source_node_label)$rel_direction[r:$rel_label]$rel_direction_end(to:$target_node_label)
356
+ WHERE r.lastupdated <> $UPDATE_TAG
357
+ AND r._sub_resource_label = $sub_resource_label
358
+ AND r._sub_resource_id = $sub_resource_id
359
+ WITH r LIMIT $LIMIT_SIZE
360
+ DELETE r;
361
+ """
362
+ )
363
+
364
+ # Determine which way to point the arrow. INWARD is toward the source, otherwise we go toward the target.
365
+ if rel_schema.direction == LinkDirection.INWARD:
366
+ rel_direction = "<-"
367
+ rel_direction_end = "-"
368
+ else:
369
+ rel_direction = "-"
370
+ rel_direction_end = "->"
371
+
372
+ # Small hack: avoid type-checking errors by converting the rel_schema to a dict.
373
+ rel_props_as_dict = _asdict_with_validate_relprops(rel_schema)
374
+
375
+ return query_template.safe_substitute(
376
+ source_node_label=rel_schema.source_node_label,
377
+ target_node_label=rel_schema.target_node_label,
378
+ rel_label=rel_schema.rel_label,
379
+ rel_direction=rel_direction,
380
+ rel_direction_end=rel_direction_end,
381
+ sub_resource_label=rel_props_as_dict["_sub_resource_label"],
382
+ sub_resource_id=rel_props_as_dict["_sub_resource_id"],
383
+ )
cartography/graph/job.py CHANGED
@@ -13,9 +13,11 @@ from typing import Union
13
13
  import neo4j
14
14
 
15
15
  from cartography.graph.cleanupbuilder import build_cleanup_queries
16
+ from cartography.graph.cleanupbuilder import build_cleanup_query_for_matchlink
16
17
  from cartography.graph.statement import get_job_shortname
17
18
  from cartography.graph.statement import GraphStatement
18
19
  from cartography.models.core.nodes import CartographyNodeSchema
20
+ from cartography.models.core.relationships import CartographyRelSchema
19
21
 
20
22
  logger = logging.getLogger(__name__)
21
23
 
@@ -123,11 +125,13 @@ class GraphJob:
123
125
  }
124
126
 
125
127
  @classmethod
126
- def from_json(cls, blob: str, short_name: Optional[str] = None) -> "GraphJob":
128
+ def from_json(
129
+ cls, blob: Union[str, dict], short_name: Optional[str] = None
130
+ ) -> "GraphJob":
127
131
  """
128
- Create a job from a JSON blob.
132
+ Create a job from a JSON dict or blob.
129
133
  """
130
- data: Dict = json.loads(blob)
134
+ data = json.loads(blob) if isinstance(blob, str) else blob
131
135
  statements = _get_statements_from_json(data, short_name)
132
136
  name = data["name"]
133
137
  return cls(name, statements, short_name)
@@ -137,11 +141,13 @@ class GraphJob:
137
141
  cls,
138
142
  node_schema: CartographyNodeSchema,
139
143
  parameters: Dict[str, Any],
144
+ iterationsize: int = 100,
140
145
  ) -> "GraphJob":
141
146
  """
142
147
  Create a cleanup job from a CartographyNodeSchema object.
143
148
  For a given node, the fields used in the node_schema.sub_resource_relationship.target_node_node_matcher.keys()
144
149
  must be provided as keys and values in the params dict.
150
+ :param iterationsize: The number of items to process in each iteration. Defaults to 100.
145
151
  """
146
152
  queries: List[str] = build_cleanup_queries(node_schema)
147
153
 
@@ -163,7 +169,7 @@ class GraphJob:
163
169
  query,
164
170
  parameters=parameters,
165
171
  iterative=True,
166
- iterationsize=100,
172
+ iterationsize=iterationsize,
167
173
  parent_job_name=node_schema.label,
168
174
  parent_job_sequence_num=idx,
169
175
  )
@@ -176,6 +182,48 @@ class GraphJob:
176
182
  node_schema.label,
177
183
  )
178
184
 
185
+ @classmethod
186
+ def from_matchlink(
187
+ cls,
188
+ rel_schema: CartographyRelSchema,
189
+ sub_resource_label: str,
190
+ sub_resource_id: str,
191
+ update_tag: int,
192
+ iterationsize: int = 100,
193
+ ) -> "GraphJob":
194
+ """
195
+ Create a cleanup job from a CartographyRelSchema object (specifically, a MatchLink).
196
+ This is used for cleaning up stale links between nodes created by load_rels(). Do not use for other purposes.
197
+
198
+ Other notes:
199
+ - For a given rel_schema, the fields used in the rel_schema.properties._sub_resource_label.name and
200
+ rel_schema.properties._sub_resource_id.name must be provided as keys and values in the params dict.
201
+ - The rel_schema must have a source_node_matcher and target_node_matcher.
202
+ :param iterationsize: The number of items to process in each iteration. Defaults to 100.
203
+ """
204
+ cleanup_link_query = build_cleanup_query_for_matchlink(rel_schema)
205
+ logger.debug(f"Cleanup query: {cleanup_link_query}")
206
+
207
+ parameters = {
208
+ "UPDATE_TAG": update_tag,
209
+ "_sub_resource_label": sub_resource_label,
210
+ "_sub_resource_id": sub_resource_id,
211
+ }
212
+
213
+ statement = GraphStatement(
214
+ cleanup_link_query,
215
+ parameters=parameters,
216
+ iterative=True,
217
+ iterationsize=iterationsize,
218
+ parent_job_name=rel_schema.rel_label,
219
+ )
220
+
221
+ return cls(
222
+ f"Cleanup {rel_schema.rel_label} between {rel_schema.source_node_label} and {rel_schema.target_node_label}",
223
+ [statement],
224
+ rel_schema.rel_label,
225
+ )
226
+
179
227
  @classmethod
180
228
  def from_json_file(cls, file_path: Union[str, Path]) -> "GraphJob":
181
229
  """
@@ -196,12 +244,12 @@ class GraphJob:
196
244
  def run_from_json(
197
245
  cls,
198
246
  neo4j_session: neo4j.Session,
199
- blob: str,
247
+ blob: Union[str, dict],
200
248
  parameters: Dict,
201
249
  short_name: Optional[str] = None,
202
250
  ) -> None:
203
251
  """
204
- Run a job from a JSON blob. This will deserialize the job and execute all statements sequentially.
252
+ Run a job from a JSON dict or blob. This will deserialize the job and execute all statements sequentially.
205
253
  """
206
254
  if not parameters:
207
255
  parameters = {}