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,225 @@
1
+ import hashlib
2
+ import logging
3
+ from typing import Any
4
+
5
+ import neo4j
6
+ from google.api_core.exceptions import PermissionDenied
7
+ from google.cloud.asset_v1 import AssetServiceClient
8
+ from google.cloud.asset_v1.types import BatchGetEffectiveIamPoliciesRequest
9
+ from google.cloud.asset_v1.types import SearchAllIamPoliciesRequest
10
+ from google.protobuf.json_format import MessageToDict
11
+
12
+ from cartography.client.core.tx import load
13
+ from cartography.graph.job import GraphJob
14
+ from cartography.models.gcp.policy_bindings import GCPPolicyBindingSchema
15
+ from cartography.util import timeit
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ @timeit
21
+ def get_policy_bindings(
22
+ project_id: str,
23
+ common_job_parameters: dict[str, Any],
24
+ client: AssetServiceClient,
25
+ ) -> dict[str, Any]:
26
+ org_id = common_job_parameters.get("ORG_RESOURCE_NAME")
27
+ project_resource_name = (
28
+ f"//cloudresourcemanager.googleapis.com/projects/{project_id}"
29
+ )
30
+
31
+ policies = []
32
+
33
+ # Fetch effective policies for project resource (using org scope for inheritance)
34
+ effective_scope = org_id
35
+ response = client.batch_get_effective_iam_policies(
36
+ request=BatchGetEffectiveIamPoliciesRequest(
37
+ scope=effective_scope, names=[project_resource_name]
38
+ )
39
+ )
40
+ effective_dict = MessageToDict(response._pb, preserving_proto_field_name=True)
41
+
42
+ policies.extend(
43
+ effective_dict["policy_results"]
44
+ ) # Fail Loudly if policy_results is not present
45
+
46
+ # Fetch direct policy bindings for all child resources using search_all_iam_policies (project scope - no inheritance)
47
+ search_request = SearchAllIamPoliciesRequest(
48
+ scope=f"projects/{project_id}",
49
+ asset_types=[],
50
+ )
51
+ for policy in client.search_all_iam_policies(request=search_request):
52
+ policy_dict = MessageToDict(policy._pb, preserving_proto_field_name=True)
53
+ # Filter out project resource itself (we already have effective policies for it)
54
+ resource = policy_dict.get("resource", "")
55
+ if resource != project_resource_name:
56
+ policy_data = policy_dict.get("policy", {})
57
+ bindings = policy_data.get("bindings", [])
58
+
59
+ policies.append(
60
+ {
61
+ "full_resource_name": resource,
62
+ "policies": [
63
+ {
64
+ "attached_resource": resource,
65
+ "policy": {"bindings": bindings},
66
+ }
67
+ ],
68
+ }
69
+ )
70
+
71
+ return {
72
+ "project_id": project_id,
73
+ "organization": org_id,
74
+ "policy_results": policies,
75
+ }
76
+
77
+
78
+ def transform_bindings(data: dict[str, Any]) -> list[dict[str, Any]]:
79
+ project_id = data["project_id"]
80
+ bindings: dict[tuple[str, str, str | None], dict[str, Any]] = {}
81
+
82
+ for policy_result in data["policy_results"]:
83
+ for policy in policy_result.get("policies", []):
84
+ resource = policy.get("attached_resource", "")
85
+
86
+ # Determine resource type
87
+ if "/organizations/" in resource:
88
+ resource_type = "organization"
89
+ elif "/folders/" in resource:
90
+ resource_type = "folder"
91
+ elif f"/projects/{project_id}" in resource and resource.endswith(
92
+ f"/projects/{project_id}"
93
+ ):
94
+ resource_type = "project"
95
+ else:
96
+ resource_type = "resource"
97
+
98
+ for binding in policy.get("policy", {}).get("bindings", []):
99
+ role = binding.get("role")
100
+ members = binding.get("members", [])
101
+ condition = binding.get("condition")
102
+
103
+ if not role or not members:
104
+ continue
105
+
106
+ # Filter members to only user:, serviceAccount:, and group: types
107
+ # Extract email part from each member (format: "type:email@example.com")
108
+ filtered_members = []
109
+ for member in members:
110
+ if ":" not in member:
111
+ continue
112
+ member_type, identifier = member.split(":", 1)
113
+ if member_type in ("user", "serviceAccount", "group"):
114
+ # Store only the email part
115
+ filtered_members.append(identifier)
116
+
117
+ # Don't process if members(principals) are not from the supported types. For example -> allUsers:, allAuthenticatedUsers, etc.
118
+ if not filtered_members:
119
+ continue
120
+
121
+ # Extract condition expression for deduplication key
122
+ # Include condition expression in key so conditional bindings stay distinct
123
+ condition_expression = (
124
+ condition.get("expression") if condition else None
125
+ )
126
+
127
+ # Deduplicate bindings by (resource, role, condition_expression)
128
+ # This ensures conditional bindings with different expressions are kept separate
129
+ key = (resource, role, condition_expression)
130
+
131
+ if key in bindings:
132
+ existing_members = set(bindings[key]["members"])
133
+ existing_members.update(filtered_members)
134
+ bindings[key]["members"] = list(existing_members)
135
+ else:
136
+ # Generate unique ID that includes condition expression hash
137
+ condition_hash = ""
138
+ if condition_expression:
139
+ condition_hash = hashlib.sha256(
140
+ condition_expression.encode("utf-8")
141
+ ).hexdigest()[
142
+ :8
143
+ ] # Use first 8 chars of hash for brevity
144
+
145
+ binding_id = f"{resource}_{role}"
146
+ if condition_hash:
147
+ binding_id = f"{binding_id}_{condition_hash}"
148
+
149
+ bindings[key] = {
150
+ "id": binding_id,
151
+ "role": role,
152
+ "resource": resource,
153
+ "resource_type": resource_type,
154
+ "members": sorted(filtered_members),
155
+ "has_condition": condition is not None,
156
+ "condition_title": (
157
+ condition.get("title") if condition else None
158
+ ),
159
+ "condition_expression": condition_expression,
160
+ }
161
+
162
+ return list(bindings.values())
163
+
164
+
165
+ @timeit
166
+ def load_bindings(
167
+ neo4j_session: neo4j.Session,
168
+ bindings: list[dict[str, Any]],
169
+ project_id: str,
170
+ update_tag: int,
171
+ ) -> None:
172
+ load(
173
+ neo4j_session,
174
+ GCPPolicyBindingSchema(),
175
+ bindings,
176
+ lastupdated=update_tag,
177
+ PROJECT_ID=project_id,
178
+ )
179
+
180
+
181
+ @timeit
182
+ def cleanup(
183
+ neo4j_session: neo4j.Session,
184
+ common_job_parameters: dict[str, Any],
185
+ ) -> None:
186
+ logger.debug("Running GCP policy bindings cleanup job")
187
+
188
+ GraphJob.from_node_schema(
189
+ GCPPolicyBindingSchema(),
190
+ common_job_parameters,
191
+ ).run(neo4j_session)
192
+
193
+
194
+ @timeit
195
+ def sync(
196
+ neo4j_session: neo4j.Session,
197
+ project_id: str,
198
+ update_tag: int,
199
+ common_job_parameters: dict[str, Any],
200
+ client: AssetServiceClient,
201
+ ) -> bool:
202
+ """
203
+ Sync GCP IAM policy bindings for a project.
204
+
205
+ Returns True if sync was successful, False if skipped due to permissions.
206
+ """
207
+ try:
208
+ bindings_data = get_policy_bindings(
209
+ project_id, common_job_parameters=common_job_parameters, client=client
210
+ ) # Why pass common_job_parameters here? Because we need to get the org_id for getting inherited policies.
211
+ except PermissionDenied as e:
212
+ logger.warning(
213
+ "Permission denied when fetching policy bindings for project %s. "
214
+ "Skipping policy bindings sync. To enable this feature, grant "
215
+ "roles/cloudasset.viewer at the organization level. Error: %s",
216
+ project_id,
217
+ e,
218
+ )
219
+ return False
220
+
221
+ transformed_bindings_data = transform_bindings(bindings_data)
222
+
223
+ load_bindings(neo4j_session, transformed_bindings_data, project_id, update_tag)
224
+ cleanup(neo4j_session, common_job_parameters)
225
+ return True
@@ -1,13 +1,17 @@
1
1
  import logging
2
2
  from typing import Dict
3
3
  from typing import List
4
+ from typing import Tuple
4
5
 
5
6
  import neo4j
6
7
  from googleapiclient.discovery import HttpError
7
8
  from googleapiclient.discovery import Resource
8
9
 
10
+ from cartography.client.core.tx import load
11
+ from cartography.graph.job import GraphJob
9
12
  from cartography.intel.gcp import compute
10
- from cartography.util import run_cleanup_job
13
+ from cartography.models.gcp.storage.bucket import GCPBucketLabelSchema
14
+ from cartography.models.gcp.storage.bucket import GCPBucketSchema
11
15
  from cartography.util import timeit
12
16
 
13
17
  logger = logging.getLogger(__name__)
@@ -58,165 +62,85 @@ def get_gcp_buckets(storage: Resource, project_id: str) -> Dict:
58
62
 
59
63
 
60
64
  @timeit
61
- def transform_gcp_buckets(bucket_res: Dict) -> List[Dict]:
65
+ def transform_gcp_buckets_and_labels(bucket_res: Dict) -> Tuple[List[Dict], List[Dict]]:
62
66
  """
63
- Transform the GCP Storage Bucket response object for Neo4j ingestion
67
+ Transform the GCP Storage Bucket response object for Neo4j ingestion.
64
68
 
65
- :type bucket_res: The GCP storage resource object (https://cloud.google.com/storage/docs/json_api/v1/buckets)
66
- :param bucket_res: The return data
67
-
68
- :rtype: list
69
- :return: List of buckets ready for ingestion to Neo4j
69
+ :param bucket_res: The raw GCP bucket response.
70
+ :return: A tuple of (buckets, bucket_labels) ready for ingestion to Neo4j.
70
71
  """
71
72
 
72
- bucket_list = []
73
+ buckets: List[Dict] = []
74
+ labels: List[Dict] = []
73
75
  for b in bucket_res.get("items", []):
74
- bucket = {}
75
- bucket["etag"] = b.get("etag")
76
- bucket["iam_config_bucket_policy_only"] = (
77
- b.get("iamConfiguration", {})
78
- .get("bucketPolicyOnly", {})
79
- .get("enabled", None)
80
- )
81
- bucket["id"] = b["id"]
82
- bucket["labels"] = [(key, val) for (key, val) in b.get("labels", {}).items()]
83
- bucket["owner_entity"] = b.get("owner", {}).get("entity")
84
- bucket["owner_entity_id"] = b.get("owner", {}).get("entityId")
85
- bucket["kind"] = b.get("kind")
86
- bucket["location"] = b.get("location")
87
- bucket["location_type"] = b.get("locationType")
88
- bucket["meta_generation"] = b.get("metageneration", None)
89
- bucket["project_number"] = b["projectNumber"]
90
- bucket["self_link"] = b.get("selfLink")
91
- bucket["storage_class"] = b.get("storageClass")
92
- bucket["time_created"] = b.get("timeCreated")
93
- bucket["updated"] = b.get("updated")
94
- bucket["versioning_enabled"] = b.get("versioning", {}).get("enabled", None)
95
- bucket["default_event_based_hold"] = b.get("defaultEventBasedHold", None)
96
- bucket["retention_period"] = b.get("retentionPolicy", {}).get(
97
- "retentionPeriod",
98
- None,
99
- )
100
- bucket["default_kms_key_name"] = b.get("encryption", {}).get(
101
- "defaultKmsKeyName",
102
- )
103
- bucket["log_bucket"] = b.get("logging", {}).get("logBucket")
104
- bucket["requester_pays"] = b.get("billing", {}).get("requesterPays", None)
105
- bucket_list.append(bucket)
106
- return bucket_list
76
+ bucket = {
77
+ "iam_config_bucket_policy_only": (
78
+ b.get("iamConfiguration", {}).get("bucketPolicyOnly", {}).get("enabled")
79
+ ),
80
+ "id": b["id"],
81
+ # Preserve legacy bucket_id field for compatibility
82
+ "bucket_id": b["id"],
83
+ "owner_entity": b.get("owner", {}).get("entity"),
84
+ "owner_entity_id": b.get("owner", {}).get("entityId"),
85
+ "kind": b.get("kind"),
86
+ "location": b.get("location"),
87
+ "location_type": b.get("locationType"),
88
+ "meta_generation": b.get("metageneration"),
89
+ "project_number": b.get("projectNumber"),
90
+ "self_link": b.get("selfLink"),
91
+ "storage_class": b.get("storageClass"),
92
+ "time_created": b.get("timeCreated"),
93
+ "versioning_enabled": b.get("versioning", {}).get("enabled"),
94
+ "retention_period": b.get("retentionPolicy", {}).get("retentionPeriod"),
95
+ "default_kms_key_name": b.get("encryption", {}).get("defaultKmsKeyName"),
96
+ "log_bucket": b.get("logging", {}).get("logBucket"),
97
+ "requester_pays": b.get("billing", {}).get("requesterPays"),
98
+ }
99
+ buckets.append(bucket)
100
+ for key, val in b.get("labels", {}).items():
101
+ labels.append(
102
+ {
103
+ "id": f"GCPBucket_{key}",
104
+ "key": key,
105
+ "value": val,
106
+ "bucket_id": b["id"],
107
+ }
108
+ )
109
+ return buckets, labels
107
110
 
108
111
 
109
112
  @timeit
110
113
  def load_gcp_buckets(
111
114
  neo4j_session: neo4j.Session,
112
115
  buckets: List[Dict],
116
+ project_id: str,
113
117
  gcp_update_tag: int,
114
118
  ) -> None:
115
- """
116
- Ingest GCP Storage Buckets to Neo4j
117
-
118
- :type neo4j_session: Neo4j session object
119
- :param neo4j session: The Neo4j session object
120
-
121
- :type buckets: list
122
- :param buckets: List of GCP Storage Buckets to injest
123
-
124
- :type gcp_update_tag: timestamp
125
- :param gcp_update_tag: The timestamp value to set our new Neo4j nodes with
126
-
127
- :rtype: NoneType
128
- :return: Nothing
129
- """
130
-
131
- query = """
132
- MERGE(p:GCPProject{projectnumber:$ProjectNumber})
133
- ON CREATE SET p.firstseen = timestamp()
134
- SET p.lastupdated = $gcp_update_tag
135
-
136
- MERGE(bucket:GCPBucket{id:$BucketId})
137
- ON CREATE SET bucket.firstseen = timestamp(),
138
- bucket.bucket_id = $BucketId
139
- SET bucket.self_link = $SelfLink,
140
- bucket.project_number = $ProjectNumber,
141
- bucket.kind = $Kind,
142
- bucket.location = $Location,
143
- bucket.location_type = $LocationType,
144
- bucket.meta_generation = $MetaGeneration,
145
- bucket.storage_class = $StorageClass,
146
- bucket.time_created = $TimeCreated,
147
- bucket.retention_period = $RetentionPeriod,
148
- bucket.iam_config_bucket_policy_only = $IamConfigBucketPolicyOnly,
149
- bucket.owner_entity = $OwnerEntity,
150
- bucket.owner_entity_id = $OwnerEntityId,
151
- bucket.lastupdated = $gcp_update_tag,
152
- bucket.versioning_enabled = $VersioningEnabled,
153
- bucket.log_bucket = $LogBucket,
154
- bucket.requester_pays = $RequesterPays,
155
- bucket.default_kms_key_name = $DefaultKmsKeyName
156
-
157
- MERGE (p)-[r:RESOURCE]->(bucket)
158
- ON CREATE SET r.firstseen = timestamp()
159
- SET r.lastupdated = $gcp_update_tag
160
- """
161
- for bucket in buckets:
162
- neo4j_session.run(
163
- query,
164
- ProjectNumber=bucket["project_number"],
165
- BucketId=bucket["id"],
166
- SelfLink=bucket["self_link"],
167
- Kind=bucket["kind"],
168
- Location=bucket["location"],
169
- LocationType=bucket["location_type"],
170
- MetaGeneration=bucket["meta_generation"],
171
- StorageClass=bucket["storage_class"],
172
- TimeCreated=bucket["time_created"],
173
- RetentionPeriod=bucket["retention_period"],
174
- IamConfigBucketPolicyOnly=bucket["iam_config_bucket_policy_only"],
175
- OwnerEntity=bucket["owner_entity"],
176
- OwnerEntityId=bucket["owner_entity_id"],
177
- VersioningEnabled=bucket["versioning_enabled"],
178
- LogBucket=bucket["log_bucket"],
179
- RequesterPays=bucket["requester_pays"],
180
- DefaultKmsKeyName=bucket["default_kms_key_name"],
181
- gcp_update_tag=gcp_update_tag,
182
- )
183
- _attach_gcp_bucket_labels(neo4j_session, bucket, gcp_update_tag)
119
+ """Ingest GCP Storage Buckets to Neo4j."""
120
+ load(
121
+ neo4j_session,
122
+ GCPBucketSchema(),
123
+ buckets,
124
+ lastupdated=gcp_update_tag,
125
+ PROJECT_ID=project_id,
126
+ )
184
127
 
185
128
 
186
129
  @timeit
187
- def _attach_gcp_bucket_labels(
130
+ def load_gcp_bucket_labels(
188
131
  neo4j_session: neo4j.Session,
189
- bucket: Resource,
132
+ bucket_labels: List[Dict],
133
+ project_id: str,
190
134
  gcp_update_tag: int,
191
135
  ) -> None:
192
- """
193
- Attach GCP bucket labels to the bucket.
194
- :param neo4j_session: The neo4j session
195
- :param bucket: The GCP bucket object
196
- :param gcp_update_tag: The update tag for this sync
197
- :return: Nothing
198
- """
199
- query = """
200
- MERGE (l:Label:GCPBucketLabel{id: $BucketLabelId})
201
- ON CREATE SET l.firstseen = timestamp(),
202
- l.key = $Key
203
- SET l.value = $Value,
204
- l.lastupdated = $gcp_update_tag
205
- WITH l
206
- MATCH (bucket:GCPBucket{id:$BucketId})
207
- MERGE (l)<-[r:LABELED]-(bucket)
208
- ON CREATE SET r.firstseen = timestamp()
209
- SET r.lastupdated = $gcp_update_tag
210
- """
211
- for key, val in bucket.get("labels", []):
212
- neo4j_session.run(
213
- query,
214
- BucketLabelId=f"GCPBucket_{key}",
215
- Key=key,
216
- Value=val,
217
- BucketId=bucket["id"],
218
- gcp_update_tag=gcp_update_tag,
219
- )
136
+ """Ingest GCP Storage Bucket labels and attach them to buckets."""
137
+ load(
138
+ neo4j_session,
139
+ GCPBucketLabelSchema(),
140
+ bucket_labels,
141
+ lastupdated=gcp_update_tag,
142
+ PROJECT_ID=project_id,
143
+ )
220
144
 
221
145
 
222
146
  @timeit
@@ -224,22 +148,14 @@ def cleanup_gcp_buckets(
224
148
  neo4j_session: neo4j.Session,
225
149
  common_job_parameters: Dict,
226
150
  ) -> None:
227
- """
228
- Delete out-of-date GCP Storage Bucket nodes and relationships
229
-
230
- :type neo4j_session: The Neo4j session object
231
- :param neo4j_session: The Neo4j session
232
-
233
- :type common_job_parameters: dict
234
- :param common_job_parameters: Dictionary of other job parameters to pass to Neo4j
235
-
236
- :rtype: NoneType
237
- :return: Nothing
238
- """
239
- run_cleanup_job(
240
- "gcp_storage_bucket_cleanup.json",
151
+ """Delete out-of-date GCP Storage Bucket nodes and relationships."""
152
+ # Bucket labels depend on buckets, so we must remove labels first to avoid
153
+ # dangling references before deleting the buckets themselves.
154
+ GraphJob.from_node_schema(GCPBucketLabelSchema(), common_job_parameters).run(
155
+ neo4j_session,
156
+ )
157
+ GraphJob.from_node_schema(GCPBucketSchema(), common_job_parameters).run(
241
158
  neo4j_session,
242
- common_job_parameters,
243
159
  )
244
160
 
245
161
 
@@ -274,7 +190,7 @@ def sync_gcp_buckets(
274
190
  """
275
191
  logger.info("Syncing Storage objects for project %s.", project_id)
276
192
  storage_res = get_gcp_buckets(storage, project_id)
277
- bucket_list = transform_gcp_buckets(storage_res)
278
- load_gcp_buckets(neo4j_session, bucket_list, gcp_update_tag)
279
- # TODO scope the cleanup to the current project - https://github.com/cartography-cncf/cartography/issues/381
193
+ buckets, bucket_labels = transform_gcp_buckets_and_labels(storage_res)
194
+ load_gcp_buckets(neo4j_session, buckets, project_id, gcp_update_tag)
195
+ load_gcp_bucket_labels(neo4j_session, bucket_labels, project_id, gcp_update_tag)
280
196
  cleanup_gcp_buckets(neo4j_session, common_job_parameters)
@@ -1,19 +1,45 @@
1
1
  import base64
2
2
  import json
3
3
  import logging
4
+ from typing import cast
4
5
 
5
6
  import neo4j
6
- from requests import exceptions
7
7
 
8
+ import cartography.intel.github.commits
8
9
  import cartography.intel.github.repos
9
10
  import cartography.intel.github.teams
10
11
  import cartography.intel.github.users
12
+ from cartography.client.core.tx import read_list_of_values_tx
11
13
  from cartography.config import Config
12
14
  from cartography.util import timeit
13
15
 
14
16
  logger = logging.getLogger(__name__)
15
17
 
16
18
 
19
+ def _get_repos_from_graph(neo4j_session: neo4j.Session, organization: str) -> list[str]:
20
+ """
21
+ Get repository names for an organization from the graph instead of making an API call.
22
+
23
+ :param neo4j_session: Neo4j session for database interface
24
+ :param organization: GitHub organization name
25
+ :return: List of repository names
26
+ """
27
+ org_url = f"https://github.com/{organization}"
28
+ query = """
29
+ MATCH (org:GitHubOrganization {id: $org_url})<-[:OWNER]-(repo:GitHubRepository)
30
+ RETURN repo.name
31
+ ORDER BY repo.name
32
+ """
33
+ return cast(
34
+ list[str],
35
+ neo4j_session.execute_read(
36
+ read_list_of_values_tx,
37
+ query,
38
+ org_url=org_url,
39
+ ),
40
+ )
41
+
42
+
17
43
  @timeit
18
44
  def start_github_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
19
45
  """
@@ -34,27 +60,38 @@ def start_github_ingestion(neo4j_session: neo4j.Session, config: Config) -> None
34
60
  }
35
61
  # run sync for the provided github tokens
36
62
  for auth_data in auth_tokens["organization"]:
37
- try:
38
- cartography.intel.github.users.sync(
39
- neo4j_session,
40
- common_job_parameters,
41
- auth_data["token"],
42
- auth_data["url"],
43
- auth_data["name"],
44
- )
45
- cartography.intel.github.repos.sync(
46
- neo4j_session,
47
- common_job_parameters,
48
- auth_data["token"],
49
- auth_data["url"],
50
- auth_data["name"],
51
- )
52
- cartography.intel.github.teams.sync_github_teams(
53
- neo4j_session,
54
- common_job_parameters,
55
- auth_data["token"],
56
- auth_data["url"],
57
- auth_data["name"],
58
- )
59
- except exceptions.RequestException as e:
60
- logger.error("Could not complete request to the GitHub API: %s", e)
63
+ cartography.intel.github.users.sync(
64
+ neo4j_session,
65
+ common_job_parameters,
66
+ auth_data["token"],
67
+ auth_data["url"],
68
+ auth_data["name"],
69
+ )
70
+ cartography.intel.github.repos.sync(
71
+ neo4j_session,
72
+ common_job_parameters,
73
+ auth_data["token"],
74
+ auth_data["url"],
75
+ auth_data["name"],
76
+ )
77
+ cartography.intel.github.teams.sync_github_teams(
78
+ neo4j_session,
79
+ common_job_parameters,
80
+ auth_data["token"],
81
+ auth_data["url"],
82
+ auth_data["name"],
83
+ )
84
+
85
+ # Sync commit relationships for the configured lookback period
86
+ # Get repo names from the graph instead of making another API call
87
+ repo_names = _get_repos_from_graph(neo4j_session, auth_data["name"])
88
+
89
+ cartography.intel.github.commits.sync_github_commits(
90
+ neo4j_session,
91
+ auth_data["token"],
92
+ auth_data["url"],
93
+ auth_data["name"],
94
+ repo_names,
95
+ common_job_parameters["UPDATE_TAG"],
96
+ config.github_commit_lookback_days,
97
+ )