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,386 @@
1
+ import json
2
+ import logging
3
+ import os
4
+ from typing import Any
5
+
6
+ import boto3
7
+ from neo4j import Session
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.models.trivy.findings import TrivyImageFindingSchema
12
+ from cartography.models.trivy.fix import TrivyFixSchema
13
+ from cartography.models.trivy.package import TrivyPackageSchema
14
+ from cartography.stats import get_stats_client
15
+ from cartography.util import timeit
16
+
17
+ logger = logging.getLogger(__name__)
18
+ stat_handler = get_stats_client(__name__)
19
+
20
+
21
+ def _validate_packages(package_list: list[dict]) -> list[dict]:
22
+ """
23
+ Validates that each package has the required fields.
24
+ Returns only packages that have both InstalledVersion and PkgName.
25
+ """
26
+ validated_packages: list[dict] = []
27
+ for pkg in package_list:
28
+ if (
29
+ "InstalledVersion" in pkg
30
+ and pkg["InstalledVersion"]
31
+ and "PkgName" in pkg
32
+ and pkg["PkgName"]
33
+ ):
34
+ validated_packages.append(pkg)
35
+ else:
36
+ logger.warning(
37
+ "Package object does not have required fields `InstalledVersion` or `PkgName` - skipping."
38
+ )
39
+ return validated_packages
40
+
41
+
42
+ def transform_scan_results(
43
+ results: list[dict], image_digest: str
44
+ ) -> tuple[list[dict], list[dict], list[dict]]:
45
+ """
46
+ Transform raw Trivy scan results into a format suitable for loading into Neo4j.
47
+ Returns a tuple of (findings_list, packages_list, fixes_list).
48
+ """
49
+ findings_list = []
50
+ packages_list = []
51
+ fixes_list = []
52
+
53
+ for scan_class in results:
54
+ # Sometimes a scan class will have no vulns and Trivy will leave the key undefined instead of showing [].
55
+ if "Vulnerabilities" in scan_class and scan_class["Vulnerabilities"]:
56
+ for result in scan_class["Vulnerabilities"]:
57
+ # Transform finding data
58
+ finding = {
59
+ "id": f'TIF|{result["VulnerabilityID"]}',
60
+ "VulnerabilityID": result["VulnerabilityID"],
61
+ "cve_id": result["VulnerabilityID"],
62
+ "Description": result.get("Description"),
63
+ "LastModifiedDate": result.get("LastModifiedDate"),
64
+ "PrimaryURL": result.get("PrimaryURL"),
65
+ "PublishedDate": result.get("PublishedDate"),
66
+ "Severity": result["Severity"],
67
+ "SeveritySource": result.get("SeveritySource"),
68
+ "Title": result.get("Title"),
69
+ "nvd_v2_score": None,
70
+ "nvd_v2_vector": None,
71
+ "nvd_v3_score": None,
72
+ "nvd_v3_vector": None,
73
+ "redhat_v3_score": None,
74
+ "redhat_v3_vector": None,
75
+ "ubuntu_v3_score": None,
76
+ "ubuntu_v3_vector": None,
77
+ "Class": scan_class["Class"],
78
+ "Type": scan_class["Type"],
79
+ "ImageDigest": image_digest, # For AFFECTS relationship
80
+ }
81
+
82
+ # Add CVSS scores if available
83
+ if "CVSS" in result:
84
+ if "nvd" in result["CVSS"]:
85
+ nvd = result["CVSS"]["nvd"]
86
+ finding["nvd_v2_score"] = nvd.get("V2Score")
87
+ finding["nvd_v2_vector"] = nvd.get("V2Vector")
88
+ finding["nvd_v3_score"] = nvd.get("V3Score")
89
+ finding["nvd_v3_vector"] = nvd.get("V3Vector")
90
+ if "redhat" in result["CVSS"]:
91
+ redhat = result["CVSS"]["redhat"]
92
+ finding["redhat_v3_score"] = redhat.get("V3Score")
93
+ finding["redhat_v3_vector"] = redhat.get("V3Vector")
94
+ if "ubuntu" in result["CVSS"]:
95
+ ubuntu = result["CVSS"]["ubuntu"]
96
+ finding["ubuntu_v3_score"] = ubuntu.get("V3Score")
97
+ finding["ubuntu_v3_vector"] = ubuntu.get("V3Vector")
98
+
99
+ findings_list.append(finding)
100
+
101
+ # Transform package data
102
+ package_id = f"{result['InstalledVersion']}|{result['PkgName']}"
103
+ packages_list.append(
104
+ {
105
+ "id": package_id,
106
+ "InstalledVersion": result["InstalledVersion"],
107
+ "PkgName": result["PkgName"],
108
+ "Class": scan_class["Class"],
109
+ "Type": scan_class["Type"],
110
+ "ImageDigest": image_digest, # For DEPLOYED relationship
111
+ "FindingId": finding["id"], # For AFFECTS relationship
112
+ }
113
+ )
114
+
115
+ # Transform fix data if available
116
+ if result.get("FixedVersion") is not None:
117
+ fixes_list.append(
118
+ {
119
+ "id": f"{result['FixedVersion']}|{result['PkgName']}",
120
+ "FixedVersion": result["FixedVersion"],
121
+ "PackageId": package_id,
122
+ "FindingId": finding["id"],
123
+ }
124
+ )
125
+
126
+ # Validate packages before returning
127
+ packages_list = _validate_packages(packages_list)
128
+ return findings_list, packages_list, fixes_list
129
+
130
+
131
+ def _parse_trivy_data(
132
+ trivy_data: dict, source: str
133
+ ) -> tuple[str | None, list[dict], str]:
134
+ """
135
+ Parse Trivy scan data and extract common fields.
136
+
137
+ Args:
138
+ trivy_data: Raw JSON Trivy data
139
+ source: Source identifier for error messages (file path or S3 URI)
140
+
141
+ Returns:
142
+ Tuple of (artifact_name, results, image_digest)
143
+ """
144
+ # Extract artifact name if present (only for file-based)
145
+ artifact_name = trivy_data.get("ArtifactName")
146
+
147
+ if "Results" not in trivy_data:
148
+ logger.error(
149
+ f"Scan data did not contain a `Results` key for {source}. This indicates a malformed scan result."
150
+ )
151
+ raise ValueError(f"Missing 'Results' key in scan data for {source}")
152
+
153
+ results = trivy_data["Results"]
154
+ if not results:
155
+ stat_handler.incr("image_scan_no_results_count")
156
+ logger.info(f"No vulnerabilities found for {source}")
157
+
158
+ if "Metadata" not in trivy_data or not trivy_data["Metadata"]:
159
+ raise ValueError(f"Missing 'Metadata' in scan data for {source}")
160
+
161
+ repo_digests = trivy_data["Metadata"].get("RepoDigests", [])
162
+ if not repo_digests:
163
+ raise ValueError(f"Missing 'RepoDigests' in scan metadata for {source}")
164
+
165
+ repo_digest = repo_digests[0]
166
+ if "@" not in repo_digest:
167
+ raise ValueError(f"Invalid repo digest format in {source}: {repo_digest}")
168
+
169
+ image_digest = repo_digest.split("@")[1]
170
+ if not image_digest:
171
+ raise ValueError(f"Empty image digest for {source}")
172
+
173
+ return artifact_name, results, image_digest
174
+
175
+
176
+ @timeit
177
+ def sync_single_image(
178
+ neo4j_session: Session,
179
+ trivy_data: dict,
180
+ source: str,
181
+ update_tag: int,
182
+ ) -> None:
183
+ """
184
+ Sync a single image's Trivy scan results to Neo4j.
185
+
186
+ Args:
187
+ neo4j_session: Neo4j session for database operations
188
+ trivy_data: Raw Trivy JSON data
189
+ source: Source identifier for logging (file path or image URI)
190
+ update_tag: Update tag for tracking
191
+ """
192
+ try:
193
+ _, results, image_digest = _parse_trivy_data(trivy_data, source)
194
+
195
+ # Transform all data in one pass
196
+ findings_list, packages_list, fixes_list = transform_scan_results(
197
+ results,
198
+ image_digest,
199
+ )
200
+
201
+ num_findings = len(findings_list)
202
+ stat_handler.incr("image_scan_cve_count", num_findings)
203
+
204
+ # Load the transformed data
205
+ load_scan_vulns(neo4j_session, findings_list, update_tag=update_tag)
206
+ load_scan_packages(neo4j_session, packages_list, update_tag=update_tag)
207
+ load_scan_fixes(neo4j_session, fixes_list, update_tag=update_tag)
208
+ stat_handler.incr("images_processed_count")
209
+
210
+ except Exception as e:
211
+ logger.error(f"Failed to process scan results for {source}: {e}")
212
+ raise
213
+
214
+
215
+ @timeit
216
+ def get_json_files_in_s3(
217
+ s3_bucket: str, s3_prefix: str, boto3_session: boto3.Session
218
+ ) -> set[str]:
219
+ """
220
+ List S3 objects in the S3 prefix.
221
+
222
+ Args:
223
+ s3_bucket: S3 bucket name containing scan results
224
+ s3_prefix: S3 prefix path containing scan results
225
+ boto3_session: boto3 session for dependency injection
226
+
227
+ Returns:
228
+ Set of S3 object keys for JSON files in the S3 prefix
229
+ """
230
+ s3_client = boto3_session.client("s3")
231
+
232
+ try:
233
+ # List objects in the S3 prefix
234
+ paginator = s3_client.get_paginator("list_objects_v2")
235
+ page_iterator = paginator.paginate(Bucket=s3_bucket, Prefix=s3_prefix)
236
+ results = set()
237
+
238
+ for page in page_iterator:
239
+ if "Contents" not in page:
240
+ continue
241
+
242
+ for obj in page["Contents"]:
243
+ object_key = obj["Key"]
244
+
245
+ # Skip non-JSON files
246
+ if not object_key.endswith(".json"):
247
+ continue
248
+
249
+ # Skip files that don't start with our prefix
250
+ if not object_key.startswith(s3_prefix):
251
+ continue
252
+
253
+ results.add(object_key)
254
+
255
+ except Exception as e:
256
+ logger.error(
257
+ f"Error listing S3 objects in bucket {s3_bucket} with prefix {s3_prefix}: {e}"
258
+ )
259
+ raise
260
+
261
+ logger.info(f"Found {len(results)} json files in s3://{s3_bucket}/{s3_prefix}")
262
+ return results
263
+
264
+
265
+ @timeit
266
+ def get_json_files_in_dir(results_dir: str) -> set[str]:
267
+ """Return set of JSON file paths under a directory."""
268
+ results = set()
269
+ for root, _dirs, files in os.walk(results_dir):
270
+ for filename in files:
271
+ if filename.endswith(".json"):
272
+ results.add(os.path.join(root, filename))
273
+ logger.info(f"Found {len(results)} json files in {results_dir}")
274
+ return results
275
+
276
+
277
+ @timeit
278
+ def cleanup(neo4j_session: Session, common_job_parameters: dict[str, Any]) -> None:
279
+ """
280
+ Run cleanup jobs for Trivy nodes.
281
+ """
282
+ logger.info("Running Trivy cleanup")
283
+ GraphJob.from_node_schema(TrivyImageFindingSchema(), common_job_parameters).run(
284
+ neo4j_session
285
+ )
286
+ GraphJob.from_node_schema(TrivyPackageSchema(), common_job_parameters).run(
287
+ neo4j_session
288
+ )
289
+ GraphJob.from_node_schema(TrivyFixSchema(), common_job_parameters).run(
290
+ neo4j_session
291
+ )
292
+
293
+
294
+ @timeit
295
+ def load_scan_vulns(
296
+ neo4j_session: Session,
297
+ findings_list: list[dict[str, Any]],
298
+ update_tag: int,
299
+ ) -> None:
300
+ """
301
+ Load TrivyImageFinding nodes into Neo4j.
302
+ """
303
+ load(
304
+ neo4j_session,
305
+ TrivyImageFindingSchema(),
306
+ findings_list,
307
+ lastupdated=update_tag,
308
+ )
309
+
310
+
311
+ @timeit
312
+ def load_scan_packages(
313
+ neo4j_session: Session,
314
+ packages_list: list[dict[str, Any]],
315
+ update_tag: int,
316
+ ) -> None:
317
+ """
318
+ Load TrivyPackage nodes into Neo4j.
319
+ """
320
+ load(
321
+ neo4j_session,
322
+ TrivyPackageSchema(),
323
+ packages_list,
324
+ lastupdated=update_tag,
325
+ )
326
+
327
+
328
+ @timeit
329
+ def load_scan_fixes(
330
+ neo4j_session: Session,
331
+ fixes_list: list[dict[str, Any]],
332
+ update_tag: int,
333
+ ) -> None:
334
+ """
335
+ Load TrivyFix nodes into Neo4j.
336
+ """
337
+ load(
338
+ neo4j_session,
339
+ TrivyFixSchema(),
340
+ fixes_list,
341
+ lastupdated=update_tag,
342
+ )
343
+
344
+
345
+ @timeit
346
+ def sync_single_image_from_s3(
347
+ neo4j_session: Session,
348
+ image_uri: str,
349
+ update_tag: int,
350
+ s3_bucket: str,
351
+ s3_object_key: str,
352
+ boto3_session: boto3.Session,
353
+ ) -> None:
354
+ """
355
+ Read Trivy scan results from S3 and sync to Neo4j.
356
+
357
+ Args:
358
+ neo4j_session: Neo4j session for database operations
359
+ image_uri: ECR image URI
360
+ update_tag: Update tag for tracking
361
+ s3_bucket: S3 bucket containing scan results
362
+ s3_object_key: S3 object key for this image's scan results
363
+ boto3_session: boto3 session for S3 operations
364
+ """
365
+ s3_client = boto3_session.client("s3")
366
+
367
+ logger.debug(f"Reading scan results from S3: s3://{s3_bucket}/{s3_object_key}")
368
+ response = s3_client.get_object(Bucket=s3_bucket, Key=s3_object_key)
369
+ scan_data_json = response["Body"].read().decode("utf-8")
370
+
371
+ trivy_data = json.loads(scan_data_json)
372
+ sync_single_image(neo4j_session, trivy_data, image_uri, update_tag)
373
+
374
+
375
+ @timeit
376
+ def sync_single_image_from_file(
377
+ neo4j_session: Session,
378
+ file_path: str,
379
+ update_tag: int,
380
+ ) -> None:
381
+ """Read a Trivy JSON file from disk and sync to Neo4j."""
382
+ logger.debug(f"Reading scan results from file: {file_path}")
383
+ with open(file_path, encoding="utf-8") as f:
384
+ trivy_data = json.load(f)
385
+
386
+ sync_single_image(neo4j_session, trivy_data, file_path, update_tag)
File without changes
@@ -0,0 +1,138 @@
1
+ from dataclasses import dataclass
2
+
3
+ from cartography.models.core.common import PropertyRef
4
+ from cartography.models.core.nodes import CartographyNodeProperties
5
+ from cartography.models.core.nodes import CartographyNodeSchema
6
+ from cartography.models.core.relationships import CartographyRelProperties
7
+ from cartography.models.core.relationships import CartographyRelSchema
8
+ from cartography.models.core.relationships import LinkDirection
9
+ from cartography.models.core.relationships import make_target_node_matcher
10
+ from cartography.models.core.relationships import OtherRelationships
11
+ from cartography.models.core.relationships import TargetNodeMatcher
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class AirbyteConnectionNodeProperties(CartographyNodeProperties):
16
+ id: PropertyRef = PropertyRef("connectionId")
17
+ name: PropertyRef = PropertyRef("name")
18
+ namespace_format: PropertyRef = PropertyRef("namespaceFormat")
19
+ prefix: PropertyRef = PropertyRef("prefix")
20
+ status: PropertyRef = PropertyRef("status")
21
+ data_residency: PropertyRef = PropertyRef("dataResidency")
22
+ non_breaking_schema_updates_behavior: PropertyRef = PropertyRef(
23
+ "nonBreakingSchemaUpdatesBehavior"
24
+ )
25
+ namespace_definition: PropertyRef = PropertyRef("namespaceDefinition")
26
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class AirbyteConnectionToOrganizationRelProperties(CartographyRelProperties):
31
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ # (:AirbyteOrganization)-[:RESOURCE]->(:AirbyteConnection)
36
+ class AirbyteConnectionToOrganizationRel(CartographyRelSchema):
37
+ target_node_label: str = "AirbyteOrganization"
38
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
39
+ {"id": PropertyRef("ORG_ID", set_in_kwargs=True)},
40
+ )
41
+ direction: LinkDirection = LinkDirection.INWARD
42
+ rel_label: str = "RESOURCE"
43
+ properties: AirbyteConnectionToOrganizationRelProperties = (
44
+ AirbyteConnectionToOrganizationRelProperties()
45
+ )
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class AirbyteConnectionToWorkspaceRelProperties(CartographyRelProperties):
50
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
51
+
52
+
53
+ @dataclass(frozen=True)
54
+ # (:AirbyteWorkspace)-[:CONTAINS]->(:AirbyteConnection)
55
+ class AirbyteConnectionToWorkspaceRel(CartographyRelSchema):
56
+ target_node_label: str = "AirbyteWorkspace"
57
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
58
+ {"id": PropertyRef("workspaceId")},
59
+ )
60
+ direction: LinkDirection = LinkDirection.INWARD
61
+ rel_label: str = "CONTAINS"
62
+ properties: AirbyteConnectionToWorkspaceRelProperties = (
63
+ AirbyteConnectionToWorkspaceRelProperties()
64
+ )
65
+
66
+
67
+ @dataclass(frozen=True)
68
+ class AirbyteConnectionToSourceRelProperties(CartographyRelProperties):
69
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
70
+
71
+
72
+ @dataclass(frozen=True)
73
+ # (:AirbyteSource)<-[:SYNC_FROM]-(:AirbyteConnection)
74
+ class AirbyteConnectionToSourceRel(CartographyRelSchema):
75
+ target_node_label: str = "AirbyteSource"
76
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
77
+ {"id": PropertyRef("sourceId")},
78
+ )
79
+ direction: LinkDirection = LinkDirection.OUTWARD
80
+ rel_label: str = "SYNC_FROM"
81
+ properties: AirbyteConnectionToSourceRelProperties = (
82
+ AirbyteConnectionToSourceRelProperties()
83
+ )
84
+
85
+
86
+ @dataclass(frozen=True)
87
+ class AirbyteConnectionToDestinationRelProperties(CartographyRelProperties):
88
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
89
+
90
+
91
+ @dataclass(frozen=True)
92
+ # (:AirbyteDestination)<-[:SYNC_TO]-(:AirbyteConnection)
93
+ class AirbyteConnectionToDestinationRel(CartographyRelSchema):
94
+ target_node_label: str = "AirbyteDestination"
95
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
96
+ {"id": PropertyRef("destinationId")},
97
+ )
98
+ direction: LinkDirection = LinkDirection.OUTWARD
99
+ rel_label: str = "SYNC_TO"
100
+ properties: AirbyteConnectionToDestinationRelProperties = (
101
+ AirbyteConnectionToDestinationRelProperties()
102
+ )
103
+
104
+
105
+ @dataclass(frozen=True)
106
+ class AirbyteConnectionToTagRelProperties(CartographyRelProperties):
107
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
108
+
109
+
110
+ @dataclass(frozen=True)
111
+ # (:AirbyteTag)<-[:TAGGED]-(:AirbyteConnection)
112
+ class AirbyteConnectionToTagRel(CartographyRelSchema):
113
+ target_node_label: str = "AirbyteTag"
114
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
115
+ {"id": PropertyRef("tags_ids", one_to_many=True)},
116
+ )
117
+ direction: LinkDirection = LinkDirection.OUTWARD
118
+ rel_label: str = "TAGGED"
119
+ properties: AirbyteConnectionToTagRelProperties = (
120
+ AirbyteConnectionToTagRelProperties()
121
+ )
122
+
123
+
124
+ @dataclass(frozen=True)
125
+ class AirbyteConnectionSchema(CartographyNodeSchema):
126
+ label: str = "AirbyteConnection"
127
+ properties: AirbyteConnectionNodeProperties = AirbyteConnectionNodeProperties()
128
+ sub_resource_relationship: AirbyteConnectionToOrganizationRel = (
129
+ AirbyteConnectionToOrganizationRel()
130
+ )
131
+ other_relationships: OtherRelationships = OtherRelationships(
132
+ [
133
+ AirbyteConnectionToWorkspaceRel(),
134
+ AirbyteConnectionToSourceRel(),
135
+ AirbyteConnectionToDestinationRel(),
136
+ AirbyteConnectionToTagRel(),
137
+ ]
138
+ )
@@ -0,0 +1,75 @@
1
+ from dataclasses import dataclass
2
+
3
+ from cartography.models.core.common import PropertyRef
4
+ from cartography.models.core.nodes import CartographyNodeProperties
5
+ from cartography.models.core.nodes import CartographyNodeSchema
6
+ from cartography.models.core.relationships import CartographyRelProperties
7
+ from cartography.models.core.relationships import CartographyRelSchema
8
+ from cartography.models.core.relationships import LinkDirection
9
+ from cartography.models.core.relationships import make_target_node_matcher
10
+ from cartography.models.core.relationships import OtherRelationships
11
+ from cartography.models.core.relationships import TargetNodeMatcher
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class AirbyteDestinationNodeProperties(CartographyNodeProperties):
16
+ id: PropertyRef = PropertyRef("destinationId")
17
+ name: PropertyRef = PropertyRef("name")
18
+ type: PropertyRef = PropertyRef("destinationType")
19
+ config_host: PropertyRef = PropertyRef("configuration.host")
20
+ config_port: PropertyRef = PropertyRef("configuration.port")
21
+ config_name: PropertyRef = PropertyRef("configuration.name")
22
+ config_region: PropertyRef = PropertyRef("configuration.region")
23
+ config_endpoint: PropertyRef = PropertyRef("configuration.endpoint")
24
+ config_account: PropertyRef = PropertyRef("configuration.account")
25
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class AirbyteDestinationToOrganizationRelProperties(CartographyRelProperties):
30
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ # (:AirbyteOrganization)-[:RESOURCE]->(:AirbyteDestination)
35
+ class AirbyteDestinationToOrganizationRel(CartographyRelSchema):
36
+ target_node_label: str = "AirbyteOrganization"
37
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
38
+ {"id": PropertyRef("ORG_ID", set_in_kwargs=True)},
39
+ )
40
+ direction: LinkDirection = LinkDirection.INWARD
41
+ rel_label: str = "RESOURCE"
42
+ properties: AirbyteDestinationToOrganizationRelProperties = (
43
+ AirbyteDestinationToOrganizationRelProperties()
44
+ )
45
+
46
+
47
+ @dataclass(frozen=True)
48
+ class AirbyteDestinationToWorkspaceRelProperties(CartographyRelProperties):
49
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
50
+
51
+
52
+ @dataclass(frozen=True)
53
+ # (:AirbyteWorkspace)-[:CONTAINS]->(:AirbyteDestination)
54
+ class AirbyteDestinationToWorkspaceRel(CartographyRelSchema):
55
+ target_node_label: str = "AirbyteWorkspace"
56
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
57
+ {"id": PropertyRef("workspaceId")},
58
+ )
59
+ direction: LinkDirection = LinkDirection.INWARD
60
+ rel_label: str = "CONTAINS"
61
+ properties: AirbyteDestinationToWorkspaceRelProperties = (
62
+ AirbyteDestinationToWorkspaceRelProperties()
63
+ )
64
+
65
+
66
+ @dataclass(frozen=True)
67
+ class AirbyteDestinationSchema(CartographyNodeSchema):
68
+ label: str = "AirbyteDestination"
69
+ properties: AirbyteDestinationNodeProperties = AirbyteDestinationNodeProperties()
70
+ sub_resource_relationship: AirbyteDestinationToOrganizationRel = (
71
+ AirbyteDestinationToOrganizationRel()
72
+ )
73
+ other_relationships: OtherRelationships = OtherRelationships(
74
+ [AirbyteDestinationToWorkspaceRel()]
75
+ )
@@ -0,0 +1,19 @@
1
+ from dataclasses import dataclass
2
+
3
+ from cartography.models.core.common import PropertyRef
4
+ from cartography.models.core.nodes import CartographyNodeProperties
5
+ from cartography.models.core.nodes import CartographyNodeSchema
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class AirbyteOrganizationNodeProperties(CartographyNodeProperties):
10
+ id: PropertyRef = PropertyRef("organizationId")
11
+ name: PropertyRef = PropertyRef("organizationName")
12
+ email: PropertyRef = PropertyRef("email")
13
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class AirbyteOrganizationSchema(CartographyNodeSchema):
18
+ label: str = "AirbyteOrganization"
19
+ properties: AirbyteOrganizationNodeProperties = AirbyteOrganizationNodeProperties()
@@ -0,0 +1,75 @@
1
+ from dataclasses import dataclass
2
+
3
+ from cartography.models.core.common import PropertyRef
4
+ from cartography.models.core.nodes import CartographyNodeProperties
5
+ from cartography.models.core.nodes import CartographyNodeSchema
6
+ from cartography.models.core.relationships import CartographyRelProperties
7
+ from cartography.models.core.relationships import CartographyRelSchema
8
+ from cartography.models.core.relationships import LinkDirection
9
+ from cartography.models.core.relationships import make_target_node_matcher
10
+ from cartography.models.core.relationships import OtherRelationships
11
+ from cartography.models.core.relationships import TargetNodeMatcher
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class AirbyteSourceNodeProperties(CartographyNodeProperties):
16
+ id: PropertyRef = PropertyRef("sourceId")
17
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
18
+ name: PropertyRef = PropertyRef("name")
19
+ type: PropertyRef = PropertyRef("sourceType")
20
+ config_host: PropertyRef = PropertyRef("configuration.host")
21
+ config_port: PropertyRef = PropertyRef("configuration.port")
22
+ config_name: PropertyRef = PropertyRef("configuration.name")
23
+ config_region: PropertyRef = PropertyRef("configuration.region")
24
+ config_endpoint: PropertyRef = PropertyRef("configuration.endpoint")
25
+ config_account: PropertyRef = PropertyRef("configuration.account")
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class AirbyteSourceToOrganizationRelProperties(CartographyRelProperties):
30
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ # (:AirbyteOrganization)-[:RESOURCE]->(:AirbyteSource)
35
+ class AirbyteSourceToOrganizationRel(CartographyRelSchema):
36
+ target_node_label: str = "AirbyteOrganization"
37
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
38
+ {"id": PropertyRef("ORG_ID", set_in_kwargs=True)},
39
+ )
40
+ direction: LinkDirection = LinkDirection.INWARD
41
+ rel_label: str = "RESOURCE"
42
+ properties: AirbyteSourceToOrganizationRelProperties = (
43
+ AirbyteSourceToOrganizationRelProperties()
44
+ )
45
+
46
+
47
+ @dataclass(frozen=True)
48
+ class AirbyteSourceToWorkspaceRelProperties(CartographyRelProperties):
49
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
50
+
51
+
52
+ @dataclass(frozen=True)
53
+ # (:AirbyteWorkspace)-[:CONTAINS]->(:AirbyteSource)
54
+ class AirbyteSourceToWorkspaceRel(CartographyRelSchema):
55
+ target_node_label: str = "AirbyteWorkspace"
56
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
57
+ {"id": PropertyRef("workspaceId")},
58
+ )
59
+ direction: LinkDirection = LinkDirection.INWARD
60
+ rel_label: str = "CONTAINS"
61
+ properties: AirbyteSourceToWorkspaceRelProperties = (
62
+ AirbyteSourceToWorkspaceRelProperties()
63
+ )
64
+
65
+
66
+ @dataclass(frozen=True)
67
+ class AirbyteSourceSchema(CartographyNodeSchema):
68
+ label: str = "AirbyteSource"
69
+ properties: AirbyteSourceNodeProperties = AirbyteSourceNodeProperties()
70
+ sub_resource_relationship: AirbyteSourceToOrganizationRel = (
71
+ AirbyteSourceToOrganizationRel()
72
+ )
73
+ other_relationships: OtherRelationships = OtherRelationships(
74
+ [AirbyteSourceToWorkspaceRel()]
75
+ )