cartography 0.96.1__tar.gz → 0.97.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cartography might be problematic. Click here for more details.

Files changed (366) hide show
  1. {cartography-0.96.1 → cartography-0.97.0}/PKG-INFO +1 -1
  2. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/identitycenter.py +1 -0
  3. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/cve/__init__.py +51 -19
  4. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/cve/feed.py +19 -37
  5. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/github/repos.py +80 -62
  6. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/github/teams.py +115 -17
  7. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/github/users.py +6 -1
  8. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/github/util.py +2 -1
  9. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/github/orgs.py +1 -1
  10. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/github/teams.py +17 -0
  11. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/github/users.py +15 -6
  12. {cartography-0.96.1 → cartography-0.97.0}/cartography.egg-info/PKG-INFO +1 -1
  13. {cartography-0.96.1 → cartography-0.97.0}/setup.py +1 -1
  14. {cartography-0.96.1 → cartography-0.97.0}/LICENSE +0 -0
  15. {cartography-0.96.1 → cartography-0.97.0}/README.md +0 -0
  16. {cartography-0.96.1 → cartography-0.97.0}/cartography/__init__.py +0 -0
  17. {cartography-0.96.1 → cartography-0.97.0}/cartography/__main__.py +0 -0
  18. {cartography-0.96.1 → cartography-0.97.0}/cartography/cli.py +0 -0
  19. {cartography-0.96.1 → cartography-0.97.0}/cartography/client/__init__.py +0 -0
  20. {cartography-0.96.1 → cartography-0.97.0}/cartography/client/aws/__init__.py +0 -0
  21. {cartography-0.96.1 → cartography-0.97.0}/cartography/client/aws/iam.py +0 -0
  22. {cartography-0.96.1 → cartography-0.97.0}/cartography/client/core/__init__.py +0 -0
  23. {cartography-0.96.1 → cartography-0.97.0}/cartography/client/core/tx.py +0 -0
  24. {cartography-0.96.1 → cartography-0.97.0}/cartography/config.py +0 -0
  25. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/__init__.py +0 -0
  26. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/indexes.cypher +0 -0
  27. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/__init__.py +0 -0
  28. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/__init__.py +0 -0
  29. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/aws_ec2_asset_exposure.json +0 -0
  30. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/aws_ec2_iaminstance.json +0 -0
  31. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/aws_ec2_iaminstanceprofile.json +0 -0
  32. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/aws_ec2_keypair_analysis.json +0 -0
  33. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/aws_eks_asset_exposure.json +0 -0
  34. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/aws_foreign_accounts.json +0 -0
  35. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/aws_lambda_ecr.json +0 -0
  36. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/aws_s3acl_analysis.json +0 -0
  37. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/gcp_compute_asset_inet_exposure.json +0 -0
  38. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/gcp_gke_asset_exposure.json +0 -0
  39. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/gcp_gke_basic_auth.json +0 -0
  40. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/analysis/gsuite_human_link.json +0 -0
  41. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/__init__.py +0 -0
  42. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_account_cleanup.json +0 -0
  43. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_apigateway_details.json +0 -0
  44. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_dns_cleanup.json +0 -0
  45. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_account_access_key_cleanup.json +0 -0
  46. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_apigateway_cleanup.json +0 -0
  47. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_config_cleanup.json +0 -0
  48. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_ec2_launch_configurations_cleanup.json +0 -0
  49. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_ec2_security_groupinfo_cleanup.json +0 -0
  50. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_ecr_cleanup.json +0 -0
  51. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_ecs_cleanup.json +0 -0
  52. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_elastic_ip_addresses_cleanup.json +0 -0
  53. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_elasticache_cleanup.json +0 -0
  54. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_es_cleanup.json +0 -0
  55. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_groups_cleanup.json +0 -0
  56. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_groups_membership_cleanup.json +0 -0
  57. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_groups_policy_cleanup.json +0 -0
  58. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_identity_center_cleanup.json +0 -0
  59. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_internet_gateways_cleanup.json +0 -0
  60. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_kms_cleanup.json +0 -0
  61. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_lambda_cleanup.json +0 -0
  62. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_principals_cleanup.json +0 -0
  63. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_rds_clusters_cleanup.json +0 -0
  64. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_rds_instances_cleanup.json +0 -0
  65. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_rds_snapshots_cleanup.json +0 -0
  66. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_redshift_clusters_cleanup.json +0 -0
  67. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_reserved_instances_cleanup.json +0 -0
  68. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_roles_cleanup.json +0 -0
  69. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_roles_policy_cleanup.json +0 -0
  70. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_s3_acl_cleanup.json +0 -0
  71. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_s3_buckets_cleanup.json +0 -0
  72. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_secrets_cleanup.json +0 -0
  73. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_securityhub_cleanup.json +0 -0
  74. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_snapshots_cleanup.json +0 -0
  75. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_sqs_queues_cleanup.json +0 -0
  76. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_tags_cleanup.json +0 -0
  77. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_tgw_cleanup.json +0 -0
  78. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_users_cleanup.json +0 -0
  79. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_vpc_cleanup.json +0 -0
  80. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_import_vpc_peering_cleanup.json +0 -0
  81. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_ingest_ec2_auto_scaling_groups_cleanup.json +0 -0
  82. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_ingest_load_balancers_cleanup.json +0 -0
  83. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_ingest_load_balancers_v2_cleanup.json +0 -0
  84. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_ingest_subnets_cleanup.json +0 -0
  85. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_kms_details.json +0 -0
  86. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_post_ingestion_principals_cleanup.json +0 -0
  87. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/aws_s3_details.json +0 -0
  88. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_cosmosdb_cassandra_keyspace_cleanup.json +0 -0
  89. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_cosmosdb_cors_details.json +0 -0
  90. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_cosmosdb_mongodb_database_cleanup.json +0 -0
  91. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_cosmosdb_sql_database_cleanup.json +0 -0
  92. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_cosmosdb_table_resources_cleanup.json +0 -0
  93. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_database_account_cleanup.json +0 -0
  94. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_import_disks_cleanup.json +0 -0
  95. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_import_snapshots_cleanup.json +0 -0
  96. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_import_virtual_machines_cleanup.json +0 -0
  97. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_sql_server_cleanup.json +0 -0
  98. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_storage_account_cleanup.json +0 -0
  99. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_subscriptions_cleanup.json +0 -0
  100. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/azure_tenant_cleanup.json +0 -0
  101. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/crowdstrike_import_cleanup.json +0 -0
  102. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/digitalocean_droplet_cleanup.json +0 -0
  103. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/digitalocean_project_cleanup.json +0 -0
  104. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_compute_firewall_cleanup.json +0 -0
  105. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_compute_forwarding_rules_cleanup.json +0 -0
  106. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_compute_instance_cleanup.json +0 -0
  107. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json +0 -0
  108. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_compute_vpc_subnet_cleanup.json +0 -0
  109. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_crm_folder_cleanup.json +0 -0
  110. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_crm_organization_cleanup.json +0 -0
  111. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_crm_project_cleanup.json +0 -0
  112. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_dns_cleanup.json +0 -0
  113. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_gke_cluster_cleanup.json +0 -0
  114. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gcp_storage_bucket_cleanup.json +0 -0
  115. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/github_org_and_users_cleanup.json +0 -0
  116. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/github_repos_cleanup.json +0 -0
  117. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gsuite_ingest_groups_cleanup.json +0 -0
  118. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/gsuite_ingest_users_cleanup.json +0 -0
  119. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/jamf_import_computers_cleanup.json +0 -0
  120. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/kubernetes_import_cleanup.json +0 -0
  121. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/oci_import_compartments_cleanup.json +0 -0
  122. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/oci_import_groups_cleanup.json +0 -0
  123. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/oci_import_groups_membership_cleanup.json +0 -0
  124. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/oci_import_policies_cleanup.json +0 -0
  125. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/oci_import_users_cleanup.json +0 -0
  126. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/oci_tenancy_cleanup.json +0 -0
  127. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/okta_groups_cleanup.json +0 -0
  128. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/okta_import_cleanup.json +0 -0
  129. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/cleanup/pagerduty_import_cleanup.json +0 -0
  130. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/scoped_analysis/__init__.py +0 -0
  131. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/jobs/scoped_analysis/semgrep_sca_risk_analysis.json +0 -0
  132. {cartography-0.96.1 → cartography-0.97.0}/cartography/data/permission_relationships.yaml +0 -0
  133. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/__init__.py +0 -0
  134. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/__main__.py +0 -0
  135. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/add_shortcut.py +0 -0
  136. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/cli.py +0 -0
  137. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/config.py +0 -0
  138. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/detect_deviations.py +0 -0
  139. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/get_states.py +0 -0
  140. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/model.py +0 -0
  141. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/reporter.py +0 -0
  142. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/serializers.py +0 -0
  143. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/shortcut.py +0 -0
  144. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/storage.py +0 -0
  145. {cartography-0.96.1 → cartography-0.97.0}/cartography/driftdetect/util.py +0 -0
  146. {cartography-0.96.1 → cartography-0.97.0}/cartography/graph/__init__.py +0 -0
  147. {cartography-0.96.1 → cartography-0.97.0}/cartography/graph/cleanupbuilder.py +0 -0
  148. {cartography-0.96.1 → cartography-0.97.0}/cartography/graph/context.py +0 -0
  149. {cartography-0.96.1 → cartography-0.97.0}/cartography/graph/job.py +0 -0
  150. {cartography-0.96.1 → cartography-0.97.0}/cartography/graph/querybuilder.py +0 -0
  151. {cartography-0.96.1 → cartography-0.97.0}/cartography/graph/statement.py +0 -0
  152. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/__init__.py +0 -0
  153. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/analysis.py +0 -0
  154. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/__init__.py +0 -0
  155. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/apigateway.py +0 -0
  156. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/config.py +0 -0
  157. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/dynamodb.py +0 -0
  158. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/__init__.py +0 -0
  159. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/auto_scaling_groups.py +0 -0
  160. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/elastic_ip_addresses.py +0 -0
  161. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/images.py +0 -0
  162. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/instances.py +0 -0
  163. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/internet_gateways.py +0 -0
  164. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/key_pairs.py +0 -0
  165. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/launch_templates.py +0 -0
  166. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/load_balancer_v2s.py +0 -0
  167. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/load_balancers.py +0 -0
  168. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/network_acls.py +0 -0
  169. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/network_interfaces.py +0 -0
  170. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/reserved_instances.py +0 -0
  171. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/security_groups.py +0 -0
  172. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/snapshots.py +0 -0
  173. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/subnets.py +0 -0
  174. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/tgw.py +0 -0
  175. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/util.py +0 -0
  176. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/volumes.py +0 -0
  177. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/vpc.py +0 -0
  178. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ec2/vpc_peerings.py +0 -0
  179. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ecr.py +0 -0
  180. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ecs.py +0 -0
  181. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/eks.py +0 -0
  182. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/elasticache.py +0 -0
  183. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/elasticsearch.py +0 -0
  184. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/emr.py +0 -0
  185. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/iam.py +0 -0
  186. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/inspector.py +0 -0
  187. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/kms.py +0 -0
  188. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/lambda_function.py +0 -0
  189. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/organizations.py +0 -0
  190. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/permission_relationships.py +0 -0
  191. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/rds.py +0 -0
  192. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/redshift.py +0 -0
  193. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/resourcegroupstaggingapi.py +0 -0
  194. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/resources.py +0 -0
  195. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/route53.py +0 -0
  196. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/s3.py +0 -0
  197. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/secretsmanager.py +0 -0
  198. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/securityhub.py +0 -0
  199. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/sqs.py +0 -0
  200. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/ssm.py +0 -0
  201. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/util/__init__.py +0 -0
  202. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/util/arns.py +0 -0
  203. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/aws/util/common.py +0 -0
  204. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/azure/__init__.py +0 -0
  205. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/azure/compute.py +0 -0
  206. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/azure/cosmosdb.py +0 -0
  207. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/azure/sql.py +0 -0
  208. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/azure/storage.py +0 -0
  209. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/azure/subscription.py +0 -0
  210. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/azure/tenant.py +0 -0
  211. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/azure/util/__init__.py +0 -0
  212. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/azure/util/credentials.py +0 -0
  213. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/bigfix/__init__.py +0 -0
  214. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/bigfix/computers.py +0 -0
  215. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/create_indexes.py +0 -0
  216. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/crowdstrike/__init__.py +0 -0
  217. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/crowdstrike/endpoints.py +0 -0
  218. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/crowdstrike/spotlight.py +0 -0
  219. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/crowdstrike/util.py +0 -0
  220. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/digitalocean/__init__.py +0 -0
  221. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/digitalocean/compute.py +0 -0
  222. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/digitalocean/management.py +0 -0
  223. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/digitalocean/platform.py +0 -0
  224. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/dns.py +0 -0
  225. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/duo/__init__.py +0 -0
  226. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/duo/api_host.py +0 -0
  227. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/duo/endpoints.py +0 -0
  228. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/duo/groups.py +0 -0
  229. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/duo/phones.py +0 -0
  230. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/duo/tokens.py +0 -0
  231. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/duo/users.py +0 -0
  232. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/duo/web_authn_credentials.py +0 -0
  233. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/gcp/__init__.py +0 -0
  234. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/gcp/compute.py +0 -0
  235. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/gcp/crm.py +0 -0
  236. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/gcp/dns.py +0 -0
  237. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/gcp/gke.py +0 -0
  238. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/gcp/storage.py +0 -0
  239. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/github/__init__.py +0 -0
  240. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/gsuite/__init__.py +0 -0
  241. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/gsuite/api.py +0 -0
  242. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/jamf/__init__.py +0 -0
  243. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/jamf/computers.py +0 -0
  244. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/jamf/util.py +0 -0
  245. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/kandji/__init__.py +0 -0
  246. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/kandji/devices.py +0 -0
  247. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/kubernetes/__init__.py +0 -0
  248. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/kubernetes/namespaces.py +0 -0
  249. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/kubernetes/pods.py +0 -0
  250. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/kubernetes/secrets.py +0 -0
  251. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/kubernetes/services.py +0 -0
  252. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/kubernetes/util.py +0 -0
  253. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/lastpass/__init__.py +0 -0
  254. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/lastpass/users.py +0 -0
  255. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/oci/__init__.py +0 -0
  256. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/oci/iam.py +0 -0
  257. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/oci/organizations.py +0 -0
  258. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/oci/utils.py +0 -0
  259. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/__init__.py +0 -0
  260. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/applications.py +0 -0
  261. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/awssaml.py +0 -0
  262. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/factors.py +0 -0
  263. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/groups.py +0 -0
  264. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/organization.py +0 -0
  265. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/origins.py +0 -0
  266. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/roles.py +0 -0
  267. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/sync_state.py +0 -0
  268. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/users.py +0 -0
  269. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/okta/utils.py +0 -0
  270. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/pagerduty/__init__.py +0 -0
  271. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/pagerduty/escalation_policies.py +0 -0
  272. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/pagerduty/schedules.py +0 -0
  273. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/pagerduty/services.py +0 -0
  274. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/pagerduty/teams.py +0 -0
  275. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/pagerduty/users.py +0 -0
  276. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/pagerduty/vendors.py +0 -0
  277. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/semgrep/__init__.py +0 -0
  278. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/semgrep/dependencies.py +0 -0
  279. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/semgrep/deployment.py +0 -0
  280. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/semgrep/findings.py +0 -0
  281. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/snipeit/__init__.py +0 -0
  282. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/snipeit/asset.py +0 -0
  283. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/snipeit/user.py +0 -0
  284. {cartography-0.96.1 → cartography-0.97.0}/cartography/intel/snipeit/util.py +0 -0
  285. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/__init__.py +0 -0
  286. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/__init__.py +0 -0
  287. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/dynamodb/__init__.py +0 -0
  288. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/dynamodb/gsi.py +0 -0
  289. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/dynamodb/tables.py +0 -0
  290. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/__init__.py +0 -0
  291. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/auto_scaling_groups.py +0 -0
  292. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/images.py +0 -0
  293. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/instances.py +0 -0
  294. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/keypairs.py +0 -0
  295. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/launch_configurations.py +0 -0
  296. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/launch_template_versions.py +0 -0
  297. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/launch_templates.py +0 -0
  298. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/loadbalancerv2.py +0 -0
  299. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/network_acl_rules.py +0 -0
  300. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/network_acls.py +0 -0
  301. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/networkinterface_instance.py +0 -0
  302. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/networkinterfaces.py +0 -0
  303. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/privateip_networkinterface.py +0 -0
  304. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/reservations.py +0 -0
  305. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/securitygroup_instance.py +0 -0
  306. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/securitygroup_networkinterface.py +0 -0
  307. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/subnet_instance.py +0 -0
  308. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/subnet_networkinterface.py +0 -0
  309. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ec2/volumes.py +0 -0
  310. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/eks/__init__.py +0 -0
  311. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/eks/clusters.py +0 -0
  312. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/emr.py +0 -0
  313. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/identitycenter/__init__.py +0 -0
  314. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/identitycenter/awsidentitycenter.py +0 -0
  315. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/identitycenter/awspermissionset.py +0 -0
  316. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/identitycenter/awsssouser.py +0 -0
  317. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/inspector/__init__.py +0 -0
  318. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/inspector/findings.py +0 -0
  319. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/inspector/packages.py +0 -0
  320. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ssm/__init__.py +0 -0
  321. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ssm/instance_information.py +0 -0
  322. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/aws/ssm/instance_patch.py +0 -0
  323. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/bigfix/__init__.py +0 -0
  324. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/bigfix/bigfix_computer.py +0 -0
  325. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/bigfix/bigfix_root.py +0 -0
  326. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/core/__init__.py +0 -0
  327. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/core/common.py +0 -0
  328. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/core/nodes.py +0 -0
  329. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/core/relationships.py +0 -0
  330. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/cve/__init__.py +0 -0
  331. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/cve/cve.py +0 -0
  332. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/cve/cve_feed.py +0 -0
  333. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/duo/__init__.py +0 -0
  334. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/duo/api_host.py +0 -0
  335. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/duo/endpoint.py +0 -0
  336. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/duo/group.py +0 -0
  337. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/duo/phone.py +0 -0
  338. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/duo/token.py +0 -0
  339. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/duo/user.py +0 -0
  340. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/duo/web_authn_credential.py +0 -0
  341. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/github/__init__.py +0 -0
  342. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/kandji/__init__.py +0 -0
  343. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/kandji/device.py +0 -0
  344. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/kandji/tenant.py +0 -0
  345. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/lastpass/__init__.py +0 -0
  346. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/lastpass/tenant.py +0 -0
  347. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/lastpass/user.py +0 -0
  348. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/semgrep/__init__.py +0 -0
  349. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/semgrep/dependencies.py +0 -0
  350. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/semgrep/deployment.py +0 -0
  351. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/semgrep/findings.py +0 -0
  352. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/semgrep/locations.py +0 -0
  353. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/snipeit/__init__.py +0 -0
  354. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/snipeit/asset.py +0 -0
  355. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/snipeit/tenant.py +0 -0
  356. {cartography-0.96.1 → cartography-0.97.0}/cartography/models/snipeit/user.py +0 -0
  357. {cartography-0.96.1 → cartography-0.97.0}/cartography/py.typed +0 -0
  358. {cartography-0.96.1 → cartography-0.97.0}/cartography/stats.py +0 -0
  359. {cartography-0.96.1 → cartography-0.97.0}/cartography/sync.py +0 -0
  360. {cartography-0.96.1 → cartography-0.97.0}/cartography/util.py +0 -0
  361. {cartography-0.96.1 → cartography-0.97.0}/cartography.egg-info/SOURCES.txt +0 -0
  362. {cartography-0.96.1 → cartography-0.97.0}/cartography.egg-info/dependency_links.txt +0 -0
  363. {cartography-0.96.1 → cartography-0.97.0}/cartography.egg-info/entry_points.txt +0 -0
  364. {cartography-0.96.1 → cartography-0.97.0}/cartography.egg-info/requires.txt +0 -0
  365. {cartography-0.96.1 → cartography-0.97.0}/cartography.egg-info/top_level.txt +0 -0
  366. {cartography-0.96.1 → cartography-0.97.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cartography
3
- Version: 0.96.1
3
+ Version: 0.97.0
4
4
  Summary: Explore assets and their relationships across your technical infrastructure.
5
5
  Home-page: https://www.github.com/cartography-cncf/cartography
6
6
  Maintainer: Cartography Contributors
@@ -56,6 +56,7 @@ def load_identity_center_instances(
56
56
 
57
57
 
58
58
  @timeit
59
+ @aws_handle_regions
59
60
  def get_permission_sets(boto3_session: boto3.session.Session, instance_arn: str, region: str) -> List[Dict]:
60
61
  """
61
62
  Get all permission sets for a given Identity Center instance
@@ -2,6 +2,9 @@ import logging
2
2
  from datetime import datetime
3
3
 
4
4
  import neo4j
5
+ from requests import Session
6
+ from requests.adapters import HTTPAdapter
7
+ from urllib3 import Retry
5
8
 
6
9
  from cartography.config import Config
7
10
  from cartography.intel.cve import feed
@@ -13,28 +16,34 @@ logger = logging.getLogger(__name__)
13
16
  stat_handler = get_stats_client(__name__)
14
17
 
15
18
 
16
- @timeit
17
- def start_cve_ingestion(
18
- neo4j_session: neo4j.Session, config: Config,
19
- ) -> None:
20
- """
21
- Perform ingestion of CVE data from NIST APIs.
22
- :param neo4j_session: Neo4J session for database interface
23
- :param config: A cartography.config object
24
- :return: None
25
- """
26
- if not config.cve_enabled:
27
- return
28
- cve_api_key: str | None = config.cve_api_key if config.cve_api_key else None
19
+ def _retryable_session() -> Session:
20
+ session = Session()
21
+ retry_policy = Retry(
22
+ total=8,
23
+ connect=1,
24
+ backoff_factor=1,
25
+ status_forcelist=[429, 500, 502, 503, 504],
26
+ allowed_methods=["GET"],
27
+ )
28
+ session.mount("https://", HTTPAdapter(max_retries=retry_policy))
29
+ logger.info(f"Configured session with retry policy: {retry_policy}")
30
+ return session
29
31
 
30
- # sync CVE year archives, if not yet synced
32
+
33
+ def _sync_year_archives(
34
+ http_session: Session,
35
+ neo4j_session: neo4j.Session,
36
+ config: Config,
37
+ cve_api_key: str | None,
38
+ ) -> None:
31
39
  existing_years = feed.get_cve_sync_metadata(neo4j_session)
32
40
  current_year = datetime.now().year
33
- for year in range(2002, current_year + 1):
41
+ logger.info(f"Syncing CVE data for year archives. Existing years: {existing_years}. Current year: {current_year}")
42
+ for year in range(1999, current_year + 1):
34
43
  if year in existing_years:
35
44
  continue
36
45
  logger.info(f"Syncing CVE data for year {year}")
37
- cves = feed.get_published_cves_per_year(config.nist_cve_url, str(year), cve_api_key)
46
+ cves = feed.get_published_cves_per_year(http_session, config.nist_cve_url, str(year), cve_api_key)
38
47
  feed_metadata = feed.transform_cve_feed(cves)
39
48
  feed.load_cve_feed(neo4j_session, [feed_metadata], config.update_tag)
40
49
  published_cves = feed.transform_cves(cves)
@@ -48,10 +57,16 @@ def start_cve_ingestion(
48
57
  stat_handler=stat_handler,
49
58
  )
50
59
 
51
- # sync modified data
60
+
61
+ def _sync_modified_data(
62
+ http_session: Session,
63
+ neo4j_session: neo4j.Session,
64
+ config: Config,
65
+ cve_api_key: str | None,
66
+ ) -> None:
52
67
  logger.info("Syncing CVE data for modified data")
53
68
  last_modified_date = feed.get_last_modified_cve_date(neo4j_session)
54
- cves = feed.get_modified_cves(config.nist_cve_url, last_modified_date, cve_api_key)
69
+ cves = feed.get_modified_cves(http_session, config.nist_cve_url, last_modified_date, cve_api_key)
55
70
  feed_metadata = feed.transform_cve_feed(cves)
56
71
  feed.load_cve_feed(neo4j_session, [feed_metadata], config.update_tag)
57
72
  modified_cves = feed.transform_cves(cves)
@@ -65,4 +80,21 @@ def start_cve_ingestion(
65
80
  stat_handler=stat_handler,
66
81
  )
67
82
 
68
- # CVEs are never deleted, so we don't need to run a cleanup job
83
+
84
+ @timeit
85
+ def start_cve_ingestion(
86
+ neo4j_session: neo4j.Session, config: Config,
87
+ ) -> None:
88
+ """
89
+ Perform ingestion of CVE data from NIST APIs.
90
+ :param neo4j_session: Neo4J session for database interface
91
+ :param config: A cartography.config object
92
+ :return: None
93
+ """
94
+ if not config.cve_enabled:
95
+ return
96
+ cve_api_key: str | None = config.cve_api_key if config.cve_api_key else None
97
+ with _retryable_session() as http_session:
98
+ _sync_year_archives(http_session, neo4j_session=neo4j_session, config=config, cve_api_key=cve_api_key)
99
+ _sync_modified_data(http_session, neo4j_session=neo4j_session, config=config, cve_api_key=cve_api_key)
100
+ # CVEs are never deleted, so we don't need to run a cleanup job
@@ -11,7 +11,7 @@ from typing import List
11
11
  from typing import Optional
12
12
 
13
13
  import neo4j
14
- import requests
14
+ from requests import Session
15
15
 
16
16
  from cartography.client.core.tx import load
17
17
  from cartography.client.core.tx import read_list_of_values_tx
@@ -22,7 +22,6 @@ from cartography.util import timeit
22
22
 
23
23
  logger = logging.getLogger(__name__)
24
24
 
25
- MAX_RETRIES = 8
26
25
  # Connect and read timeouts of 120 seconds each; see https://requests.readthedocs.io/en/master/user/advanced/#timeouts
27
26
  CONNECT_AND_READ_TIMEOUT = (30, 120)
28
27
  CVE_FEED_ID = "NIST_NVD"
@@ -68,51 +67,36 @@ def _map_cve_dict(cve_dict: Dict[Any, Any], data: Dict[Any, Any]) -> None:
68
67
  cve_dict["startIndex"] = data["startIndex"]
69
68
 
70
69
 
71
- def _call_cves_api(url: str, api_key: str | None, params: Dict[str, Any]) -> Dict[Any, Any]:
72
- totalResults = 0
73
- sleep_time = DEFAULT_SLEEP_TIME
74
- retries = 0
70
+ def _call_cves_api(http_session: Session, url: str, api_key: str | None, params: Dict[str, Any]) -> Dict[Any, Any]:
71
+ total_results = 0
75
72
  params["startIndex"] = 0
76
73
  params["resultsPerPage"] = RESULTS_PER_PAGE
77
- headers = {}
78
- headers["Content-Type"] = "application/json"
74
+ headers = {"Content-Type": "application/json"}
79
75
  if api_key:
76
+ sleep_between_requests = DEFAULT_SLEEP_TIME
80
77
  headers["apiKey"] = api_key
81
78
  else:
82
- sleep_time = DELAYED_SLEEP_TIME # Sleep for 6 seconds between each request to avoid rate limiting
79
+ sleep_between_requests = DELAYED_SLEEP_TIME
83
80
  logger.warning(
84
- f"No NIST NVD API key provided. Increasing sleep time to {sleep_time}.",
81
+ f"No NIST NVD API key provided. Increasing sleep time to {sleep_between_requests}.",
85
82
  )
86
83
  results: Dict[Any, Any] = dict()
87
84
 
88
- while params["resultsPerPage"] > 0 or params["startIndex"] < totalResults:
89
- try:
90
- res = requests.get(
91
- url, params=params, headers=headers, timeout=CONNECT_AND_READ_TIMEOUT,
92
- )
93
- res.raise_for_status()
94
- except requests.exceptions.HTTPError:
95
- logger.error(
96
- f"Failed to get CVE data from NIST NVD API {res.status_code} : {res.text}",
97
- )
98
- retries += 1
99
- if retries >= MAX_RETRIES:
100
- raise
101
- # Exponential backoff
102
- sleep_time *= 2
103
- time.sleep(sleep_time)
104
- continue
85
+ while params["resultsPerPage"] > 0 or params["startIndex"] < total_results:
86
+ logger.info(f"Calling NIST NVD API at {url} with params {params}")
87
+ res = http_session.get(url, params=params, headers=headers, timeout=CONNECT_AND_READ_TIMEOUT)
88
+ res.raise_for_status()
105
89
  data = res.json()
106
90
  _map_cve_dict(results, data)
107
- totalResults = data["totalResults"]
91
+ total_results = data["totalResults"]
108
92
  params["resultsPerPage"] = data["resultsPerPage"]
109
93
  params["startIndex"] += data["resultsPerPage"]
110
- retries = 0
111
- time.sleep(sleep_time)
94
+ time.sleep(sleep_between_requests)
112
95
  return results
113
96
 
114
97
 
115
98
  def get_cves_in_batches(
99
+ http_session: Session,
116
100
  nist_cve_url: str,
117
101
  start_date: datetime,
118
102
  end_date: datetime,
@@ -145,7 +129,7 @@ def get_cves_in_batches(
145
129
  logger.info(
146
130
  f"Querying CVE data between {current_start_date} and {current_end_date}",
147
131
  )
148
- batch_cves = _call_cves_api(nist_cve_url, api_key, params)
132
+ batch_cves = _call_cves_api(http_session, nist_cve_url, api_key, params)
149
133
  _map_cve_dict(cves, batch_cves)
150
134
  current_start_date = current_end_date
151
135
  new_end_date = current_start_date + batch_size
@@ -156,9 +140,8 @@ def get_cves_in_batches(
156
140
 
157
141
 
158
142
  def get_modified_cves(
159
- nist_cve_url: str, last_modified_date: str, api_key: str | None,
143
+ http_session: Session, nist_cve_url: str, last_modified_date: str, api_key: str | None,
160
144
  ) -> Dict[Any, Any]:
161
- cves = dict()
162
145
  end_date = datetime.now(tz=timezone.utc)
163
146
  start_date = datetime.strptime(last_modified_date, "%Y-%m-%dT%H:%M:%S").replace(
164
147
  tzinfo=timezone.utc,
@@ -168,15 +151,14 @@ def get_modified_cves(
168
151
  "end": "lastModEndDate",
169
152
  }
170
153
  cves = get_cves_in_batches(
171
- nist_cve_url, start_date, end_date, date_param_names, api_key,
154
+ http_session, nist_cve_url, start_date, end_date, date_param_names, api_key,
172
155
  )
173
156
  return cves
174
157
 
175
158
 
176
159
  def get_published_cves_per_year(
177
- nist_cve_url: str, year: str, api_key: str | None,
160
+ http_session: Session, nist_cve_url: str, year: str, api_key: str | None,
178
161
  ) -> Dict[Any, Any]:
179
- cves = {}
180
162
  start_of_year = datetime.strptime(f"{year}-01-01", "%Y-%m-%d")
181
163
  next_year = int(year) + 1
182
164
  end_of_next_year = datetime.strptime(f"{next_year}-01-01", "%Y-%m-%d")
@@ -185,7 +167,7 @@ def get_published_cves_per_year(
185
167
  "end": "pubEndDate",
186
168
  }
187
169
  cves = get_cves_in_batches(
188
- nist_cve_url, start_of_year, end_of_next_year, date_param_names, api_key,
170
+ http_session, nist_cve_url, start_of_year, end_of_next_year, date_param_names, api_key,
189
171
  )
190
172
  return cves
191
173
 
@@ -140,22 +140,40 @@ def _get_repo_collaborators_inner_func(
140
140
  org: str,
141
141
  api_url: str,
142
142
  token: str,
143
- repo_name: str,
143
+ repo_raw_data: list[dict[str, Any]],
144
144
  affiliation: str,
145
145
  collab_users: list[dict[str, Any]],
146
146
  collab_permission: list[str],
147
- ) -> None:
148
- logger.info(f"Loading {affiliation} collaborators for repo {repo_name}.")
149
- collaborators = _get_repo_collaborators(token, api_url, org, repo_name, affiliation)
147
+ ) -> dict[str, list[UserAffiliationAndRepoPermission]]:
148
+ result: dict[str, list[UserAffiliationAndRepoPermission]] = {}
149
+
150
+ for repo in repo_raw_data:
151
+ repo_name = repo['name']
152
+ repo_url = repo['url']
153
+
154
+ if ((affiliation == 'OUTSIDE' and repo['outsideCollaborators']['totalCount'] == 0) or
155
+ (affiliation == 'DIRECT' and repo['directCollaborators']['totalCount'] == 0)):
156
+ # repo has no collabs of the affiliation type we're looking for, so don't waste time making an API call
157
+ result[repo_url] = []
158
+ continue
159
+
160
+ logger.info(f"Loading {affiliation} collaborators for repo {repo_name}.")
161
+ collaborators = _get_repo_collaborators(token, api_url, org, repo_name, affiliation)
150
162
 
151
- # nodes and edges are expected to always be present given that we only call for them if totalCount is > 0
152
- # however sometimes GitHub returns None, as in issue 1334 and 1404.
153
- for collab in collaborators.nodes or []:
154
- collab_users.append(collab)
163
+ # nodes and edges are expected to always be present given that we only call for them if totalCount is > 0
164
+ # however sometimes GitHub returns None, as in issue 1334 and 1404.
165
+ for collab in collaborators.nodes or []:
166
+ collab_users.append(collab)
155
167
 
156
- # The `or []` is because `.edges` can be None.
157
- for perm in collaborators.edges or []:
158
- collab_permission.append(perm['permission'])
168
+ # The `or []` is because `.edges` can be None.
169
+ for perm in collaborators.edges or []:
170
+ collab_permission.append(perm['permission'])
171
+
172
+ result[repo_url] = [
173
+ UserAffiliationAndRepoPermission(user, permission, affiliation)
174
+ for user, permission in zip(collab_users, collab_permission)
175
+ ]
176
+ return result
159
177
 
160
178
 
161
179
  def _get_repo_collaborators_for_multiple_repos(
@@ -175,39 +193,24 @@ def _get_repo_collaborators_for_multiple_repos(
175
193
  :param token: The Github API token as string.
176
194
  :return: A dictionary of repo URL to list of UserAffiliationAndRepoPermission
177
195
  """
178
- result: dict[str, list[UserAffiliationAndRepoPermission]] = {}
179
- for repo in repo_raw_data:
180
- repo_name = repo['name']
181
- repo_url = repo['url']
182
-
183
- if ((affiliation == 'OUTSIDE' and repo['outsideCollaborators']['totalCount'] == 0) or
184
- (affiliation == 'DIRECT' and repo['directCollaborators']['totalCount'] == 0)):
185
- # repo has no collabs of the affiliation type we're looking for, so don't waste time making an API call
186
- result[repo_url] = []
187
- continue
188
-
189
- collab_users: List[dict[str, Any]] = []
190
- collab_permission: List[str] = []
191
-
192
- retries_with_backoff(
193
- _get_repo_collaborators_inner_func,
194
- TypeError,
195
- 5,
196
- backoff_handler,
197
- )(
198
- org=org,
199
- api_url=api_url,
200
- token=token,
201
- repo_name=repo_name,
202
- affiliation=affiliation,
203
- collab_users=collab_users,
204
- collab_permission=collab_permission,
205
- )
206
-
207
- result[repo_url] = [
208
- UserAffiliationAndRepoPermission(user, permission, affiliation)
209
- for user, permission in zip(collab_users, collab_permission)
210
- ]
196
+ logger.info(f'Retrieving repo collaborators for affiliation "{affiliation}" on org "{org}".')
197
+ collab_users: List[dict[str, Any]] = []
198
+ collab_permission: List[str] = []
199
+
200
+ result: dict[str, list[UserAffiliationAndRepoPermission]] = retries_with_backoff(
201
+ _get_repo_collaborators_inner_func,
202
+ TypeError,
203
+ 5,
204
+ backoff_handler,
205
+ )(
206
+ org=org,
207
+ api_url=api_url,
208
+ token=token,
209
+ repo_raw_data=repo_raw_data,
210
+ affiliation=affiliation,
211
+ collab_users=collab_users,
212
+ collab_permission=collab_permission,
213
+ )
211
214
  return result
212
215
 
213
216
 
@@ -260,8 +263,9 @@ def get(token: str, api_url: str, organization: str) -> List[Dict]:
260
263
 
261
264
 
262
265
  def transform(
263
- repos_json: List[Dict], direct_collaborators: dict[str, List[UserAffiliationAndRepoPermission]],
264
- outside_collaborators: dict[str, List[UserAffiliationAndRepoPermission]],
266
+ repos_json: List[Dict],
267
+ direct_collaborators: dict[str, List[UserAffiliationAndRepoPermission]],
268
+ outside_collaborators: dict[str, List[UserAffiliationAndRepoPermission]],
265
269
  ) -> Dict:
266
270
  """
267
271
  Parses the JSON returned from GitHub API to create data for graph ingestion
@@ -289,16 +293,24 @@ def transform(
289
293
  _transform_repo_languages(repo_object['url'], repo_object, transformed_repo_languages)
290
294
  _transform_repo_objects(repo_object, transformed_repo_list)
291
295
  _transform_repo_owners(repo_object['owner']['url'], repo_object, transformed_repo_owners)
292
- _transform_collaborators(
293
- repo_object['url'], outside_collaborators[repo_object['url']],
294
- transformed_outside_collaborators,
295
- )
296
- _transform_collaborators(
297
- repo_object['url'], direct_collaborators[repo_object['url']],
298
- transformed_direct_collaborators,
299
- )
300
- _transform_requirements_txt(repo_object['requirements'], repo_object['url'], transformed_requirements_files)
301
- _transform_setup_cfg_requirements(repo_object['setupCfg'], repo_object['url'], transformed_requirements_files)
296
+
297
+ # Allow sync to continue if we didn't have permissions to list collaborators
298
+ repo_url = repo_object['url']
299
+ if repo_url in outside_collaborators:
300
+ _transform_collaborators(
301
+ repo_object['url'],
302
+ outside_collaborators[repo_object['url']],
303
+ transformed_outside_collaborators,
304
+ )
305
+ if repo_url in direct_collaborators:
306
+ _transform_collaborators(
307
+ repo_object['url'],
308
+ direct_collaborators[repo_object['url']],
309
+ transformed_direct_collaborators,
310
+ )
311
+
312
+ _transform_requirements_txt(repo_object['requirements'], repo_url, transformed_requirements_files)
313
+ _transform_setup_cfg_requirements(repo_object['setupCfg'], repo_url, transformed_requirements_files)
302
314
  results = {
303
315
  'repos': transformed_repo_list,
304
316
  'repo_languages': transformed_repo_languages,
@@ -737,12 +749,18 @@ def sync(
737
749
  """
738
750
  logger.info("Syncing GitHub repos")
739
751
  repos_json = get(github_api_key, github_url, organization)
740
- direct_collabs = _get_repo_collaborators_for_multiple_repos(
741
- repos_json, "DIRECT", organization, github_url, github_api_key,
742
- )
743
- outside_collabs = _get_repo_collaborators_for_multiple_repos(
744
- repos_json, "OUTSIDE", organization, github_url, github_api_key,
745
- )
752
+ direct_collabs: dict[str, list[UserAffiliationAndRepoPermission]] = {}
753
+ outside_collabs: dict[str, list[UserAffiliationAndRepoPermission]] = {}
754
+ try:
755
+ direct_collabs = _get_repo_collaborators_for_multiple_repos(
756
+ repos_json, "DIRECT", organization, github_url, github_api_key,
757
+ )
758
+ outside_collabs = _get_repo_collaborators_for_multiple_repos(
759
+ repos_json, "OUTSIDE", organization, github_url, github_api_key,
760
+ )
761
+ except TypeError:
762
+ # due to permission errors or transient network error or some other nonsense
763
+ logger.warning('Unable to list repo collaborators due to permission errors; continuing on.', exc_info=True)
746
764
  repo_data = transform(repos_json, direct_collabs, outside_collabs)
747
765
  load(neo4j_session, common_job_parameters, repo_data)
748
766
  run_cleanup_job('github_repos_cleanup.json', neo4j_session, common_job_parameters)
@@ -21,6 +21,9 @@ logger = logging.getLogger(__name__)
21
21
  RepoPermission = namedtuple('RepoPermission', ['repo_url', 'permission'])
22
22
  # A team member's role: https://docs.github.com/en/graphql/reference/enums#teammemberrole
23
23
  UserRole = namedtuple('UserRole', ['user_url', 'role'])
24
+ # Unlike the other tuples here, there is no qualification (like 'role' or 'permission') to the relationship.
25
+ # A child team is just a child team: https://docs.github.com/en/graphql/reference/objects#teamconnection
26
+ ChildTeam = namedtuple('ChildTeam', ['team_url'])
24
27
 
25
28
 
26
29
  def backoff_handler(details: Dict) -> None:
@@ -53,6 +56,9 @@ def get_teams(org: str, api_url: str, token: str) -> Tuple[PaginatedGraphqlData,
53
56
  members(membership: IMMEDIATE) {
54
57
  totalCount
55
58
  }
59
+ childTeams {
60
+ totalCount
61
+ }
56
62
  }
57
63
  pageInfo{
58
64
  endCursor
@@ -166,6 +172,21 @@ def _get_team_repos(org: str, api_url: str, token: str, team: str) -> PaginatedG
166
172
  return team_repos
167
173
 
168
174
 
175
+ def _get_teams_users_inner_func(
176
+ org: str, api_url: str, token: str, team_name: str,
177
+ user_urls: List[str], user_roles: List[str],
178
+ ) -> None:
179
+ logger.info(f"Loading team users for {team_name}.")
180
+ team_users = _get_team_users(org, api_url, token, team_name)
181
+ # The `or []` is because `.nodes` can be None. See:
182
+ # https://docs.github.com/en/graphql/reference/objects#teammemberconnection
183
+ for user in team_users.nodes or []:
184
+ user_urls.append(user['url'])
185
+ # The `or []` is because `.edges` can be None.
186
+ for edge in team_users.edges or []:
187
+ user_roles.append(edge['role'])
188
+
189
+
169
190
  def _get_team_users_for_multiple_teams(
170
191
  team_raw_data: list[dict[str, Any]],
171
192
  org: str,
@@ -185,21 +206,7 @@ def _get_team_users_for_multiple_teams(
185
206
  user_urls: List[str] = []
186
207
  user_roles: List[str] = []
187
208
 
188
- def get_teams_users_inner_func(
189
- org: str, api_url: str, token: str, team_name: str,
190
- user_urls: List[str], user_roles: List[str],
191
- ) -> None:
192
- logger.info(f"Loading team users for {team_name}.")
193
- team_users = _get_team_users(org, api_url, token, team_name)
194
- # The `or []` is because `.nodes` can be None. See:
195
- # https://docs.github.com/en/graphql/reference/objects#teammemberconnection
196
- for user in team_users.nodes or []:
197
- user_urls.append(user['url'])
198
- # The `or []` is because `.edges` can be None.
199
- for edge in team_users.edges or []:
200
- user_roles.append(edge['role'])
201
-
202
- retries_with_backoff(get_teams_users_inner_func, TypeError, 5, backoff_handler)(
209
+ retries_with_backoff(_get_teams_users_inner_func, TypeError, 5, backoff_handler)(
203
210
  org=org, api_url=api_url, token=token, team_name=team_name, user_urls=user_urls, user_roles=user_roles,
204
211
  )
205
212
 
@@ -252,11 +259,90 @@ def _get_team_users(org: str, api_url: str, token: str, team: str) -> PaginatedG
252
259
  return team_users
253
260
 
254
261
 
262
+ def _get_child_teams_inner_func(
263
+ org: str, api_url: str, token: str, team_name: str, team_urls: List[str],
264
+ ) -> None:
265
+ logger.info(f"Loading child teams for {team_name}.")
266
+ child_teams = _get_child_teams(org, api_url, token, team_name)
267
+ # The `or []` is because `.nodes` can be None. See:
268
+ # https://docs.github.com/en/graphql/reference/objects#teammemberconnection
269
+ for cteam in child_teams.nodes or []:
270
+ team_urls.append(cteam['url'])
271
+ # No edges to process here, the GitHub response for child teams has no relevant info in edges.
272
+
273
+
274
+ def _get_child_teams_for_multiple_teams(
275
+ team_raw_data: list[dict[str, Any]],
276
+ org: str,
277
+ api_url: str,
278
+ token: str,
279
+ ) -> dict[str, list[ChildTeam]]:
280
+ result: dict[str, list[ChildTeam]] = {}
281
+ for team in team_raw_data:
282
+ team_name = team['slug']
283
+ team_count = team['childTeams']['totalCount']
284
+
285
+ if team_count == 0:
286
+ # This team has no child teams so let's move on
287
+ result[team_name] = []
288
+ continue
289
+
290
+ team_urls: List[str] = []
291
+
292
+ retries_with_backoff(_get_child_teams_inner_func, TypeError, 5, backoff_handler)(
293
+ org=org, api_url=api_url, token=token, team_name=team_name, team_urls=team_urls,
294
+ )
295
+
296
+ result[team_name] = [ChildTeam(url) for url in team_urls]
297
+ return result
298
+
299
+
300
+ def _get_child_teams(org: str, api_url: str, token: str, team: str) -> PaginatedGraphqlData:
301
+ team_users_gql = """
302
+ query($login: String!, $team: String!, $cursor: String) {
303
+ organization(login: $login) {
304
+ url
305
+ login
306
+ team(slug: $team) {
307
+ slug
308
+ childTeams(first: 100, after: $cursor) {
309
+ totalCount
310
+ nodes {
311
+ url
312
+ }
313
+ pageInfo {
314
+ endCursor
315
+ hasNextPage
316
+ }
317
+ }
318
+ }
319
+ }
320
+ rateLimit {
321
+ limit
322
+ cost
323
+ remaining
324
+ resetAt
325
+ }
326
+ }
327
+ """
328
+ team_users, _ = fetch_all(
329
+ token,
330
+ api_url,
331
+ org,
332
+ team_users_gql,
333
+ 'team',
334
+ resource_inner_type='childTeams',
335
+ team=team,
336
+ )
337
+ return team_users
338
+
339
+
255
340
  def transform_teams(
256
341
  team_paginated_data: PaginatedGraphqlData,
257
342
  org_data: Dict[str, Any],
258
343
  team_repo_data: dict[str, list[RepoPermission]],
259
344
  team_user_data: dict[str, list[UserRole]],
345
+ team_child_team_data: dict[str, list[ChildTeam]],
260
346
  ) -> list[dict[str, Any]]:
261
347
  result = []
262
348
  for team in team_paginated_data.nodes:
@@ -267,13 +353,15 @@ def transform_teams(
267
353
  'description': team['description'],
268
354
  'repo_count': team['repositories']['totalCount'],
269
355
  'member_count': team['members']['totalCount'],
356
+ 'child_team_count': team['childTeams']['totalCount'],
270
357
  'org_url': org_data['url'],
271
358
  'org_login': org_data['login'],
272
359
  }
273
360
  repo_permissions = team_repo_data[team_name]
274
361
  user_roles = team_user_data[team_name]
362
+ child_teams = team_child_team_data[team_name]
275
363
 
276
- if not repo_permissions and not user_roles:
364
+ if not repo_permissions and not user_roles and not child_teams:
277
365
  result.append(repo_info)
278
366
  continue
279
367
 
@@ -289,6 +377,15 @@ def transform_teams(
289
377
  repo_info_copy = repo_info.copy()
290
378
  repo_info_copy[role] = user_url
291
379
  result.append(repo_info_copy)
380
+ if child_teams:
381
+ for (team_url,) in child_teams:
382
+ repo_info_copy = repo_info.copy()
383
+ # GitHub speaks of team-team relationships as 'child teams', as in the graphql query
384
+ # or here: https://docs.github.com/en/graphql/reference/enums#teammembershiptype
385
+ # We label the relationship as 'MEMBER_OF_TEAM' here because it is in line with
386
+ # other similar relationships in Cartography.
387
+ repo_info_copy['MEMBER_OF_TEAM'] = team_url
388
+ result.append(repo_info_copy)
292
389
  return result
293
390
 
294
391
 
@@ -325,7 +422,8 @@ def sync_github_teams(
325
422
  teams_paginated, org_data = get_teams(organization, github_url, github_api_key)
326
423
  team_repos = _get_team_repos_for_multiple_teams(teams_paginated.nodes, organization, github_url, github_api_key)
327
424
  team_users = _get_team_users_for_multiple_teams(teams_paginated.nodes, organization, github_url, github_api_key)
328
- processed_data = transform_teams(teams_paginated, org_data, team_repos, team_users)
425
+ team_children = _get_child_teams_for_multiple_teams(teams_paginated.nodes, organization, github_url, github_api_key)
426
+ processed_data = transform_teams(teams_paginated, org_data, team_repos, team_users, team_children)
329
427
  load_team_repos(neo4j_session, processed_data, common_job_parameters['UPDATE_TAG'], org_data['url'])
330
428
  common_job_parameters['org_url'] = org_data['url']
331
429
  cleanup(neo4j_session, common_job_parameters)
@@ -90,6 +90,7 @@ def get_users(token: str, api_url: str, organization: str) -> Tuple[List[Dict],
90
90
  2. data on the owning GitHub organization
91
91
  see tests.data.github.users.GITHUB_USER_DATA for shape of both
92
92
  """
93
+ logger.info(f"Retrieving users from GitHub organization {organization}")
93
94
  users, org = fetch_all(
94
95
  token,
95
96
  api_url,
@@ -112,6 +113,7 @@ def get_enterprise_owners(token: str, api_url: str, organization: str) -> Tuple[
112
113
  3. data on the owning GitHub organization
113
114
  see tests.data.github.users.GITHUB_ENTERPRISE_OWNER_DATA for shape
114
115
  """
116
+ logger.info(f"Retrieving enterprise owners from GitHub organization {organization}")
115
117
  owners, org = fetch_all(
116
118
  token,
117
119
  api_url,
@@ -142,10 +144,13 @@ def transform_users(user_data: List[Dict], owners_data: List[Dict], org_data: Di
142
144
 
143
145
  users_dict = {}
144
146
  for user in user_data:
147
+ # all members get the 'MEMBER_OF' relationship
145
148
  processed_user = deepcopy(user['node'])
146
- processed_user['role'] = user['role']
147
149
  processed_user['hasTwoFactorEnabled'] = user['hasTwoFactorEnabled']
148
150
  processed_user['MEMBER_OF'] = org_data['url']
151
+ # admins get a second relationship expressing them as such
152
+ if user['role'] == 'ADMIN':
153
+ processed_user['ADMIN_OF'] = org_data['url']
149
154
  users_dict[processed_user['url']] = processed_user
150
155
 
151
156
  owners_dict = {}
@@ -163,7 +163,8 @@ def fetch_all(
163
163
 
164
164
  if retry >= retries:
165
165
  logger.error(
166
- f"GitHub: Could not retrieve page of resource `{resource_type}` due to HTTP error.",
166
+ f"GitHub: Could not retrieve page of resource `{resource_type}` due to HTTP error "
167
+ f"after {retry} retries. Raising exception.",
167
168
  exc_info=True,
168
169
  )
169
170
  raise exc