cartography 0.93.0rc1__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.
- cartography/__main__.py +1 -2
- cartography/_version.py +34 -0
- cartography/cli.py +903 -225
- cartography/client/aws/__init__.py +19 -0
- cartography/client/aws/ecr.py +51 -0
- cartography/client/core/tx.py +400 -27
- cartography/config.py +215 -10
- cartography/data/azure_permission_relationships.yaml +20 -0
- cartography/data/gcp_permission_relationships.yaml +21 -0
- cartography/data/indexes.cypher +1 -200
- cartography/data/jobs/analysis/aws_ec2_asset_exposure.json +17 -2
- cartography/data/jobs/analysis/aws_ec2_keypair_analysis.json +2 -2
- cartography/data/jobs/analysis/gcp_compute_asset_inet_exposure.json +1 -1
- cartography/data/jobs/analysis/keycloak_inheritance.json +30 -0
- cartography/data/jobs/cleanup/crowdstrike_import_cleanup.json +0 -5
- cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json +0 -12
- cartography/data/jobs/cleanup/github_repos_cleanup.json +27 -0
- cartography/data/jobs/scoped_analysis/aws_ec2_iaminstanceprofile.json +15 -0
- cartography/data/jobs/scoped_analysis/semgrep_sca_risk_analysis.json +13 -13
- cartography/driftdetect/__main__.py +1 -2
- cartography/driftdetect/add_shortcut.py +10 -2
- cartography/driftdetect/cli.py +72 -75
- cartography/driftdetect/detect_deviations.py +7 -3
- cartography/driftdetect/get_states.py +20 -8
- cartography/driftdetect/model.py +5 -5
- cartography/driftdetect/serializers.py +8 -6
- cartography/driftdetect/storage.py +2 -2
- cartography/graph/cleanupbuilder.py +255 -35
- cartography/graph/job.py +104 -20
- cartography/graph/querybuilder.py +689 -91
- cartography/graph/statement.py +49 -36
- cartography/intel/airbyte/__init__.py +105 -0
- cartography/intel/airbyte/connections.py +120 -0
- cartography/intel/airbyte/destinations.py +81 -0
- cartography/intel/airbyte/organizations.py +59 -0
- cartography/intel/airbyte/sources.py +78 -0
- cartography/intel/airbyte/tags.py +64 -0
- cartography/intel/airbyte/users.py +106 -0
- cartography/intel/airbyte/util.py +122 -0
- cartography/intel/airbyte/workspaces.py +63 -0
- cartography/intel/analysis.py +4 -1
- cartography/intel/anthropic/__init__.py +62 -0
- cartography/intel/anthropic/apikeys.py +72 -0
- cartography/intel/anthropic/users.py +75 -0
- cartography/intel/anthropic/util.py +51 -0
- cartography/intel/anthropic/workspaces.py +95 -0
- cartography/intel/aws/__init__.py +137 -59
- cartography/intel/aws/acm.py +124 -0
- cartography/intel/aws/apigateway.py +482 -217
- cartography/intel/aws/apigatewayv2.py +116 -0
- cartography/intel/aws/cloudtrail.py +105 -0
- cartography/intel/aws/cloudtrail_management_events.py +962 -0
- cartography/intel/aws/cloudwatch.py +239 -0
- cartography/intel/aws/codebuild.py +132 -0
- cartography/intel/aws/cognito.py +201 -0
- cartography/intel/aws/config.py +63 -23
- cartography/intel/aws/dynamodb.py +108 -40
- cartography/intel/aws/ec2/__init__.py +2 -2
- cartography/intel/aws/ec2/auto_scaling_groups.py +254 -189
- cartography/intel/aws/ec2/elastic_ip_addresses.py +44 -14
- cartography/intel/aws/ec2/images.py +74 -39
- cartography/intel/aws/ec2/instances.py +262 -137
- cartography/intel/aws/ec2/internet_gateways.py +44 -13
- cartography/intel/aws/ec2/key_pairs.py +72 -39
- cartography/intel/aws/ec2/launch_templates.py +143 -66
- cartography/intel/aws/ec2/load_balancer_v2s.py +119 -45
- cartography/intel/aws/ec2/load_balancers.py +165 -147
- cartography/intel/aws/ec2/network_acls.py +233 -0
- cartography/intel/aws/ec2/network_interfaces.py +150 -87
- cartography/intel/aws/ec2/reserved_instances.py +48 -17
- cartography/intel/aws/ec2/route_tables.py +327 -0
- cartography/intel/aws/ec2/security_groups.py +189 -121
- cartography/intel/aws/ec2/snapshots.py +93 -91
- cartography/intel/aws/ec2/subnets.py +70 -58
- cartography/intel/aws/ec2/tgw.py +111 -39
- cartography/intel/aws/ec2/util.py +1 -1
- cartography/intel/aws/ec2/volumes.py +69 -41
- cartography/intel/aws/ec2/vpc.py +157 -116
- cartography/intel/aws/ec2/vpc_peerings.py +317 -121
- cartography/intel/aws/ecr.py +336 -93
- cartography/intel/aws/ecr_image_layers.py +923 -0
- cartography/intel/aws/ecs.py +310 -403
- cartography/intel/aws/efs.py +261 -0
- cartography/intel/aws/eks.py +55 -29
- cartography/intel/aws/elasticache.py +130 -83
- cartography/intel/aws/elasticsearch.py +70 -24
- cartography/intel/aws/emr.py +61 -23
- cartography/intel/aws/eventbridge.py +164 -0
- cartography/intel/aws/glue.py +181 -0
- cartography/intel/aws/guardduty.py +443 -0
- cartography/intel/aws/iam.py +978 -464
- cartography/intel/aws/iam_instance_profiles.py +73 -0
- cartography/intel/aws/identitycenter.py +847 -0
- cartography/intel/aws/inspector.py +330 -133
- cartography/intel/aws/kms.py +235 -209
- cartography/intel/aws/lambda_function.py +328 -176
- cartography/intel/aws/organizations.py +40 -19
- cartography/intel/aws/permission_relationships.py +144 -68
- cartography/intel/aws/rds.py +467 -412
- cartography/intel/aws/redshift.py +116 -50
- cartography/intel/aws/resourcegroupstaggingapi.py +198 -82
- cartography/intel/aws/resources.py +80 -42
- cartography/intel/aws/route53.py +419 -318
- cartography/intel/aws/s3.py +489 -96
- cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
- cartography/intel/aws/secretsmanager.py +217 -40
- cartography/intel/aws/securityhub.py +23 -10
- cartography/intel/aws/sns.py +226 -0
- cartography/intel/aws/sqs.py +74 -96
- cartography/intel/aws/ssm.py +142 -33
- cartography/intel/aws/util/arns.py +7 -7
- cartography/intel/aws/util/common.py +31 -4
- cartography/intel/azure/__init__.py +259 -46
- cartography/intel/azure/aks.py +175 -0
- cartography/intel/azure/app_service.py +105 -0
- cartography/intel/azure/compute.py +141 -120
- cartography/intel/azure/container_instances.py +95 -0
- cartography/intel/azure/cosmosdb.py +706 -519
- cartography/intel/azure/data_factory.py +85 -0
- cartography/intel/azure/data_factory_dataset.py +128 -0
- cartography/intel/azure/data_factory_linked_service.py +119 -0
- cartography/intel/azure/data_factory_pipeline.py +142 -0
- cartography/intel/azure/data_lake.py +124 -0
- cartography/intel/azure/event_grid.py +94 -0
- cartography/intel/azure/functions.py +124 -0
- cartography/intel/azure/load_balancers.py +263 -0
- cartography/intel/azure/logic_apps.py +101 -0
- cartography/intel/azure/monitor.py +105 -0
- cartography/intel/azure/network.py +467 -0
- cartography/intel/azure/permission_relationships.py +466 -0
- cartography/intel/azure/rbac.py +309 -0
- cartography/intel/azure/resource_groups.py +82 -0
- cartography/intel/azure/security_center.py +106 -0
- cartography/intel/azure/sql.py +436 -392
- cartography/intel/azure/storage.py +467 -335
- cartography/intel/azure/subscription.py +49 -55
- cartography/intel/azure/tenant.py +46 -28
- cartography/intel/azure/util/common.py +13 -0
- cartography/intel/azure/util/credentials.py +58 -143
- cartography/intel/azure/util/tag.py +41 -0
- cartography/intel/bigfix/__init__.py +2 -2
- cartography/intel/bigfix/computers.py +93 -65
- cartography/intel/cloudflare/__init__.py +74 -0
- cartography/intel/cloudflare/accounts.py +57 -0
- cartography/intel/cloudflare/dnsrecords.py +64 -0
- cartography/intel/cloudflare/members.py +75 -0
- cartography/intel/cloudflare/roles.py +65 -0
- cartography/intel/cloudflare/zones.py +64 -0
- cartography/intel/create_indexes.py +5 -3
- cartography/intel/crowdstrike/__init__.py +26 -12
- cartography/intel/crowdstrike/endpoints.py +17 -45
- cartography/intel/crowdstrike/spotlight.py +13 -5
- cartography/intel/cve/__init__.py +91 -26
- cartography/intel/cve/feed.py +77 -56
- cartography/intel/digitalocean/__init__.py +22 -13
- cartography/intel/digitalocean/compute.py +75 -108
- cartography/intel/digitalocean/management.py +44 -80
- cartography/intel/digitalocean/platform.py +48 -43
- cartography/intel/dns.py +41 -12
- cartography/intel/duo/__init__.py +21 -16
- cartography/intel/duo/api_host.py +14 -9
- cartography/intel/duo/endpoints.py +50 -45
- cartography/intel/duo/groups.py +18 -14
- cartography/intel/duo/phones.py +37 -34
- cartography/intel/duo/tokens.py +26 -23
- cartography/intel/duo/users.py +54 -50
- cartography/intel/duo/web_authn_credentials.py +30 -25
- cartography/intel/entra/__init__.py +160 -0
- cartography/intel/entra/app_role_assignments.py +284 -0
- cartography/intel/entra/applications.py +182 -0
- cartography/intel/entra/federation/__init__.py +0 -0
- cartography/intel/entra/federation/aws_identity_center.py +77 -0
- cartography/intel/entra/groups.py +198 -0
- cartography/intel/entra/ou.py +136 -0
- cartography/intel/entra/service_principals.py +217 -0
- cartography/intel/entra/users.py +259 -0
- cartography/intel/gcp/__init__.py +381 -175
- cartography/intel/gcp/bigtable_app_profile.py +101 -0
- cartography/intel/gcp/bigtable_backup.py +91 -0
- cartography/intel/gcp/bigtable_cluster.py +93 -0
- cartography/intel/gcp/bigtable_instance.py +86 -0
- cartography/intel/gcp/bigtable_table.py +87 -0
- cartography/intel/gcp/cai.py +292 -0
- cartography/intel/gcp/clients.py +112 -0
- cartography/intel/gcp/compute.py +521 -325
- cartography/intel/gcp/crm/__init__.py +0 -0
- cartography/intel/gcp/crm/folders.py +114 -0
- cartography/intel/gcp/crm/orgs.py +70 -0
- cartography/intel/gcp/crm/projects.py +120 -0
- cartography/intel/gcp/dns.py +134 -179
- cartography/intel/gcp/gke.py +100 -107
- cartography/intel/gcp/iam.py +262 -0
- cartography/intel/gcp/permission_relationships.py +394 -0
- cartography/intel/gcp/policy_bindings.py +225 -0
- cartography/intel/gcp/storage.py +103 -158
- cartography/intel/github/__init__.py +66 -27
- cartography/intel/github/commits.py +423 -0
- cartography/intel/github/repos.py +871 -160
- cartography/intel/github/teams.py +386 -53
- cartography/intel/github/users.py +214 -49
- cartography/intel/github/util.py +50 -35
- cartography/intel/googleworkspace/__init__.py +193 -0
- cartography/intel/googleworkspace/devices.py +254 -0
- cartography/intel/googleworkspace/groups.py +568 -0
- cartography/intel/googleworkspace/oauth_apps.py +259 -0
- cartography/intel/googleworkspace/tenant.py +85 -0
- cartography/intel/googleworkspace/users.py +138 -0
- cartography/intel/gsuite/__init__.py +101 -42
- cartography/intel/gsuite/groups.py +291 -0
- cartography/intel/gsuite/users.py +142 -0
- cartography/intel/jamf/__init__.py +19 -1
- cartography/intel/jamf/computers.py +37 -8
- cartography/intel/jamf/util.py +7 -2
- cartography/intel/kandji/__init__.py +6 -3
- cartography/intel/kandji/devices.py +40 -10
- cartography/intel/keycloak/__init__.py +153 -0
- cartography/intel/keycloak/authenticationexecutions.py +322 -0
- cartography/intel/keycloak/authenticationflows.py +77 -0
- cartography/intel/keycloak/clients.py +187 -0
- cartography/intel/keycloak/groups.py +126 -0
- cartography/intel/keycloak/identityproviders.py +94 -0
- cartography/intel/keycloak/organizations.py +163 -0
- cartography/intel/keycloak/realms.py +61 -0
- cartography/intel/keycloak/roles.py +202 -0
- cartography/intel/keycloak/scopes.py +73 -0
- cartography/intel/keycloak/users.py +70 -0
- cartography/intel/keycloak/util.py +47 -0
- cartography/intel/kubernetes/__init__.py +60 -14
- cartography/intel/kubernetes/clusters.py +86 -0
- cartography/intel/kubernetes/eks.py +402 -0
- cartography/intel/kubernetes/namespaces.py +60 -55
- cartography/intel/kubernetes/pods.py +171 -75
- cartography/intel/kubernetes/rbac.py +597 -0
- cartography/intel/kubernetes/secrets.py +95 -45
- cartography/intel/kubernetes/services.py +131 -63
- cartography/intel/kubernetes/util.py +142 -14
- cartography/intel/lastpass/__init__.py +2 -2
- cartography/intel/lastpass/users.py +23 -12
- cartography/intel/oci/__init__.py +44 -11
- cartography/intel/oci/iam.py +157 -47
- cartography/intel/oci/organizations.py +16 -7
- cartography/intel/oci/utils.py +71 -25
- cartography/intel/okta/__init__.py +66 -15
- cartography/intel/okta/applications.py +57 -25
- cartography/intel/okta/awssaml.py +105 -41
- cartography/intel/okta/factors.py +19 -5
- cartography/intel/okta/groups.py +61 -31
- cartography/intel/okta/organization.py +8 -2
- cartography/intel/okta/origins.py +9 -3
- cartography/intel/okta/roles.py +20 -7
- cartography/intel/okta/users.py +31 -10
- cartography/intel/okta/utils.py +6 -4
- cartography/intel/ontology/__init__.py +44 -0
- cartography/intel/ontology/devices.py +54 -0
- cartography/intel/ontology/users.py +54 -0
- cartography/intel/ontology/utils.py +176 -0
- cartography/intel/openai/__init__.py +86 -0
- cartography/intel/openai/adminapikeys.py +89 -0
- cartography/intel/openai/apikeys.py +96 -0
- cartography/intel/openai/projects.py +97 -0
- cartography/intel/openai/serviceaccounts.py +82 -0
- cartography/intel/openai/users.py +75 -0
- cartography/intel/openai/util.py +45 -0
- cartography/intel/pagerduty/__init__.py +8 -7
- cartography/intel/pagerduty/escalation_policies.py +31 -12
- cartography/intel/pagerduty/schedules.py +21 -8
- cartography/intel/pagerduty/services.py +18 -7
- cartography/intel/pagerduty/teams.py +13 -5
- cartography/intel/pagerduty/users.py +6 -2
- cartography/intel/pagerduty/vendors.py +6 -2
- cartography/intel/scaleway/__init__.py +127 -0
- cartography/intel/scaleway/iam/__init__.py +0 -0
- cartography/intel/scaleway/iam/apikeys.py +71 -0
- cartography/intel/scaleway/iam/applications.py +71 -0
- cartography/intel/scaleway/iam/groups.py +71 -0
- cartography/intel/scaleway/iam/users.py +71 -0
- cartography/intel/scaleway/instances/__init__.py +0 -0
- cartography/intel/scaleway/instances/flexibleips.py +86 -0
- cartography/intel/scaleway/instances/instances.py +92 -0
- cartography/intel/scaleway/projects.py +79 -0
- cartography/intel/scaleway/storage/__init__.py +0 -0
- cartography/intel/scaleway/storage/snapshots.py +86 -0
- cartography/intel/scaleway/storage/volumes.py +84 -0
- cartography/intel/scaleway/utils.py +37 -0
- cartography/intel/semgrep/__init__.py +30 -5
- cartography/intel/semgrep/dependencies.py +255 -0
- cartography/intel/semgrep/deployment.py +69 -0
- cartography/intel/semgrep/findings.py +157 -117
- cartography/intel/sentinelone/__init__.py +75 -0
- cartography/intel/sentinelone/account.py +140 -0
- cartography/intel/sentinelone/agent.py +139 -0
- cartography/intel/sentinelone/api.py +124 -0
- cartography/intel/sentinelone/application.py +248 -0
- cartography/intel/sentinelone/cve.py +119 -0
- cartography/intel/sentinelone/utils.py +28 -0
- cartography/intel/slack/__init__.py +78 -0
- cartography/intel/slack/channels.py +80 -0
- cartography/intel/slack/groups.py +90 -0
- cartography/intel/slack/teams.py +65 -0
- cartography/intel/slack/users.py +57 -0
- cartography/intel/slack/utils.py +29 -0
- cartography/intel/snipeit/__init__.py +44 -0
- cartography/intel/snipeit/asset.py +80 -0
- cartography/intel/snipeit/user.py +78 -0
- cartography/intel/snipeit/util.py +40 -0
- cartography/intel/spacelift/__init__.py +161 -0
- cartography/intel/spacelift/account.py +73 -0
- cartography/intel/spacelift/ec2_ownership.py +280 -0
- cartography/intel/spacelift/runs.py +463 -0
- cartography/intel/spacelift/spaces.py +112 -0
- cartography/intel/spacelift/stacks.py +119 -0
- cartography/intel/spacelift/util.py +122 -0
- cartography/intel/spacelift/workerpools.py +131 -0
- cartography/intel/spacelift/workers.py +128 -0
- cartography/intel/tailscale/__init__.py +77 -0
- cartography/intel/tailscale/acls.py +146 -0
- cartography/intel/tailscale/devices.py +127 -0
- cartography/intel/tailscale/postureintegrations.py +81 -0
- cartography/intel/tailscale/tailnets.py +76 -0
- cartography/intel/tailscale/users.py +80 -0
- cartography/intel/tailscale/utils.py +132 -0
- cartography/intel/trivy/__init__.py +272 -0
- cartography/intel/trivy/scanner.py +386 -0
- cartography/models/airbyte/__init__.py +0 -0
- cartography/models/airbyte/connection.py +138 -0
- cartography/models/airbyte/destination.py +75 -0
- cartography/models/airbyte/organization.py +19 -0
- cartography/models/airbyte/source.py +75 -0
- cartography/models/airbyte/stream.py +74 -0
- cartography/models/airbyte/tag.py +69 -0
- cartography/models/airbyte/user.py +115 -0
- cartography/models/airbyte/workspace.py +46 -0
- cartography/models/anthropic/__init__.py +0 -0
- cartography/models/anthropic/apikey.py +94 -0
- cartography/models/anthropic/organization.py +19 -0
- cartography/models/anthropic/user.py +52 -0
- cartography/models/anthropic/workspace.py +90 -0
- cartography/models/aws/acm/__init__.py +0 -0
- cartography/models/aws/acm/certificate.py +75 -0
- cartography/models/aws/apigateway/__init__.py +0 -0
- cartography/models/aws/apigateway/apigateway.py +51 -0
- cartography/models/aws/apigateway/apigatewaycertificate.py +72 -0
- cartography/models/aws/apigateway/apigatewaydeployment.py +74 -0
- cartography/models/aws/apigateway/apigatewayintegration.py +79 -0
- cartography/models/aws/apigateway/apigatewaymethod.py +74 -0
- cartography/models/aws/apigateway/apigatewayresource.py +70 -0
- cartography/models/aws/apigateway/apigatewaystage.py +75 -0
- cartography/models/aws/apigatewayv2/__init__.py +0 -0
- cartography/models/aws/apigatewayv2/apigatewayv2.py +53 -0
- cartography/models/aws/cloudtrail/__init__.py +0 -0
- cartography/models/aws/cloudtrail/management_events.py +153 -0
- cartography/models/aws/cloudtrail/trail.py +106 -0
- cartography/models/aws/cloudwatch/__init__.py +0 -0
- cartography/models/aws/cloudwatch/log_metric_filter.py +79 -0
- cartography/models/aws/cloudwatch/loggroup.py +52 -0
- cartography/models/aws/cloudwatch/metric_alarm.py +53 -0
- cartography/models/aws/codebuild/__init__.py +0 -0
- cartography/models/aws/codebuild/project.py +49 -0
- cartography/models/aws/cognito/__init__.py +0 -0
- cartography/models/aws/cognito/identity_pool.py +70 -0
- cartography/models/aws/cognito/user_pool.py +47 -0
- cartography/models/aws/dynamodb/gsi.py +30 -22
- cartography/models/aws/dynamodb/tables.py +27 -17
- cartography/models/aws/ec2/auto_scaling_groups.py +224 -0
- cartography/models/aws/ec2/images.py +36 -34
- cartography/models/aws/ec2/instances.py +85 -38
- cartography/models/aws/ec2/keypair.py +59 -0
- cartography/models/aws/ec2/keypair_instance.py +76 -0
- cartography/models/aws/ec2/launch_configurations.py +59 -0
- cartography/models/aws/ec2/launch_template_versions.py +48 -38
- cartography/models/aws/ec2/launch_templates.py +21 -17
- cartography/models/aws/ec2/load_balancer_listeners.py +72 -0
- cartography/models/aws/ec2/load_balancers.py +112 -0
- cartography/models/aws/ec2/network_acl_rules.py +106 -0
- cartography/models/aws/ec2/network_acls.py +95 -0
- cartography/models/aws/ec2/networkinterface_instance.py +52 -39
- cartography/models/aws/ec2/networkinterfaces.py +57 -37
- cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
- cartography/models/aws/ec2/reservations.py +18 -14
- cartography/models/aws/ec2/route_table_associations.py +97 -0
- cartography/models/aws/ec2/route_tables.py +128 -0
- cartography/models/aws/ec2/routes.py +85 -0
- cartography/models/aws/ec2/security_group_rules.py +109 -0
- cartography/models/aws/ec2/security_groups.py +90 -0
- cartography/models/aws/ec2/securitygroup_instance.py +29 -20
- cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
- cartography/models/aws/ec2/snapshots.py +58 -0
- cartography/models/aws/ec2/subnet_instance.py +26 -19
- cartography/models/aws/ec2/subnet_networkinterface.py +42 -31
- cartography/models/aws/ec2/subnets.py +65 -0
- cartography/models/aws/ec2/volumes.py +67 -40
- cartography/models/aws/ec2/vpc.py +46 -0
- cartography/models/aws/ec2/vpc_cidr.py +102 -0
- cartography/models/aws/ec2/vpc_peering.py +157 -0
- cartography/models/aws/ecr/__init__.py +0 -0
- cartography/models/aws/ecr/image.py +146 -0
- cartography/models/aws/ecr/image_layer.py +107 -0
- cartography/models/aws/ecr/repository.py +72 -0
- cartography/models/aws/ecr/repository_image.py +95 -0
- cartography/models/aws/ecs/__init__.py +0 -0
- cartography/models/aws/ecs/clusters.py +64 -0
- cartography/models/aws/ecs/container_definitions.py +93 -0
- cartography/models/aws/ecs/container_instances.py +84 -0
- cartography/models/aws/ecs/containers.py +101 -0
- cartography/models/aws/ecs/services.py +134 -0
- cartography/models/aws/ecs/task_definitions.py +135 -0
- cartography/models/aws/ecs/tasks.py +134 -0
- cartography/models/aws/efs/__init__.py +0 -0
- cartography/models/aws/efs/access_point.py +77 -0
- cartography/models/aws/efs/file_system.py +60 -0
- cartography/models/aws/efs/mount_target.py +79 -0
- cartography/models/aws/eks/clusters.py +23 -21
- cartography/models/aws/elasticache/__init__.py +0 -0
- cartography/models/aws/elasticache/cluster.py +65 -0
- cartography/models/aws/elasticache/topic.py +67 -0
- cartography/models/aws/emr.py +32 -30
- cartography/models/aws/eventbridge/__init__.py +0 -0
- cartography/models/aws/eventbridge/rule.py +77 -0
- cartography/models/aws/eventbridge/target.py +71 -0
- cartography/models/aws/glue/__init__.py +0 -0
- cartography/models/aws/glue/connection.py +51 -0
- cartography/models/aws/glue/job.py +69 -0
- cartography/models/aws/guardduty/__init__.py +1 -0
- cartography/models/aws/guardduty/detectors.py +50 -0
- cartography/models/aws/guardduty/findings.py +121 -0
- cartography/models/aws/iam/__init__.py +0 -0
- cartography/models/aws/iam/access_key.py +103 -0
- cartography/models/aws/iam/account_role.py +24 -0
- cartography/models/aws/iam/federated_principal.py +60 -0
- cartography/models/aws/iam/group.py +60 -0
- cartography/models/aws/iam/group_membership.py +27 -0
- cartography/models/aws/iam/inline_policy.py +78 -0
- cartography/models/aws/iam/instanceprofile.py +76 -0
- cartography/models/aws/iam/managed_policy.py +51 -0
- cartography/models/aws/iam/policy_statement.py +57 -0
- cartography/models/aws/iam/role.py +83 -0
- cartography/models/aws/iam/root_principal.py +52 -0
- cartography/models/aws/iam/service_principal.py +30 -0
- cartography/models/aws/iam/sts_assumerole_allow.py +38 -0
- cartography/models/aws/iam/user.py +59 -0
- cartography/models/aws/identitycenter/__init__.py +0 -0
- cartography/models/aws/identitycenter/awsidentitycenter.py +49 -0
- cartography/models/aws/identitycenter/awspermissionset.py +162 -0
- cartography/models/aws/identitycenter/awssogroup.py +70 -0
- cartography/models/aws/identitycenter/awsssouser.py +110 -0
- cartography/models/aws/inspector/findings.py +124 -58
- cartography/models/aws/inspector/packages.py +18 -42
- cartography/models/aws/kms/__init__.py +0 -0
- cartography/models/aws/kms/aliases.py +86 -0
- cartography/models/aws/kms/grants.py +65 -0
- cartography/models/aws/kms/keys.py +88 -0
- cartography/models/aws/lambda_function/__init__.py +0 -0
- cartography/models/aws/lambda_function/alias.py +74 -0
- cartography/models/aws/lambda_function/event_source_mapping.py +88 -0
- cartography/models/aws/lambda_function/lambda_function.py +91 -0
- cartography/models/aws/lambda_function/layer.py +72 -0
- cartography/models/aws/rds/__init__.py +0 -0
- cartography/models/aws/rds/cluster.py +91 -0
- cartography/models/aws/rds/event_subscription.py +146 -0
- cartography/models/aws/rds/instance.py +156 -0
- cartography/models/aws/rds/snapshot.py +108 -0
- cartography/models/aws/rds/subnet_group.py +101 -0
- cartography/models/aws/route53/__init__.py +0 -0
- cartography/models/aws/route53/dnsrecord.py +235 -0
- cartography/models/aws/route53/nameserver.py +63 -0
- cartography/models/aws/route53/subzone.py +40 -0
- cartography/models/aws/route53/zone.py +47 -0
- cartography/models/aws/s3/__init__.py +0 -0
- cartography/models/aws/s3/account_public_access_block.py +51 -0
- cartography/models/aws/s3/notification.py +24 -0
- cartography/models/aws/secretsmanager/__init__.py +0 -0
- cartography/models/aws/secretsmanager/secret.py +106 -0
- cartography/models/aws/secretsmanager/secret_version.py +114 -0
- cartography/models/aws/sns/__init__.py +0 -0
- cartography/models/aws/sns/topic.py +50 -0
- cartography/models/aws/sns/topic_subscription.py +74 -0
- cartography/models/aws/sqs/__init__.py +0 -0
- cartography/models/aws/sqs/queue.py +89 -0
- cartography/models/aws/ssm/instance_information.py +51 -39
- cartography/models/aws/ssm/instance_patch.py +32 -26
- cartography/models/aws/ssm/parameters.py +84 -0
- cartography/models/azure/__init__.py +0 -0
- cartography/models/azure/aks_cluster.py +54 -0
- cartography/models/azure/aks_nodepool.py +54 -0
- cartography/models/azure/app_service.py +59 -0
- cartography/models/azure/container_instance.py +57 -0
- cartography/models/azure/cosmosdb/__init__.py +0 -0
- cartography/models/azure/cosmosdb/account.py +77 -0
- cartography/models/azure/cosmosdb/accountfailoverpolicy.py +77 -0
- cartography/models/azure/cosmosdb/cassandrakeyspace.py +82 -0
- cartography/models/azure/cosmosdb/cassandratable.py +81 -0
- cartography/models/azure/cosmosdb/corspolicy.py +74 -0
- cartography/models/azure/cosmosdb/dblocation.py +120 -0
- cartography/models/azure/cosmosdb/mongodbcollection.py +82 -0
- cartography/models/azure/cosmosdb/mongodbdatabase.py +78 -0
- cartography/models/azure/cosmosdb/privateendpointconnection.py +81 -0
- cartography/models/azure/cosmosdb/sqlcontainer.py +88 -0
- cartography/models/azure/cosmosdb/sqldatabase.py +78 -0
- cartography/models/azure/cosmosdb/tableresource.py +76 -0
- cartography/models/azure/cosmosdb/virtualnetworkrule.py +78 -0
- cartography/models/azure/data_factory/__init__.py +0 -0
- cartography/models/azure/data_factory/data_factory.py +51 -0
- cartography/models/azure/data_factory/data_factory_dataset.py +94 -0
- cartography/models/azure/data_factory/data_factory_linked_service.py +78 -0
- cartography/models/azure/data_factory/data_factory_pipeline.py +93 -0
- cartography/models/azure/data_lake_filesystem.py +51 -0
- cartography/models/azure/event_grid_topic.py +57 -0
- cartography/models/azure/function_app.py +59 -0
- cartography/models/azure/load_balancer/__init__.py +0 -0
- cartography/models/azure/load_balancer/load_balancer.py +49 -0
- cartography/models/azure/load_balancer/load_balancer_backend_pool.py +73 -0
- cartography/models/azure/load_balancer/load_balancer_frontend_ip.py +75 -0
- cartography/models/azure/load_balancer/load_balancer_inbound_nat_rule.py +78 -0
- cartography/models/azure/load_balancer/load_balancer_rule.py +108 -0
- cartography/models/azure/logic_apps.py +56 -0
- cartography/models/azure/monitor.py +54 -0
- cartography/models/azure/network_interface.py +112 -0
- cartography/models/azure/network_security_group.py +50 -0
- cartography/models/azure/permission_relationships.py +60 -0
- cartography/models/azure/principal.py +41 -0
- cartography/models/azure/public_ip_address.py +50 -0
- cartography/models/azure/rbac.py +268 -0
- cartography/models/azure/resource_groups.py +52 -0
- cartography/models/azure/security_center.py +50 -0
- cartography/models/azure/sql/__init__.py +0 -0
- cartography/models/azure/sql/databasethreatdetectionpolicy.py +85 -0
- cartography/models/azure/sql/elasticpool.py +77 -0
- cartography/models/azure/sql/failovergroup.py +73 -0
- cartography/models/azure/sql/recoverabledatabase.py +75 -0
- cartography/models/azure/sql/replicationlink.py +81 -0
- cartography/models/azure/sql/restorabledroppeddatabase.py +82 -0
- cartography/models/azure/sql/restorepoint.py +74 -0
- cartography/models/azure/sql/serveradadministrator.py +74 -0
- cartography/models/azure/sql/serverdnsalias.py +71 -0
- cartography/models/azure/sql/sqldatabase.py +85 -0
- cartography/models/azure/sql/sqlserver.py +50 -0
- cartography/models/azure/sql/transparentdataencryption.py +76 -0
- cartography/models/azure/storage/__init__.py +0 -0
- cartography/models/azure/storage/account.py +59 -0
- cartography/models/azure/storage/blobcontainer.py +85 -0
- cartography/models/azure/storage/blobservice.py +71 -0
- cartography/models/azure/storage/fileservice.py +71 -0
- cartography/models/azure/storage/fileshare.py +82 -0
- cartography/models/azure/storage/queue.py +71 -0
- cartography/models/azure/storage/queueservice.py +73 -0
- cartography/models/azure/storage/table.py +72 -0
- cartography/models/azure/storage/tableservice.py +73 -0
- cartography/models/azure/subnet.py +101 -0
- cartography/models/azure/subscription.py +47 -0
- cartography/models/azure/tags/__init__.py +0 -0
- cartography/models/azure/tags/storage_tag.py +40 -0
- cartography/models/azure/tags/tag.py +37 -0
- cartography/models/azure/tenant.py +17 -0
- cartography/models/azure/virtual_network.py +49 -0
- cartography/models/azure/vm/__init__.py +0 -0
- cartography/models/azure/vm/datadisk.py +80 -0
- cartography/models/azure/vm/disk.py +55 -0
- cartography/models/azure/vm/snapshot.py +56 -0
- cartography/models/azure/vm/virtualmachine.py +59 -0
- cartography/models/bigfix/bigfix_computer.py +42 -38
- cartography/models/bigfix/bigfix_root.py +3 -3
- cartography/models/cloudflare/__init__.py +0 -0
- cartography/models/cloudflare/account.py +25 -0
- cartography/models/cloudflare/dnsrecord.py +55 -0
- cartography/models/cloudflare/member.py +86 -0
- cartography/models/cloudflare/role.py +44 -0
- cartography/models/cloudflare/zone.py +59 -0
- cartography/models/core/common.py +53 -2
- cartography/models/core/nodes.py +20 -4
- cartography/models/core/relationships.py +58 -6
- cartography/models/crowdstrike/__init__.py +0 -0
- cartography/models/crowdstrike/hosts.py +51 -0
- cartography/models/cve/cve.py +34 -32
- cartography/models/cve/cve_feed.py +6 -6
- cartography/models/digitalocean/__init__.py +0 -0
- cartography/models/digitalocean/account.py +21 -0
- cartography/models/digitalocean/droplet.py +58 -0
- cartography/models/digitalocean/project.py +48 -0
- cartography/models/duo/api_host.py +3 -3
- cartography/models/duo/endpoint.py +43 -41
- cartography/models/duo/group.py +14 -14
- cartography/models/duo/phone.py +27 -27
- cartography/models/duo/token.py +16 -16
- cartography/models/duo/user.py +50 -44
- cartography/models/duo/web_authn_credential.py +27 -19
- cartography/models/entra/__init__.py +0 -0
- cartography/models/entra/app_role_assignment.py +115 -0
- cartography/models/entra/application.py +49 -0
- cartography/models/entra/entra_user_to_aws_sso.py +41 -0
- cartography/models/entra/group.py +117 -0
- cartography/models/entra/ou.py +48 -0
- cartography/models/entra/service_principal.py +104 -0
- cartography/models/entra/tenant.py +39 -0
- cartography/models/entra/user.py +90 -0
- cartography/models/gcp/__init__.py +0 -0
- cartography/models/gcp/bigtable/__init__.py +0 -0
- cartography/models/gcp/bigtable/app_profile.py +94 -0
- cartography/models/gcp/bigtable/backup.py +91 -0
- cartography/models/gcp/bigtable/cluster.py +73 -0
- cartography/models/gcp/bigtable/instance.py +52 -0
- cartography/models/gcp/bigtable/table.py +69 -0
- cartography/models/gcp/compute/__init__.py +0 -0
- cartography/models/gcp/compute/subnet.py +74 -0
- cartography/models/gcp/compute/vpc.py +50 -0
- cartography/models/gcp/crm/__init__.py +0 -0
- cartography/models/gcp/crm/folders.py +98 -0
- cartography/models/gcp/crm/organizations.py +21 -0
- cartography/models/gcp/crm/projects.py +100 -0
- cartography/models/gcp/dns.py +109 -0
- cartography/models/gcp/gke.py +69 -0
- cartography/models/gcp/iam.py +73 -0
- cartography/models/gcp/permission_relationships.py +61 -0
- cartography/models/gcp/policy_bindings.py +93 -0
- cartography/models/gcp/storage/__init__.py +0 -0
- cartography/models/gcp/storage/bucket.py +119 -0
- cartography/models/github/commits.py +63 -0
- cartography/models/github/dependencies.py +73 -0
- cartography/models/github/manifests.py +49 -0
- cartography/models/github/orgs.py +27 -0
- cartography/models/github/teams.py +74 -22
- cartography/models/github/users.py +149 -0
- cartography/models/googleworkspace/__init__.py +0 -0
- cartography/models/googleworkspace/device.py +132 -0
- cartography/models/googleworkspace/group.py +382 -0
- cartography/models/googleworkspace/oauth_app.py +124 -0
- cartography/models/googleworkspace/tenant.py +30 -0
- cartography/models/googleworkspace/user.py +113 -0
- cartography/models/gsuite/__init__.py +0 -0
- cartography/models/gsuite/group.py +218 -0
- cartography/models/gsuite/tenant.py +29 -0
- cartography/models/gsuite/user.py +107 -0
- cartography/models/kandji/device.py +22 -17
- cartography/models/kandji/tenant.py +6 -4
- cartography/models/keycloak/__init__.py +0 -0
- cartography/models/keycloak/authenticationexecution.py +160 -0
- cartography/models/keycloak/authenticationflow.py +54 -0
- cartography/models/keycloak/client.py +179 -0
- cartography/models/keycloak/group.py +101 -0
- cartography/models/keycloak/identityprovider.py +89 -0
- cartography/models/keycloak/organization.py +116 -0
- cartography/models/keycloak/organizationdomain.py +73 -0
- cartography/models/keycloak/realm.py +173 -0
- cartography/models/keycloak/role.py +126 -0
- cartography/models/keycloak/scope.py +73 -0
- cartography/models/keycloak/user.py +55 -0
- cartography/models/kubernetes/__init__.py +0 -0
- cartography/models/kubernetes/clusterrolebindings.py +138 -0
- cartography/models/kubernetes/clusterroles.py +52 -0
- cartography/models/kubernetes/clusters.py +26 -0
- cartography/models/kubernetes/containers.py +133 -0
- cartography/models/kubernetes/groups.py +107 -0
- cartography/models/kubernetes/namespaces.py +51 -0
- cartography/models/kubernetes/oidc.py +51 -0
- cartography/models/kubernetes/pods.py +80 -0
- cartography/models/kubernetes/rolebindings.py +159 -0
- cartography/models/kubernetes/roles.py +76 -0
- cartography/models/kubernetes/secrets.py +79 -0
- cartography/models/kubernetes/serviceaccounts.py +77 -0
- cartography/models/kubernetes/services.py +108 -0
- cartography/models/kubernetes/users.py +105 -0
- cartography/models/lastpass/tenant.py +3 -3
- cartography/models/lastpass/user.py +36 -28
- cartography/models/ontology/__init__.py +0 -0
- cartography/models/ontology/device.py +137 -0
- cartography/models/ontology/mapping/__init__.py +76 -0
- cartography/models/ontology/mapping/data/__init__.py +0 -0
- cartography/models/ontology/mapping/data/apikeys.py +93 -0
- cartography/models/ontology/mapping/data/computeinstance.py +95 -0
- cartography/models/ontology/mapping/data/containers.py +88 -0
- cartography/models/ontology/mapping/data/databases.py +182 -0
- cartography/models/ontology/mapping/data/devices.py +194 -0
- cartography/models/ontology/mapping/data/thirdpartyapps.py +140 -0
- cartography/models/ontology/mapping/data/useraccounts.py +416 -0
- cartography/models/ontology/mapping/data/users.py +63 -0
- cartography/models/ontology/mapping/specs.py +85 -0
- cartography/models/ontology/user.py +51 -0
- cartography/models/openai/__init__.py +0 -0
- cartography/models/openai/adminapikey.py +94 -0
- cartography/models/openai/apikey.py +88 -0
- cartography/models/openai/organization.py +17 -0
- cartography/models/openai/project.py +89 -0
- cartography/models/openai/serviceaccount.py +50 -0
- cartography/models/openai/user.py +53 -0
- cartography/models/scaleway/__init__.py +0 -0
- cartography/models/scaleway/iam/__init__.py +0 -0
- cartography/models/scaleway/iam/apikey.py +100 -0
- cartography/models/scaleway/iam/application.py +52 -0
- cartography/models/scaleway/iam/group.py +95 -0
- cartography/models/scaleway/iam/user.py +64 -0
- cartography/models/scaleway/instance/__init__.py +0 -0
- cartography/models/scaleway/instance/flexibleip.py +52 -0
- cartography/models/scaleway/instance/instance.py +120 -0
- cartography/models/scaleway/organization.py +19 -0
- cartography/models/scaleway/project.py +48 -0
- cartography/models/scaleway/storage/__init__.py +0 -0
- cartography/models/scaleway/storage/snapshot.py +78 -0
- cartography/models/scaleway/storage/volume.py +51 -0
- cartography/models/semgrep/dependencies.py +102 -0
- cartography/models/semgrep/deployment.py +5 -5
- cartography/models/semgrep/findings.py +58 -40
- cartography/models/semgrep/locations.py +27 -21
- cartography/models/sentinelone/__init__.py +1 -0
- cartography/models/sentinelone/account.py +40 -0
- cartography/models/sentinelone/agent.py +50 -0
- cartography/models/sentinelone/application.py +44 -0
- cartography/models/sentinelone/application_version.py +96 -0
- cartography/models/sentinelone/cve.py +73 -0
- cartography/models/slack/__init__.py +0 -0
- cartography/models/slack/channels.py +92 -0
- cartography/models/slack/group.py +129 -0
- cartography/models/slack/team.py +22 -0
- cartography/models/slack/user.py +62 -0
- cartography/models/snipeit/__init__.py +0 -0
- cartography/models/snipeit/asset.py +92 -0
- cartography/models/snipeit/tenant.py +19 -0
- cartography/models/snipeit/user.py +60 -0
- cartography/models/spacelift/__init__.py +0 -0
- cartography/models/spacelift/cloudtrailevent.py +120 -0
- cartography/models/spacelift/run.py +162 -0
- cartography/models/spacelift/space.py +131 -0
- cartography/models/spacelift/spaceliftaccount.py +31 -0
- cartography/models/spacelift/spaceliftgitcommit.py +157 -0
- cartography/models/spacelift/stack.py +96 -0
- cartography/models/spacelift/user.py +63 -0
- cartography/models/spacelift/worker.py +97 -0
- cartography/models/spacelift/workerpool.py +90 -0
- cartography/models/tailscale/__init__.py +0 -0
- cartography/models/tailscale/device.py +96 -0
- cartography/models/tailscale/group.py +86 -0
- cartography/models/tailscale/postureintegration.py +58 -0
- cartography/models/tailscale/tag.py +102 -0
- cartography/models/tailscale/tailnet.py +29 -0
- cartography/models/tailscale/user.py +57 -0
- cartography/models/trivy/__init__.py +0 -0
- cartography/models/trivy/findings.py +66 -0
- cartography/models/trivy/fix.py +66 -0
- cartography/models/trivy/package.py +71 -0
- cartography/rules/README.md +1 -0
- cartography/rules/__init__.py +0 -0
- cartography/rules/cli.py +261 -0
- cartography/rules/data/__init__.py +0 -0
- cartography/rules/data/rules/__init__.py +46 -0
- cartography/rules/data/rules/cloud_security_product_deactivated.py +49 -0
- cartography/rules/data/rules/compute_instance_exposed.py +51 -0
- cartography/rules/data/rules/database_instance_exposed.py +53 -0
- cartography/rules/data/rules/delegation_boundary_modifiable.py +90 -0
- cartography/rules/data/rules/identity_administration_privileges.py +100 -0
- cartography/rules/data/rules/inactive_user_active_accounts.py +48 -0
- cartography/rules/data/rules/malicious_npm_dependencies_shai_hulud.py +2222 -0
- cartography/rules/data/rules/mfa_missing.py +46 -0
- cartography/rules/data/rules/object_storage_public.py +100 -0
- cartography/rules/data/rules/policy_administration_privileges.py +104 -0
- cartography/rules/data/rules/unmanaged_accounts.py +43 -0
- cartography/rules/data/rules/workload_identity_admin_capabilities.py +193 -0
- cartography/rules/formatters.py +108 -0
- cartography/rules/runners.py +216 -0
- cartography/rules/spec/__init__.py +0 -0
- cartography/rules/spec/model.py +267 -0
- cartography/rules/spec/result.py +38 -0
- cartography/stats.py +4 -4
- cartography/sync.py +137 -31
- cartography/util.py +187 -77
- cartography-0.123.0.dist-info/METADATA +230 -0
- cartography-0.123.0.dist-info/RECORD +856 -0
- {cartography-0.93.0rc1.dist-info → cartography-0.123.0.dist-info}/WHEEL +1 -1
- {cartography-0.93.0rc1.dist-info → cartography-0.123.0.dist-info}/entry_points.txt +1 -0
- {cartography-0.93.0rc1.dist-info → cartography-0.123.0.dist-info/licenses}/LICENSE +1 -1
- cartography/data/jobs/analysis/aws_ec2_iaminstance.json +0 -10
- cartography/data/jobs/analysis/aws_ec2_iaminstanceprofile.json +0 -10
- cartography/data/jobs/cleanup/aws_apigateway_details.json +0 -10
- cartography/data/jobs/cleanup/aws_dns_cleanup.json +0 -65
- cartography/data/jobs/cleanup/aws_import_account_access_key_cleanup.json +0 -17
- cartography/data/jobs/cleanup/aws_import_apigateway_cleanup.json +0 -45
- cartography/data/jobs/cleanup/aws_import_ec2_security_groupinfo_cleanup.json +0 -24
- cartography/data/jobs/cleanup/aws_import_groups_cleanup.json +0 -13
- cartography/data/jobs/cleanup/aws_import_lambda_cleanup.json +0 -50
- cartography/data/jobs/cleanup/aws_import_principals_cleanup.json +0 -30
- cartography/data/jobs/cleanup/aws_import_rds_clusters_cleanup.json +0 -23
- cartography/data/jobs/cleanup/aws_import_rds_instances_cleanup.json +0 -47
- cartography/data/jobs/cleanup/aws_import_rds_snapshots_cleanup.json +0 -23
- cartography/data/jobs/cleanup/aws_import_roles_cleanup.json +0 -13
- cartography/data/jobs/cleanup/aws_import_secrets_cleanup.json +0 -8
- cartography/data/jobs/cleanup/aws_import_snapshots_cleanup.json +0 -30
- cartography/data/jobs/cleanup/aws_import_users_cleanup.json +0 -8
- cartography/data/jobs/cleanup/aws_import_vpc_cleanup.json +0 -23
- cartography/data/jobs/cleanup/aws_import_vpc_peering_cleanup.json +0 -45
- cartography/data/jobs/cleanup/aws_kms_details.json +0 -10
- cartography/data/jobs/cleanup/azure_cosmosdb_cassandra_keyspace_cleanup.json +0 -25
- cartography/data/jobs/cleanup/azure_cosmosdb_cors_details.json +0 -15
- cartography/data/jobs/cleanup/azure_cosmosdb_mongodb_database_cleanup.json +0 -25
- cartography/data/jobs/cleanup/azure_cosmosdb_sql_database_cleanup.json +0 -25
- cartography/data/jobs/cleanup/azure_cosmosdb_table_resources_cleanup.json +0 -15
- cartography/data/jobs/cleanup/azure_database_account_cleanup.json +0 -85
- cartography/data/jobs/cleanup/azure_import_disks_cleanup.json +0 -15
- cartography/data/jobs/cleanup/azure_import_snapshots_cleanup.json +0 -15
- cartography/data/jobs/cleanup/azure_import_virtual_machines_cleanup.json +0 -25
- cartography/data/jobs/cleanup/azure_sql_server_cleanup.json +0 -125
- cartography/data/jobs/cleanup/azure_storage_account_cleanup.json +0 -95
- cartography/data/jobs/cleanup/azure_subscriptions_cleanup.json +0 -14
- cartography/data/jobs/cleanup/azure_tenant_cleanup.json +0 -9
- cartography/data/jobs/cleanup/crxcavator_import_cleanup.json +0 -18
- cartography/data/jobs/cleanup/gcp_compute_vpc_subnet_cleanup.json +0 -35
- cartography/data/jobs/cleanup/gcp_crm_folder_cleanup.json +0 -23
- cartography/data/jobs/cleanup/gcp_crm_organization_cleanup.json +0 -17
- cartography/data/jobs/cleanup/gcp_crm_project_cleanup.json +0 -23
- cartography/data/jobs/cleanup/gcp_dns_cleanup.json +0 -29
- cartography/data/jobs/cleanup/gcp_gke_cluster_cleanup.json +0 -17
- cartography/data/jobs/cleanup/gcp_storage_bucket_cleanup.json +0 -29
- cartography/data/jobs/cleanup/github_users_cleanup.json +0 -23
- cartography/data/jobs/cleanup/gsuite_ingest_groups_cleanup.json +0 -23
- cartography/data/jobs/cleanup/gsuite_ingest_users_cleanup.json +0 -11
- cartography/data/jobs/cleanup/kubernetes_import_cleanup.json +0 -70
- cartography/intel/crxcavator/__init__.py +0 -44
- cartography/intel/crxcavator/crxcavator.py +0 -329
- cartography/intel/gcp/crm.py +0 -302
- cartography/intel/gsuite/api.py +0 -284
- cartography/models/aws/ec2/keypairs.py +0 -64
- cartography-0.93.0rc1.dist-info/METADATA +0 -55
- cartography-0.93.0rc1.dist-info/NOTICE +0 -4
- cartography-0.93.0rc1.dist-info/RECORD +0 -341
- /cartography/data/jobs/{analysis → scoped_analysis}/aws_s3acl_analysis.json +0 -0
- {cartography-0.93.0rc1.dist-info → cartography-0.123.0.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from copy import deepcopy
|
|
2
3
|
from typing import Any
|
|
3
4
|
from typing import Dict
|
|
4
5
|
from typing import List
|
|
@@ -6,10 +7,14 @@ from typing import Tuple
|
|
|
6
7
|
|
|
7
8
|
import neo4j
|
|
8
9
|
|
|
10
|
+
from cartography.client.core.tx import load
|
|
11
|
+
from cartography.graph.job import GraphJob
|
|
9
12
|
from cartography.intel.github.util import fetch_all
|
|
13
|
+
from cartography.models.github.orgs import GitHubOrganizationSchema
|
|
14
|
+
from cartography.models.github.users import GitHubOrganizationUserSchema
|
|
15
|
+
from cartography.models.github.users import GitHubUnaffiliatedUserSchema
|
|
10
16
|
from cartography.stats import get_stats_client
|
|
11
17
|
from cartography.util import merge_module_sync_metadata
|
|
12
|
-
from cartography.util import run_cleanup_job
|
|
13
18
|
from cartography.util import timeit
|
|
14
19
|
|
|
15
20
|
logger = logging.getLogger(__name__)
|
|
@@ -32,6 +37,7 @@ GITHUB_ORG_USERS_PAGINATED_GRAPHQL = """
|
|
|
32
37
|
isSiteAdmin
|
|
33
38
|
email
|
|
34
39
|
company
|
|
40
|
+
organizationVerifiedDomainEmails(login: $login)
|
|
35
41
|
}
|
|
36
42
|
role
|
|
37
43
|
}
|
|
@@ -44,83 +50,242 @@ GITHUB_ORG_USERS_PAGINATED_GRAPHQL = """
|
|
|
44
50
|
}
|
|
45
51
|
"""
|
|
46
52
|
|
|
53
|
+
GITHUB_ENTERPRISE_OWNER_USERS_PAGINATED_GRAPHQL = """
|
|
54
|
+
query($login: String!, $cursor: String) {
|
|
55
|
+
organization(login: $login)
|
|
56
|
+
{
|
|
57
|
+
url
|
|
58
|
+
login
|
|
59
|
+
enterpriseOwners(first:100, after: $cursor){
|
|
60
|
+
edges {
|
|
61
|
+
node {
|
|
62
|
+
url
|
|
63
|
+
login
|
|
64
|
+
name
|
|
65
|
+
isSiteAdmin
|
|
66
|
+
email
|
|
67
|
+
company
|
|
68
|
+
organizationVerifiedDomainEmails(login: $login)
|
|
69
|
+
}
|
|
70
|
+
organizationRole
|
|
71
|
+
}
|
|
72
|
+
pageInfo{
|
|
73
|
+
endCursor
|
|
74
|
+
hasNextPage
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
"""
|
|
80
|
+
|
|
47
81
|
|
|
48
82
|
@timeit
|
|
49
|
-
def
|
|
83
|
+
def get_users(token: str, api_url: str, organization: str) -> Tuple[List[Dict], Dict]:
|
|
50
84
|
"""
|
|
51
85
|
Retrieve a list of users from the given GitHub organization as described in
|
|
52
86
|
https://docs.github.com/en/graphql/reference/objects#organizationmemberedge.
|
|
53
87
|
:param token: The Github API token as string.
|
|
54
88
|
:param api_url: The Github v4 API endpoint as string.
|
|
55
89
|
:param organization: The name of the target Github organization as string.
|
|
56
|
-
:return: A 2-tuple containing
|
|
57
|
-
|
|
90
|
+
:return: A 2-tuple containing
|
|
91
|
+
1. a list of dicts representing users and
|
|
92
|
+
2. data on the owning GitHub organization
|
|
93
|
+
see tests.data.github.users.GITHUB_USER_DATA for shape of both
|
|
58
94
|
"""
|
|
95
|
+
logger.info(f"Retrieving users from GitHub organization {organization}")
|
|
59
96
|
users, org = fetch_all(
|
|
60
97
|
token,
|
|
61
98
|
api_url,
|
|
62
99
|
organization,
|
|
63
100
|
GITHUB_ORG_USERS_PAGINATED_GRAPHQL,
|
|
64
|
-
|
|
101
|
+
"membersWithRole",
|
|
65
102
|
)
|
|
66
103
|
return users.edges, org
|
|
67
104
|
|
|
68
105
|
|
|
106
|
+
def get_enterprise_owners(
|
|
107
|
+
token: str,
|
|
108
|
+
api_url: str,
|
|
109
|
+
organization: str,
|
|
110
|
+
) -> Tuple[List[Dict], Dict]:
|
|
111
|
+
"""
|
|
112
|
+
Retrieve a list of enterprise owners from the given GitHub organization as described in
|
|
113
|
+
https://docs.github.com/en/graphql/reference/objects#organizationenterpriseowneredge.
|
|
114
|
+
:param token: The Github API token as string.
|
|
115
|
+
:param api_url: The Github v4 API endpoint as string.
|
|
116
|
+
:param organization: The name of the target Github organization as string.
|
|
117
|
+
:return: A 2-tuple containing
|
|
118
|
+
1. a list of dicts representing users who are enterprise owners
|
|
119
|
+
3. data on the owning GitHub organization
|
|
120
|
+
see tests.data.github.users.GITHUB_ENTERPRISE_OWNER_DATA for shape
|
|
121
|
+
"""
|
|
122
|
+
logger.info(f"Retrieving enterprise owners from GitHub organization {organization}")
|
|
123
|
+
owners, org = fetch_all(
|
|
124
|
+
token,
|
|
125
|
+
api_url,
|
|
126
|
+
organization,
|
|
127
|
+
GITHUB_ENTERPRISE_OWNER_USERS_PAGINATED_GRAPHQL,
|
|
128
|
+
"enterpriseOwners",
|
|
129
|
+
)
|
|
130
|
+
return owners.edges, org
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@timeit
|
|
134
|
+
def transform_users(
|
|
135
|
+
user_data: List[Dict],
|
|
136
|
+
owners_data: List[Dict],
|
|
137
|
+
org_data: Dict,
|
|
138
|
+
) -> Tuple[List[Dict], List[Dict]]:
|
|
139
|
+
"""
|
|
140
|
+
Taking raw user and owner data, return two lists of processed user data:
|
|
141
|
+
* organization users aka affiliated users (users directly affiliated with an organization)
|
|
142
|
+
* unaffiliated users (user who, for example, are enterprise owners but not members of the target organization).
|
|
143
|
+
|
|
144
|
+
:param token: The Github API token as string.
|
|
145
|
+
:param api_url: The Github v4 API endpoint as string.
|
|
146
|
+
:param organization: The name of the target Github organization as string.
|
|
147
|
+
:return: A 2-tuple containing
|
|
148
|
+
1. a list of dicts representing users who are affiliated with the target org
|
|
149
|
+
see tests.data.github.users.GITHUB_USER_DATA for shape
|
|
150
|
+
2. a list of dicts representing users who are not affiliated (e.g. enterprise owners who are not also in
|
|
151
|
+
the target org) — see tests.data.github.users.GITHUB_ENTERPRISE_OWNER_DATA for shape
|
|
152
|
+
3. data on the owning GitHub organization
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
users_dict = {}
|
|
156
|
+
for user in user_data:
|
|
157
|
+
# all members get the 'MEMBER_OF' relationship
|
|
158
|
+
processed_user = deepcopy(user["node"])
|
|
159
|
+
# GitHub returns empty strings for email addresses, so we convert them to None
|
|
160
|
+
if "email" in processed_user and not processed_user["email"]:
|
|
161
|
+
processed_user["email"] = None
|
|
162
|
+
processed_user["hasTwoFactorEnabled"] = user["hasTwoFactorEnabled"]
|
|
163
|
+
processed_user["MEMBER_OF"] = org_data["url"]
|
|
164
|
+
# admins get a second relationship expressing them as such
|
|
165
|
+
if user["role"] == "ADMIN":
|
|
166
|
+
processed_user["ADMIN_OF"] = org_data["url"]
|
|
167
|
+
users_dict[processed_user["url"]] = processed_user
|
|
168
|
+
|
|
169
|
+
owners_dict = {}
|
|
170
|
+
for owner in owners_data:
|
|
171
|
+
processed_owner = deepcopy(owner["node"])
|
|
172
|
+
processed_owner["isEnterpriseOwner"] = True
|
|
173
|
+
if owner["organizationRole"] == "UNAFFILIATED":
|
|
174
|
+
processed_owner["UNAFFILIATED"] = org_data["url"]
|
|
175
|
+
else:
|
|
176
|
+
processed_owner["MEMBER_OF"] = org_data["url"]
|
|
177
|
+
owners_dict[processed_owner["url"]] = processed_owner
|
|
178
|
+
|
|
179
|
+
affiliated_users = [] # users affiliated with the target org
|
|
180
|
+
for url, user in users_dict.items():
|
|
181
|
+
user["isEnterpriseOwner"] = url in owners_dict
|
|
182
|
+
affiliated_users.append(user)
|
|
183
|
+
|
|
184
|
+
unaffiliated_users = [] # users not affiliated with the target org
|
|
185
|
+
for url, owner in owners_dict.items():
|
|
186
|
+
if url not in users_dict:
|
|
187
|
+
unaffiliated_users.append(owner)
|
|
188
|
+
|
|
189
|
+
return affiliated_users, unaffiliated_users
|
|
190
|
+
|
|
191
|
+
|
|
69
192
|
@timeit
|
|
70
|
-
def
|
|
71
|
-
neo4j_session: neo4j.Session,
|
|
193
|
+
def load_users(
|
|
194
|
+
neo4j_session: neo4j.Session,
|
|
195
|
+
node_schema: GitHubOrganizationUserSchema | GitHubUnaffiliatedUserSchema,
|
|
196
|
+
user_data: List[Dict],
|
|
197
|
+
org_data: Dict,
|
|
72
198
|
update_tag: int,
|
|
73
199
|
) -> None:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
"""
|
|
98
|
-
neo4j_session.run(
|
|
99
|
-
query,
|
|
100
|
-
OrgUrl=org_data['url'],
|
|
101
|
-
OrgLogin=org_data['login'],
|
|
102
|
-
UserData=user_data,
|
|
103
|
-
UpdateTag=update_tag,
|
|
200
|
+
logger.info(f"Loading {len(user_data)} GitHub users to the graph")
|
|
201
|
+
load(
|
|
202
|
+
neo4j_session,
|
|
203
|
+
node_schema,
|
|
204
|
+
user_data,
|
|
205
|
+
lastupdated=update_tag,
|
|
206
|
+
org_url=org_data["url"],
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@timeit
|
|
211
|
+
def load_organization(
|
|
212
|
+
neo4j_session: neo4j.Session,
|
|
213
|
+
node_schema: GitHubOrganizationSchema,
|
|
214
|
+
org_data: List[Dict[str, Any]],
|
|
215
|
+
update_tag: int,
|
|
216
|
+
) -> None:
|
|
217
|
+
logger.info(f"Loading {len(org_data)} GitHub organization to the graph")
|
|
218
|
+
load(
|
|
219
|
+
neo4j_session,
|
|
220
|
+
node_schema,
|
|
221
|
+
org_data,
|
|
222
|
+
lastupdated=update_tag,
|
|
104
223
|
)
|
|
105
224
|
|
|
106
225
|
|
|
226
|
+
@timeit
|
|
227
|
+
def cleanup(
|
|
228
|
+
neo4j_session: neo4j.Session,
|
|
229
|
+
common_job_parameters: dict[str, Any],
|
|
230
|
+
) -> None:
|
|
231
|
+
logger.info("Cleaning up GitHub users")
|
|
232
|
+
GraphJob.from_node_schema(
|
|
233
|
+
GitHubOrganizationUserSchema(),
|
|
234
|
+
common_job_parameters,
|
|
235
|
+
).run(neo4j_session)
|
|
236
|
+
GraphJob.from_node_schema(
|
|
237
|
+
GitHubUnaffiliatedUserSchema(),
|
|
238
|
+
common_job_parameters,
|
|
239
|
+
).run(neo4j_session)
|
|
240
|
+
|
|
241
|
+
|
|
107
242
|
@timeit
|
|
108
243
|
def sync(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
244
|
+
neo4j_session: neo4j.Session,
|
|
245
|
+
common_job_parameters: Dict,
|
|
246
|
+
github_api_key: str,
|
|
247
|
+
github_url: str,
|
|
248
|
+
organization: str,
|
|
114
249
|
) -> None:
|
|
115
250
|
logger.info("Syncing GitHub users")
|
|
116
|
-
user_data, org_data =
|
|
117
|
-
|
|
118
|
-
|
|
251
|
+
user_data, org_data = get_users(github_api_key, github_url, organization)
|
|
252
|
+
owners_data, org_data = get_enterprise_owners(
|
|
253
|
+
github_api_key,
|
|
254
|
+
github_url,
|
|
255
|
+
organization,
|
|
256
|
+
)
|
|
257
|
+
processed_affiliated_user_data, processed_unaffiliated_user_data = transform_users(
|
|
258
|
+
user_data,
|
|
259
|
+
owners_data,
|
|
260
|
+
org_data,
|
|
261
|
+
)
|
|
262
|
+
load_organization(
|
|
263
|
+
neo4j_session,
|
|
264
|
+
GitHubOrganizationSchema(),
|
|
265
|
+
[org_data],
|
|
266
|
+
common_job_parameters["UPDATE_TAG"],
|
|
267
|
+
)
|
|
268
|
+
load_users(
|
|
269
|
+
neo4j_session,
|
|
270
|
+
GitHubOrganizationUserSchema(),
|
|
271
|
+
processed_affiliated_user_data,
|
|
272
|
+
org_data,
|
|
273
|
+
common_job_parameters["UPDATE_TAG"],
|
|
274
|
+
)
|
|
275
|
+
load_users(
|
|
276
|
+
neo4j_session,
|
|
277
|
+
GitHubUnaffiliatedUserSchema(),
|
|
278
|
+
processed_unaffiliated_user_data,
|
|
279
|
+
org_data,
|
|
280
|
+
common_job_parameters["UPDATE_TAG"],
|
|
281
|
+
)
|
|
282
|
+
cleanup(neo4j_session, common_job_parameters)
|
|
283
|
+
|
|
119
284
|
merge_module_sync_metadata(
|
|
120
285
|
neo4j_session,
|
|
121
|
-
group_type=
|
|
122
|
-
group_id=org_data[
|
|
123
|
-
synced_type=
|
|
124
|
-
update_tag=common_job_parameters[
|
|
286
|
+
group_type="GitHubOrganization",
|
|
287
|
+
group_id=org_data["url"],
|
|
288
|
+
synced_type="GitHubOrganization",
|
|
289
|
+
update_tag=common_job_parameters["UPDATE_TAG"],
|
|
125
290
|
stat_handler=stat_handler,
|
|
126
291
|
)
|
cartography/intel/github/util.py
CHANGED
|
@@ -13,7 +13,6 @@ from typing import Tuple
|
|
|
13
13
|
|
|
14
14
|
import requests
|
|
15
15
|
|
|
16
|
-
|
|
17
16
|
logger = logging.getLogger(__name__)
|
|
18
17
|
# Connect and read timeouts of 60 seconds each; see https://requests.readthedocs.io/en/master/user/advanced/#timeouts
|
|
19
18
|
_TIMEOUT = (60, 60)
|
|
@@ -26,25 +25,28 @@ class PaginatedGraphqlData(NamedTuple):
|
|
|
26
25
|
|
|
27
26
|
|
|
28
27
|
def handle_rate_limit_sleep(token: str) -> None:
|
|
29
|
-
|
|
28
|
+
"""
|
|
30
29
|
Check the remaining rate limit and sleep if remaining is below threshold
|
|
31
30
|
:param token: The Github API token as string.
|
|
32
|
-
|
|
33
|
-
response = requests.get(
|
|
31
|
+
"""
|
|
32
|
+
response = requests.get(
|
|
33
|
+
"https://api.github.com/rate_limit",
|
|
34
|
+
headers={"Authorization": f"token {token}"},
|
|
35
|
+
)
|
|
34
36
|
response.raise_for_status()
|
|
35
37
|
response_json = response.json()
|
|
36
|
-
rate_limit_obj = response_json[
|
|
37
|
-
remaining = rate_limit_obj[
|
|
38
|
+
rate_limit_obj = response_json["resources"]["graphql"]
|
|
39
|
+
remaining = rate_limit_obj["remaining"]
|
|
38
40
|
threshold = _GRAPHQL_RATE_LIMIT_REMAINING_THRESHOLD
|
|
39
41
|
if remaining > threshold:
|
|
40
42
|
return
|
|
41
|
-
reset_at = datetime.fromtimestamp(rate_limit_obj[
|
|
43
|
+
reset_at = datetime.fromtimestamp(rate_limit_obj["reset"], tz=tz.utc)
|
|
42
44
|
now = datetime.now(tz.utc)
|
|
43
45
|
# add an extra minute for safety
|
|
44
46
|
sleep_duration = reset_at - now + timedelta(minutes=1)
|
|
45
47
|
logger.warning(
|
|
46
|
-
f
|
|
47
|
-
f
|
|
48
|
+
f"Github graphql ratelimit has {remaining} remaining and is under threshold {threshold},"
|
|
49
|
+
f" sleeping until reset at {reset_at} for {sleep_duration}",
|
|
48
50
|
)
|
|
49
51
|
time.sleep(sleep_duration.seconds)
|
|
50
52
|
|
|
@@ -58,11 +60,11 @@ def call_github_api(query: str, variables: str, token: str, api_url: str) -> Dic
|
|
|
58
60
|
:param api_url: the URL to call for the API
|
|
59
61
|
:return: query results json
|
|
60
62
|
"""
|
|
61
|
-
headers = {
|
|
63
|
+
headers = {"Authorization": f"token {token}"}
|
|
62
64
|
try:
|
|
63
65
|
response = requests.post(
|
|
64
66
|
api_url,
|
|
65
|
-
json={
|
|
67
|
+
json={"query": query, "variables": variables},
|
|
66
68
|
headers=headers,
|
|
67
69
|
timeout=_TIMEOUT,
|
|
68
70
|
)
|
|
@@ -75,7 +77,7 @@ def call_github_api(query: str, variables: str, token: str, api_url: str) -> Dic
|
|
|
75
77
|
if "errors" in response_json:
|
|
76
78
|
logger.warning(
|
|
77
79
|
f'call_github_api() response has errors, please investigate. Raw response: {response_json["errors"]}; '
|
|
78
|
-
f
|
|
80
|
+
f"continuing sync.",
|
|
79
81
|
)
|
|
80
82
|
return response_json # type: ignore
|
|
81
83
|
|
|
@@ -101,8 +103,8 @@ def fetch_page(
|
|
|
101
103
|
"""
|
|
102
104
|
gql_vars = {
|
|
103
105
|
**kwargs,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
"login": organization,
|
|
107
|
+
"cursor": cursor,
|
|
106
108
|
}
|
|
107
109
|
gql_vars_json = json.dumps(gql_vars)
|
|
108
110
|
response = call_github_api(query, gql_vars_json, token, api_url)
|
|
@@ -110,14 +112,14 @@ def fetch_page(
|
|
|
110
112
|
|
|
111
113
|
|
|
112
114
|
def fetch_all(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
token: str,
|
|
116
|
+
api_url: str,
|
|
117
|
+
organization: str,
|
|
118
|
+
query: str,
|
|
119
|
+
resource_type: str,
|
|
120
|
+
retries: int = 5,
|
|
121
|
+
resource_inner_type: Optional[str] = None,
|
|
122
|
+
**kwargs: Any,
|
|
121
123
|
) -> Tuple[PaginatedGraphqlData, Dict[str, Any]]:
|
|
122
124
|
"""
|
|
123
125
|
Fetch and return all data items of the given `resource_type` and `field_name` from Github's paginated GraphQL API as
|
|
@@ -155,6 +157,18 @@ def fetch_all(
|
|
|
155
157
|
retry += 1
|
|
156
158
|
exc = err
|
|
157
159
|
except requests.exceptions.HTTPError as err:
|
|
160
|
+
if (
|
|
161
|
+
err.response is not None
|
|
162
|
+
and err.response.status_code == 502
|
|
163
|
+
and kwargs.get("count")
|
|
164
|
+
and kwargs["count"] > 1
|
|
165
|
+
):
|
|
166
|
+
kwargs["count"] = max(1, kwargs["count"] // 2)
|
|
167
|
+
logger.warning(
|
|
168
|
+
"GitHub: Received 502 response. Reducing page size to %s and retrying.",
|
|
169
|
+
kwargs["count"],
|
|
170
|
+
)
|
|
171
|
+
continue
|
|
158
172
|
retry += 1
|
|
159
173
|
exc = err
|
|
160
174
|
except requests.exceptions.ChunkedEncodingError as err:
|
|
@@ -163,37 +177,38 @@ def fetch_all(
|
|
|
163
177
|
|
|
164
178
|
if retry >= retries:
|
|
165
179
|
logger.error(
|
|
166
|
-
f"GitHub: Could not retrieve page of resource `{resource_type}` due to HTTP error
|
|
180
|
+
f"GitHub: Could not retrieve page of resource `{resource_type}` due to HTTP error "
|
|
181
|
+
f"after {retry} retries. Raising exception.",
|
|
167
182
|
exc_info=True,
|
|
168
183
|
)
|
|
169
184
|
raise exc
|
|
170
185
|
elif retry > 0:
|
|
171
|
-
time.sleep(2
|
|
186
|
+
time.sleep(2**retry)
|
|
172
187
|
continue
|
|
173
188
|
|
|
174
|
-
if
|
|
189
|
+
if "data" not in resp:
|
|
175
190
|
logger.warning(
|
|
176
191
|
f'Got no "data" attribute in response: {resp}. '
|
|
177
|
-
f
|
|
178
|
-
f
|
|
192
|
+
f"Stopping requests for organization: {organization} and "
|
|
193
|
+
f"resource_type: {resource_type}",
|
|
179
194
|
)
|
|
180
195
|
has_next_page = False
|
|
181
196
|
continue
|
|
182
197
|
|
|
183
|
-
resource = resp[
|
|
198
|
+
resource = resp["data"]["organization"][resource_type]
|
|
184
199
|
if resource_inner_type:
|
|
185
|
-
resource = resp[
|
|
200
|
+
resource = resp["data"]["organization"][resource_type][resource_inner_type]
|
|
186
201
|
|
|
187
202
|
# Allow for paginating both nodes and edges fields of the GitHub GQL structure.
|
|
188
|
-
data.nodes.extend(resource.get(
|
|
189
|
-
data.edges.extend(resource.get(
|
|
203
|
+
data.nodes.extend(resource.get("nodes", []))
|
|
204
|
+
data.edges.extend(resource.get("edges", []))
|
|
190
205
|
|
|
191
|
-
cursor = resource[
|
|
192
|
-
has_next_page = resource[
|
|
206
|
+
cursor = resource["pageInfo"]["endCursor"]
|
|
207
|
+
has_next_page = resource["pageInfo"]["hasNextPage"]
|
|
193
208
|
if not org_data:
|
|
194
209
|
org_data = {
|
|
195
|
-
|
|
196
|
-
|
|
210
|
+
"url": resp["data"]["organization"]["url"],
|
|
211
|
+
"login": resp["data"]["organization"]["login"],
|
|
197
212
|
}
|
|
198
213
|
|
|
199
214
|
if not org_data:
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
from collections import namedtuple
|
|
6
|
+
|
|
7
|
+
import googleapiclient.discovery
|
|
8
|
+
import neo4j
|
|
9
|
+
from google.auth import default
|
|
10
|
+
from google.auth.exceptions import DefaultCredentialsError
|
|
11
|
+
from google.auth.transport.requests import Request
|
|
12
|
+
from google.oauth2 import credentials
|
|
13
|
+
from google.oauth2 import service_account
|
|
14
|
+
from google.oauth2.credentials import Credentials as OAuth2Credentials
|
|
15
|
+
from google.oauth2.service_account import Credentials as ServiceAccountCredentials
|
|
16
|
+
|
|
17
|
+
from cartography.config import Config
|
|
18
|
+
from cartography.intel.googleworkspace import devices
|
|
19
|
+
from cartography.intel.googleworkspace import groups
|
|
20
|
+
from cartography.intel.googleworkspace import oauth_apps
|
|
21
|
+
from cartography.intel.googleworkspace import tenant
|
|
22
|
+
from cartography.intel.googleworkspace import users
|
|
23
|
+
from cartography.util import timeit
|
|
24
|
+
|
|
25
|
+
OAUTH_SCOPES = [
|
|
26
|
+
"https://www.googleapis.com/auth/admin.directory.customer.readonly",
|
|
27
|
+
"https://www.googleapis.com/auth/admin.directory.user.readonly",
|
|
28
|
+
"https://www.googleapis.com/auth/admin.directory.user.security",
|
|
29
|
+
"https://www.googleapis.com/auth/cloud-identity.devices.readonly",
|
|
30
|
+
"https://www.googleapis.com/auth/cloud-identity.groups.readonly",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
Resources = namedtuple("Resources", ["admin", "cloudidentity"])
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _initialize_resources(
|
|
39
|
+
creds: OAuth2Credentials | ServiceAccountCredentials,
|
|
40
|
+
) -> Resources:
|
|
41
|
+
"""
|
|
42
|
+
Create namedtuple of all resource objects necessary for Google API data gathering.
|
|
43
|
+
:param credentials: The credentials object
|
|
44
|
+
:return: namedtuple of all resource objects
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
return Resources(
|
|
48
|
+
googleapiclient.discovery.build(
|
|
49
|
+
"admin",
|
|
50
|
+
"directory_v1",
|
|
51
|
+
credentials=creds,
|
|
52
|
+
cache_discovery=False,
|
|
53
|
+
),
|
|
54
|
+
googleapiclient.discovery.build(
|
|
55
|
+
"cloudidentity",
|
|
56
|
+
"v1",
|
|
57
|
+
credentials=creds,
|
|
58
|
+
cache_discovery=False,
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@timeit
|
|
64
|
+
def start_googleworkspace_ingestion(
|
|
65
|
+
neo4j_session: neo4j.Session, config: Config
|
|
66
|
+
) -> None:
|
|
67
|
+
"""
|
|
68
|
+
Starts the Google Workspace ingestion process by initializing
|
|
69
|
+
|
|
70
|
+
:param neo4j_session: The Neo4j session
|
|
71
|
+
:param config: A `cartography.config` object
|
|
72
|
+
:return: Nothing
|
|
73
|
+
"""
|
|
74
|
+
common_job_parameters = {
|
|
75
|
+
"UPDATE_TAG": config.update_tag,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
creds: OAuth2Credentials | ServiceAccountCredentials
|
|
79
|
+
if config.googleworkspace_auth_method == "delegated": # Legacy delegated method
|
|
80
|
+
if config.googleworkspace_config is None or not os.path.isfile(
|
|
81
|
+
config.googleworkspace_config
|
|
82
|
+
):
|
|
83
|
+
logger.warning(
|
|
84
|
+
(
|
|
85
|
+
"The Google Workspace config file is not set or is not a valid file."
|
|
86
|
+
"Skipping Google Workspace ingestion."
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
return
|
|
90
|
+
logger.info(
|
|
91
|
+
"Attempting to authenticate to Google Workspace using legacy delegated method"
|
|
92
|
+
)
|
|
93
|
+
try:
|
|
94
|
+
creds = service_account.Credentials.from_service_account_file(
|
|
95
|
+
config.googleworkspace_config,
|
|
96
|
+
scopes=OAUTH_SCOPES,
|
|
97
|
+
)
|
|
98
|
+
creds = creds.with_subject(os.environ.get("GOOGLE_DELEGATED_ADMIN"))
|
|
99
|
+
|
|
100
|
+
except DefaultCredentialsError as e:
|
|
101
|
+
logger.error(
|
|
102
|
+
(
|
|
103
|
+
"Unable to initialize Google Workspace creds. If you don't have Google Workspace data or don't want to load "
|
|
104
|
+
"Google Workspace data then you can ignore this message. Otherwise, the error code is: %s "
|
|
105
|
+
"Make sure your Google Workspace credentials file (if any) is valid. "
|
|
106
|
+
"For more details see documentation."
|
|
107
|
+
),
|
|
108
|
+
e,
|
|
109
|
+
)
|
|
110
|
+
return
|
|
111
|
+
elif config.googleworkspace_auth_method == "oauth":
|
|
112
|
+
auth_tokens = json.loads(
|
|
113
|
+
str(base64.b64decode(config.googleworkspace_config).decode())
|
|
114
|
+
)
|
|
115
|
+
logger.info("Attempting to authenticate to Google Workspace using OAuth")
|
|
116
|
+
try:
|
|
117
|
+
creds = credentials.Credentials(
|
|
118
|
+
token=None,
|
|
119
|
+
client_id=auth_tokens["client_id"],
|
|
120
|
+
client_secret=auth_tokens["client_secret"],
|
|
121
|
+
refresh_token=auth_tokens["refresh_token"],
|
|
122
|
+
expiry=None,
|
|
123
|
+
token_uri=auth_tokens["token_uri"],
|
|
124
|
+
scopes=OAUTH_SCOPES,
|
|
125
|
+
)
|
|
126
|
+
creds.refresh(Request())
|
|
127
|
+
except DefaultCredentialsError as e:
|
|
128
|
+
logger.error(
|
|
129
|
+
(
|
|
130
|
+
"Unable to initialize Google Workspace creds. If you don't have Google Workspace data or don't want to load "
|
|
131
|
+
"Google Workspace data then you can ignore this message. Otherwise, the error code is: %s "
|
|
132
|
+
"Make sure your Google Workspace credentials are configured correctly, your credentials are valid. "
|
|
133
|
+
"For more details see documentation."
|
|
134
|
+
),
|
|
135
|
+
e,
|
|
136
|
+
)
|
|
137
|
+
return
|
|
138
|
+
elif config.googleworkspace_auth_method == "default":
|
|
139
|
+
logger.info(
|
|
140
|
+
"Attempting to authenticate to Google Workspace using default credentials"
|
|
141
|
+
)
|
|
142
|
+
try:
|
|
143
|
+
creds, _ = default(scopes=OAUTH_SCOPES)
|
|
144
|
+
except DefaultCredentialsError as e:
|
|
145
|
+
logger.error(
|
|
146
|
+
(
|
|
147
|
+
"Unable to initialize Google Workspace creds using default credentials. If you don't have Google Workspace data or "
|
|
148
|
+
"don't want to load Google Workspace data then you can ignore this message. Otherwise, the error code is: %s "
|
|
149
|
+
"Make sure you have valid application default credentials configured. "
|
|
150
|
+
"For more details see documentation."
|
|
151
|
+
),
|
|
152
|
+
e,
|
|
153
|
+
)
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
resources = _initialize_resources(creds)
|
|
157
|
+
customer_id = tenant.sync_googleworkspace_tenant(
|
|
158
|
+
neo4j_session,
|
|
159
|
+
resources.admin,
|
|
160
|
+
config.update_tag,
|
|
161
|
+
common_job_parameters,
|
|
162
|
+
)
|
|
163
|
+
common_job_parameters["CUSTOMER_ID"] = customer_id
|
|
164
|
+
|
|
165
|
+
# Sync users and get the list of transformed users for OAuth token sync
|
|
166
|
+
user_ids = users.sync_googleworkspace_users(
|
|
167
|
+
neo4j_session,
|
|
168
|
+
resources.admin,
|
|
169
|
+
config.update_tag,
|
|
170
|
+
common_job_parameters,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Sync OAuth apps for all users
|
|
174
|
+
oauth_apps.sync_googleworkspace_oauth_apps(
|
|
175
|
+
neo4j_session,
|
|
176
|
+
resources.admin,
|
|
177
|
+
user_ids,
|
|
178
|
+
config.update_tag,
|
|
179
|
+
common_job_parameters,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
groups.sync_googleworkspace_groups(
|
|
183
|
+
neo4j_session,
|
|
184
|
+
resources.cloudidentity,
|
|
185
|
+
config.update_tag,
|
|
186
|
+
common_job_parameters,
|
|
187
|
+
)
|
|
188
|
+
devices.sync_googleworkspace_devices(
|
|
189
|
+
neo4j_session,
|
|
190
|
+
resources.cloudidentity,
|
|
191
|
+
config.update_tag,
|
|
192
|
+
common_job_parameters,
|
|
193
|
+
)
|