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
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import neo4j
|
|
5
|
+
|
|
6
|
+
from cartography.client.core.tx import load
|
|
7
|
+
from cartography.graph.job import GraphJob
|
|
8
|
+
from cartography.intel.sentinelone.api import get_paginated_results
|
|
9
|
+
from cartography.models.sentinelone.agent import S1AgentSchema
|
|
10
|
+
from cartography.util import timeit
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@timeit
|
|
16
|
+
def get_agents(api_url: str, api_token: str, account_id: str) -> list[dict[str, Any]]:
|
|
17
|
+
"""
|
|
18
|
+
Get agent data from SentinelOne API
|
|
19
|
+
:param api_url: The SentinelOne API URL
|
|
20
|
+
:param api_token: The SentinelOne API token
|
|
21
|
+
:param account_id: The SentinelOne account ID
|
|
22
|
+
:return: Raw agent data from API
|
|
23
|
+
"""
|
|
24
|
+
logger.info(f"Retrieving SentinelOne agent data for account {account_id}")
|
|
25
|
+
|
|
26
|
+
agents = get_paginated_results(
|
|
27
|
+
api_url=api_url,
|
|
28
|
+
endpoint="web/api/v2.1/agents",
|
|
29
|
+
api_token=api_token,
|
|
30
|
+
params={
|
|
31
|
+
"accountIds": account_id,
|
|
32
|
+
"limit": 1000,
|
|
33
|
+
},
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
logger.info(f"Retrieved {len(agents)} agents from SentinelOne account {account_id}")
|
|
37
|
+
return agents
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@timeit
|
|
41
|
+
def transform_agents(agent_list: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
42
|
+
"""
|
|
43
|
+
Transform SentinelOne agent data for loading into Neo4j
|
|
44
|
+
:param agent_list: Raw agent data from the API
|
|
45
|
+
:return: Transformed agent data
|
|
46
|
+
"""
|
|
47
|
+
result: list[dict[str, Any]] = []
|
|
48
|
+
|
|
49
|
+
for agent in agent_list:
|
|
50
|
+
transformed_agent = {
|
|
51
|
+
# Required fields - use direct access (will raise KeyError if missing)
|
|
52
|
+
"id": agent["id"],
|
|
53
|
+
# Optional fields - use .get() with None default
|
|
54
|
+
"uuid": agent.get("uuid"),
|
|
55
|
+
"computer_name": agent.get("computerName"),
|
|
56
|
+
"firewall_enabled": agent.get("firewallEnabled"),
|
|
57
|
+
"os_name": agent.get("osName"),
|
|
58
|
+
"os_revision": agent.get("osRevision"),
|
|
59
|
+
"domain": agent.get("domain"),
|
|
60
|
+
"last_active": agent.get("lastActiveDate"),
|
|
61
|
+
"last_successful_scan": agent.get("lastSuccessfulScanDate"),
|
|
62
|
+
"scan_status": agent.get("scanStatus"),
|
|
63
|
+
"serial_number": agent.get("serialNumber"),
|
|
64
|
+
}
|
|
65
|
+
result.append(transformed_agent)
|
|
66
|
+
|
|
67
|
+
return result
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@timeit
|
|
71
|
+
def load_agents(
|
|
72
|
+
neo4j_session: neo4j.Session,
|
|
73
|
+
data: list[dict[str, Any]],
|
|
74
|
+
account_id: str,
|
|
75
|
+
update_tag: int,
|
|
76
|
+
) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Load SentinelOne agent data into Neo4j
|
|
79
|
+
:param neo4j_session: Neo4j session
|
|
80
|
+
:param data: The transformed agent data
|
|
81
|
+
:param account_id: The SentinelOne account ID
|
|
82
|
+
:param update_tag: Update tag for tracking data freshness
|
|
83
|
+
:return: None
|
|
84
|
+
"""
|
|
85
|
+
logger.info(
|
|
86
|
+
f"Loading {len(data)} SentinelOne agents into Neo4j for account {account_id}"
|
|
87
|
+
)
|
|
88
|
+
load(
|
|
89
|
+
neo4j_session,
|
|
90
|
+
S1AgentSchema(),
|
|
91
|
+
data,
|
|
92
|
+
lastupdated=update_tag,
|
|
93
|
+
S1_ACCOUNT_ID=account_id,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@timeit
|
|
98
|
+
def cleanup(
|
|
99
|
+
neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
|
|
100
|
+
) -> None:
|
|
101
|
+
"""
|
|
102
|
+
Remove stale SentinelOne agent data from Neo4j
|
|
103
|
+
:param neo4j_session: Neo4j session
|
|
104
|
+
:param common_job_parameters: Common job parameters for cleanup
|
|
105
|
+
:return: None
|
|
106
|
+
"""
|
|
107
|
+
logger.debug("Running S1Agent cleanup job")
|
|
108
|
+
GraphJob.from_node_schema(S1AgentSchema(), common_job_parameters).run(neo4j_session)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@timeit
|
|
112
|
+
def sync(
|
|
113
|
+
neo4j_session: neo4j.Session,
|
|
114
|
+
common_job_parameters: dict[str, Any],
|
|
115
|
+
) -> None:
|
|
116
|
+
"""
|
|
117
|
+
Sync SentinelOne agents using the standard sync pattern
|
|
118
|
+
:param neo4j_session: Neo4j session
|
|
119
|
+
:param common_job_parameters: Common job parameters containing API_URL, API_TOKEN, S1_ACCOUNT_ID, UPDATE_TAG
|
|
120
|
+
:return: None
|
|
121
|
+
"""
|
|
122
|
+
api_url = common_job_parameters["API_URL"]
|
|
123
|
+
api_token = common_job_parameters["API_TOKEN"]
|
|
124
|
+
account_id = common_job_parameters["S1_ACCOUNT_ID"]
|
|
125
|
+
update_tag = common_job_parameters["UPDATE_TAG"]
|
|
126
|
+
|
|
127
|
+
logger.info(f"Syncing SentinelOne agent data for account {account_id}")
|
|
128
|
+
|
|
129
|
+
# 1. GET - Fetch data from API
|
|
130
|
+
agents_raw_data = get_agents(api_url, api_token, account_id)
|
|
131
|
+
|
|
132
|
+
# 2. TRANSFORM - Shape data for ingestion
|
|
133
|
+
transformed_data = transform_agents(agents_raw_data)
|
|
134
|
+
|
|
135
|
+
# 3. LOAD - Ingest to Neo4j using data model
|
|
136
|
+
load_agents(neo4j_session, transformed_data, account_id, update_tag)
|
|
137
|
+
|
|
138
|
+
# 4. CLEANUP - Remove stale data
|
|
139
|
+
cleanup(neo4j_session, common_job_parameters)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
|
|
5
|
+
from cartography.util import backoff_handler
|
|
6
|
+
from cartography.util import retries_with_backoff
|
|
7
|
+
|
|
8
|
+
# Connect and read timeouts of 60 seconds each
|
|
9
|
+
_TIMEOUT = (60, 60)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _call_sentinelone_api_base(
|
|
13
|
+
api_url: str,
|
|
14
|
+
endpoint: str,
|
|
15
|
+
api_token: str,
|
|
16
|
+
method: str = "GET",
|
|
17
|
+
params: dict[str, Any] | None = None,
|
|
18
|
+
data: dict[str, Any] | None = None,
|
|
19
|
+
) -> dict[str, Any]:
|
|
20
|
+
"""
|
|
21
|
+
Call the SentinelOne API
|
|
22
|
+
:param api_url: The base URL for the SentinelOne API
|
|
23
|
+
:param endpoint: The API endpoint to call
|
|
24
|
+
:param api_token: The API token for authentication
|
|
25
|
+
:param method: The HTTP method to use (default is GET)
|
|
26
|
+
:param params: Query parameters to include in the request
|
|
27
|
+
:param data: Data to include in the request body for POST/PUT methods
|
|
28
|
+
:return: The JSON response from the API
|
|
29
|
+
"""
|
|
30
|
+
full_url = f"{api_url.rstrip('/')}/{endpoint.lstrip('/')}"
|
|
31
|
+
|
|
32
|
+
headers = {
|
|
33
|
+
"Accept": "application/json",
|
|
34
|
+
"Authorization": f"ApiToken {api_token}",
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
response = requests.request(
|
|
39
|
+
method=method,
|
|
40
|
+
url=full_url,
|
|
41
|
+
headers=headers,
|
|
42
|
+
params=params,
|
|
43
|
+
json=data,
|
|
44
|
+
timeout=_TIMEOUT,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Raise an exception for HTTP errors (this will be caught by backoff wrapper)
|
|
48
|
+
response.raise_for_status()
|
|
49
|
+
|
|
50
|
+
return response.json()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def call_sentinelone_api(
|
|
54
|
+
api_url: str,
|
|
55
|
+
endpoint: str,
|
|
56
|
+
api_token: str,
|
|
57
|
+
method: str = "GET",
|
|
58
|
+
params: dict[str, Any] | None = None,
|
|
59
|
+
data: dict[str, Any] | None = None,
|
|
60
|
+
) -> dict[str, Any]:
|
|
61
|
+
"""
|
|
62
|
+
Call the SentinelOne API with backoff functionality
|
|
63
|
+
:param api_url: The base URL for the SentinelOne API
|
|
64
|
+
:param endpoint: The API endpoint to call
|
|
65
|
+
:param api_token: The API token for authentication
|
|
66
|
+
:param method: The HTTP method to use (default is GET)
|
|
67
|
+
:param params: Query parameters to include in the request
|
|
68
|
+
:param data: Data to include in the request body for POST/PUT methods
|
|
69
|
+
:return: The JSON response from the API
|
|
70
|
+
"""
|
|
71
|
+
wrapped_func = retries_with_backoff(
|
|
72
|
+
func=_call_sentinelone_api_base,
|
|
73
|
+
exception_type=requests.exceptions.RequestException, # Covers Timeout and HTTPError as subclasses
|
|
74
|
+
max_tries=5, # Maximum number of retry attempts
|
|
75
|
+
on_backoff=backoff_handler,
|
|
76
|
+
)
|
|
77
|
+
return wrapped_func(api_url, endpoint, api_token, method, params, data)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_paginated_results(
|
|
81
|
+
api_url: str,
|
|
82
|
+
endpoint: str,
|
|
83
|
+
api_token: str,
|
|
84
|
+
params: dict[str, Any] | None = None,
|
|
85
|
+
) -> list[dict[str, Any]]:
|
|
86
|
+
"""
|
|
87
|
+
Handle cursor-based pagination for SentinelOne API requests
|
|
88
|
+
:param api_url: The base URL for the SentinelOne API
|
|
89
|
+
:param endpoint: The API endpoint to call
|
|
90
|
+
:param api_token: The API token for authentication
|
|
91
|
+
:param params: Query parameters to include in the request
|
|
92
|
+
:return: A list of all items from all pages
|
|
93
|
+
"""
|
|
94
|
+
query_params = params or {}
|
|
95
|
+
|
|
96
|
+
# Set default pagination parameters if not provided
|
|
97
|
+
if "limit" not in query_params:
|
|
98
|
+
query_params["limit"] = 100
|
|
99
|
+
|
|
100
|
+
next_cursor = None
|
|
101
|
+
total_items = []
|
|
102
|
+
|
|
103
|
+
while True:
|
|
104
|
+
if next_cursor:
|
|
105
|
+
query_params["cursor"] = next_cursor
|
|
106
|
+
|
|
107
|
+
response = call_sentinelone_api(
|
|
108
|
+
api_url=api_url,
|
|
109
|
+
endpoint=endpoint,
|
|
110
|
+
api_token=api_token,
|
|
111
|
+
params=query_params,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
items = response.get("data", [])
|
|
115
|
+
if not items:
|
|
116
|
+
break
|
|
117
|
+
|
|
118
|
+
total_items.extend(items)
|
|
119
|
+
pagination = response.get("pagination", {})
|
|
120
|
+
next_cursor = pagination.get("nextCursor")
|
|
121
|
+
if not next_cursor:
|
|
122
|
+
break
|
|
123
|
+
|
|
124
|
+
return total_items
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import neo4j
|
|
5
|
+
|
|
6
|
+
from cartography.client.core.tx import load
|
|
7
|
+
from cartography.graph.job import GraphJob
|
|
8
|
+
from cartography.intel.sentinelone.api import get_paginated_results
|
|
9
|
+
from cartography.intel.sentinelone.utils import get_application_id
|
|
10
|
+
from cartography.intel.sentinelone.utils import get_application_version_id
|
|
11
|
+
from cartography.models.sentinelone.application import S1ApplicationSchema
|
|
12
|
+
from cartography.models.sentinelone.application_version import (
|
|
13
|
+
S1ApplicationVersionSchema,
|
|
14
|
+
)
|
|
15
|
+
from cartography.util import timeit
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@timeit
|
|
21
|
+
def get_application_data(
|
|
22
|
+
account_id: str, api_url: str, api_token: str
|
|
23
|
+
) -> list[dict[str, Any]]:
|
|
24
|
+
"""
|
|
25
|
+
Get application data from SentinelOne API
|
|
26
|
+
:param account_id: SentinelOne account ID
|
|
27
|
+
:param api_url: SentinelOne API URL
|
|
28
|
+
:param api_token: SentinelOne API token
|
|
29
|
+
:return: A list of application data dictionaries
|
|
30
|
+
"""
|
|
31
|
+
logger.info(f"Retrieving SentinelOne application data for account {account_id}")
|
|
32
|
+
applications = get_paginated_results(
|
|
33
|
+
api_url=api_url,
|
|
34
|
+
endpoint="/web/api/v2.1/application-management/inventory",
|
|
35
|
+
api_token=api_token,
|
|
36
|
+
params={
|
|
37
|
+
"accountIds": account_id,
|
|
38
|
+
"limit": 1000,
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
logger.info(f"Retrieved {len(applications)} applications from SentinelOne")
|
|
43
|
+
return applications
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@timeit
|
|
47
|
+
def get_application_installs(
|
|
48
|
+
app_inventory: list[dict[str, Any]], account_id: str, api_url: str, api_token: str
|
|
49
|
+
) -> list[dict[str, Any]]:
|
|
50
|
+
"""
|
|
51
|
+
Get application installs from SentinelOne API
|
|
52
|
+
:param app_inventory: List of applications to get installs for
|
|
53
|
+
:param account_id: SentinelOne account ID
|
|
54
|
+
:param api_url: SentinelOne API URL
|
|
55
|
+
:param api_token: SentinelOne API token
|
|
56
|
+
:return: A list of application installs data dictionaries
|
|
57
|
+
"""
|
|
58
|
+
logger.info(
|
|
59
|
+
f"Retrieving SentinelOne application installs for "
|
|
60
|
+
f"{len(app_inventory)} applications in account "
|
|
61
|
+
f"{account_id}",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
application_installs = []
|
|
65
|
+
for i, app in enumerate(app_inventory):
|
|
66
|
+
logger.info(
|
|
67
|
+
f"Retrieving SentinelOne installs for {app.get('applicationName')} "
|
|
68
|
+
f"{app.get('applicationVendor')} ({i + 1}/{len(app_inventory)})",
|
|
69
|
+
)
|
|
70
|
+
name = app["applicationName"]
|
|
71
|
+
vendor = app["applicationVendor"]
|
|
72
|
+
app_installs = get_paginated_results(
|
|
73
|
+
api_url=api_url,
|
|
74
|
+
endpoint="/web/api/v2.1/application-management/inventory/endpoints",
|
|
75
|
+
api_token=api_token,
|
|
76
|
+
params={
|
|
77
|
+
"accountIds": account_id,
|
|
78
|
+
"limit": 1000,
|
|
79
|
+
"applicationName": name,
|
|
80
|
+
"applicationVendor": vendor,
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Replace applicationVendor and applicationName with original values
|
|
85
|
+
# for consistency with the application data
|
|
86
|
+
for app_install in app_installs:
|
|
87
|
+
app_install["applicationVendor"] = vendor
|
|
88
|
+
app_install["applicationName"] = name
|
|
89
|
+
application_installs.extend(app_installs)
|
|
90
|
+
|
|
91
|
+
return application_installs
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def transform_applications(
|
|
95
|
+
applications_list: list[dict[str, Any]],
|
|
96
|
+
) -> list[dict[str, Any]]:
|
|
97
|
+
"""
|
|
98
|
+
Transform SentinelOne application data for loading into Neo4j
|
|
99
|
+
:param applications_list: Raw application data from the API
|
|
100
|
+
:return: Transformed application data
|
|
101
|
+
"""
|
|
102
|
+
transformed_data = []
|
|
103
|
+
for app in applications_list:
|
|
104
|
+
vendor = app["applicationVendor"].strip()
|
|
105
|
+
name = app["applicationName"].strip()
|
|
106
|
+
app_id = get_application_id(name, vendor)
|
|
107
|
+
transformed_app = {
|
|
108
|
+
"id": app_id,
|
|
109
|
+
"name": name,
|
|
110
|
+
"vendor": vendor,
|
|
111
|
+
}
|
|
112
|
+
transformed_data.append(transformed_app)
|
|
113
|
+
|
|
114
|
+
return transformed_data
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def transform_application_versions(
|
|
118
|
+
application_installs_list: list[dict[str, Any]],
|
|
119
|
+
) -> list[dict[str, Any]]:
|
|
120
|
+
"""
|
|
121
|
+
Transform SentinelOne application installs for loading into Neo4j
|
|
122
|
+
:param application_installs_list: Raw application installs data from the API
|
|
123
|
+
:return: Transformed application installs data
|
|
124
|
+
"""
|
|
125
|
+
transformed_data = []
|
|
126
|
+
for installed_version in application_installs_list:
|
|
127
|
+
app_name = installed_version["applicationName"]
|
|
128
|
+
app_vendor = installed_version["applicationVendor"]
|
|
129
|
+
version = installed_version.get("version") or "unknown"
|
|
130
|
+
|
|
131
|
+
transformed_version = {
|
|
132
|
+
"id": get_application_version_id(
|
|
133
|
+
app_name,
|
|
134
|
+
app_vendor,
|
|
135
|
+
version,
|
|
136
|
+
),
|
|
137
|
+
"application_id": get_application_id(
|
|
138
|
+
app_name,
|
|
139
|
+
app_vendor,
|
|
140
|
+
),
|
|
141
|
+
"application_name": app_name,
|
|
142
|
+
"application_vendor": app_vendor,
|
|
143
|
+
"agent_uuid": installed_version.get("endpointUuid"),
|
|
144
|
+
"installation_path": installed_version.get("applicationInstallationPath"),
|
|
145
|
+
"installed_dt": installed_version.get("applicationInstallationDate"),
|
|
146
|
+
"version": version,
|
|
147
|
+
}
|
|
148
|
+
transformed_data.append(transformed_version)
|
|
149
|
+
|
|
150
|
+
return transformed_data
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@timeit
|
|
154
|
+
def load_application_data(
|
|
155
|
+
neo4j_session: neo4j.Session,
|
|
156
|
+
data: list[dict[str, Any]],
|
|
157
|
+
account_id: str,
|
|
158
|
+
update_tag: int,
|
|
159
|
+
) -> None:
|
|
160
|
+
"""
|
|
161
|
+
Load SentinelOne application data into Neo4j
|
|
162
|
+
:param neo4j_session: Neo4j session
|
|
163
|
+
:param data: The transformed application data
|
|
164
|
+
:param account_id: The SentinelOne account ID
|
|
165
|
+
:param update_tag: Update tag to set on the nodes
|
|
166
|
+
:return: None
|
|
167
|
+
"""
|
|
168
|
+
logger.info(f"Loading {len(data)} SentinelOne applications into Neo4j")
|
|
169
|
+
load(
|
|
170
|
+
neo4j_session,
|
|
171
|
+
S1ApplicationSchema(),
|
|
172
|
+
data,
|
|
173
|
+
lastupdated=update_tag,
|
|
174
|
+
S1_ACCOUNT_ID=account_id,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@timeit
|
|
179
|
+
def load_application_versions(
|
|
180
|
+
neo4j_session: neo4j.Session,
|
|
181
|
+
data: list[dict[str, Any]],
|
|
182
|
+
account_id: str,
|
|
183
|
+
update_tag: int,
|
|
184
|
+
) -> None:
|
|
185
|
+
logger.info(f"Loading {len(data)} SentinelOne application versions into Neo4j")
|
|
186
|
+
load(
|
|
187
|
+
neo4j_session,
|
|
188
|
+
S1ApplicationVersionSchema(),
|
|
189
|
+
data,
|
|
190
|
+
lastupdated=update_tag,
|
|
191
|
+
S1_ACCOUNT_ID=account_id,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@timeit
|
|
196
|
+
def cleanup(
|
|
197
|
+
neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
|
|
198
|
+
) -> None:
|
|
199
|
+
logger.debug("Running SentinelOne S1Application cleanup")
|
|
200
|
+
GraphJob.from_node_schema(S1ApplicationSchema(), common_job_parameters).run(
|
|
201
|
+
neo4j_session
|
|
202
|
+
)
|
|
203
|
+
logger.debug("Running SentinelOne S1ApplicationVersion cleanup")
|
|
204
|
+
GraphJob.from_node_schema(S1ApplicationVersionSchema(), common_job_parameters).run(
|
|
205
|
+
neo4j_session
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@timeit
|
|
210
|
+
def sync(
|
|
211
|
+
neo4j_session: neo4j.Session,
|
|
212
|
+
common_job_parameters: dict[str, Any],
|
|
213
|
+
) -> None:
|
|
214
|
+
"""
|
|
215
|
+
Sync SentinelOne applications
|
|
216
|
+
:param neo4j_session: Neo4j session
|
|
217
|
+
:param common_job_parameters: Common job parameters containing API_URL, API_TOKEN, etc.
|
|
218
|
+
:return: None
|
|
219
|
+
"""
|
|
220
|
+
logger.info("Syncing SentinelOne application data")
|
|
221
|
+
account_id = str(common_job_parameters["S1_ACCOUNT_ID"])
|
|
222
|
+
api_url = str(common_job_parameters["API_URL"])
|
|
223
|
+
api_token = str(common_job_parameters["API_TOKEN"])
|
|
224
|
+
|
|
225
|
+
applications = get_application_data(account_id, api_url, api_token)
|
|
226
|
+
application_versions = get_application_installs(
|
|
227
|
+
applications, account_id, api_url, api_token
|
|
228
|
+
)
|
|
229
|
+
transformed_applications = transform_applications(applications)
|
|
230
|
+
transformed_application_versions = transform_application_versions(
|
|
231
|
+
application_versions
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
load_application_data(
|
|
235
|
+
neo4j_session,
|
|
236
|
+
transformed_applications,
|
|
237
|
+
account_id,
|
|
238
|
+
common_job_parameters["UPDATE_TAG"],
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
load_application_versions(
|
|
242
|
+
neo4j_session,
|
|
243
|
+
transformed_application_versions,
|
|
244
|
+
account_id,
|
|
245
|
+
common_job_parameters["UPDATE_TAG"],
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
cleanup(neo4j_session, common_job_parameters)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import neo4j
|
|
5
|
+
|
|
6
|
+
from cartography.client.core.tx import load
|
|
7
|
+
from cartography.graph.job import GraphJob
|
|
8
|
+
from cartography.intel.sentinelone.api import get_paginated_results
|
|
9
|
+
from cartography.intel.sentinelone.utils import get_application_version_id
|
|
10
|
+
from cartography.models.sentinelone.cve import S1CVESchema
|
|
11
|
+
from cartography.util import timeit
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@timeit
|
|
17
|
+
def get(api_url: str, api_token: str, account_id: str) -> list[dict[str, Any]]:
|
|
18
|
+
logger.info("Retrieving SentinelOne CVE data")
|
|
19
|
+
cves = get_paginated_results(
|
|
20
|
+
api_url=api_url,
|
|
21
|
+
endpoint="/web/api/v2.1/application-management/risks",
|
|
22
|
+
api_token=api_token,
|
|
23
|
+
params={
|
|
24
|
+
"limit": 1000,
|
|
25
|
+
"accountIds": account_id,
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
logger.info("Retrieved %d CVEs from SentinelOne", len(cves))
|
|
30
|
+
return cves
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def transform(cves_list: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
34
|
+
"""
|
|
35
|
+
Transform SentinelOne CVE data for loading into Neo4j
|
|
36
|
+
"""
|
|
37
|
+
transformed_cves = []
|
|
38
|
+
for cve in cves_list:
|
|
39
|
+
app_version_id = get_application_version_id(
|
|
40
|
+
cve.get("applicationName", "unknown"),
|
|
41
|
+
cve.get("applicationVendor", "unknown"),
|
|
42
|
+
cve.get("applicationVersion", "unknown"),
|
|
43
|
+
)
|
|
44
|
+
transformed_cve = {
|
|
45
|
+
# Required fields - let them fail if missing
|
|
46
|
+
"id": f"S1|{cve['cveId']}", # Use CVE ID as the unique identifier for the node
|
|
47
|
+
"cve_id": cve["cveId"],
|
|
48
|
+
# Optional fields - use .get() with None default
|
|
49
|
+
"application_version_id": app_version_id,
|
|
50
|
+
"base_score": cve.get("baseScore"),
|
|
51
|
+
"cvss_version": cve.get("cvssVersion"),
|
|
52
|
+
"published_date": cve.get("publishedDate"),
|
|
53
|
+
"severity": cve.get("severity"),
|
|
54
|
+
# Relationship properties
|
|
55
|
+
"days_detected": cve.get("daysDetected"),
|
|
56
|
+
"detection_date": cve.get("detectionDate"),
|
|
57
|
+
"last_scan_date": cve.get("lastScanDate"),
|
|
58
|
+
"last_scan_result": cve.get("lastScanResult"),
|
|
59
|
+
"status": cve.get("status"),
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
transformed_cves.append(transformed_cve)
|
|
63
|
+
|
|
64
|
+
return transformed_cves
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@timeit
|
|
68
|
+
def load_cves(
|
|
69
|
+
neo4j_session: neo4j.Session,
|
|
70
|
+
data: list[dict[str, Any]],
|
|
71
|
+
account_id: str,
|
|
72
|
+
update_tag: int,
|
|
73
|
+
) -> None:
|
|
74
|
+
"""
|
|
75
|
+
Load SentinelOne CVE data into Neo4j
|
|
76
|
+
"""
|
|
77
|
+
logger.info(f"Loading {len(data)} SentinelOne CVEs into Neo4j")
|
|
78
|
+
load(
|
|
79
|
+
neo4j_session,
|
|
80
|
+
S1CVESchema(),
|
|
81
|
+
data,
|
|
82
|
+
lastupdated=update_tag,
|
|
83
|
+
S1_ACCOUNT_ID=account_id, # Fixed parameter name to match model
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@timeit
|
|
88
|
+
def cleanup(
|
|
89
|
+
neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
|
|
90
|
+
) -> None:
|
|
91
|
+
"""Remove CVE nodes that weren't updated in this sync run"""
|
|
92
|
+
logger.debug("Running S1CVEs cleanup")
|
|
93
|
+
GraphJob.from_node_schema(S1CVESchema(), common_job_parameters).run(neo4j_session)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@timeit
|
|
97
|
+
def sync(
|
|
98
|
+
neo4j_session: neo4j.Session,
|
|
99
|
+
common_job_parameters: dict[str, Any],
|
|
100
|
+
) -> None:
|
|
101
|
+
"""
|
|
102
|
+
Sync SentinelOne CVEs following the standard pattern:
|
|
103
|
+
GET -> TRANSFORM -> LOAD -> CLEANUP
|
|
104
|
+
"""
|
|
105
|
+
logger.info("Syncing SentinelOne CVE data")
|
|
106
|
+
|
|
107
|
+
api_url = common_job_parameters.get("API_URL", "")
|
|
108
|
+
api_token = common_job_parameters.get("API_TOKEN", "")
|
|
109
|
+
account_id = common_job_parameters.get("S1_ACCOUNT_ID", "")
|
|
110
|
+
update_tag = common_job_parameters.get("UPDATE_TAG", 0)
|
|
111
|
+
|
|
112
|
+
if not api_url or not api_token or not account_id or not update_tag:
|
|
113
|
+
logger.error("Missing required parameters for SentinelOne CVE sync")
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
cves = get(api_url, api_token, account_id)
|
|
117
|
+
transformed_cves = transform(cves)
|
|
118
|
+
load_cves(neo4j_session, transformed_cves, account_id, update_tag)
|
|
119
|
+
cleanup(neo4j_session, common_job_parameters)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_application_id(name: str, vendor: str) -> str:
|
|
5
|
+
"""
|
|
6
|
+
Generate a normalized unique identifier for an application.
|
|
7
|
+
:param name: Application name
|
|
8
|
+
:param vendor: Application vendor/publisher
|
|
9
|
+
:return: Normalized unique identifier in format 'vendor:name'
|
|
10
|
+
"""
|
|
11
|
+
name_normalized = name.strip().lower().replace(" ", "_")
|
|
12
|
+
vendor_normalized = vendor.strip().lower().replace(" ", "_")
|
|
13
|
+
name_normalized = re.sub(r"[^\w]", "", name_normalized)
|
|
14
|
+
vendor_normalized = re.sub(r"[^\w]", "", vendor_normalized)
|
|
15
|
+
return f"{vendor_normalized}:{name_normalized}"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_application_version_id(name: str, vendor: str, version: str) -> str:
|
|
19
|
+
"""
|
|
20
|
+
Generate a unique identifier for an application version
|
|
21
|
+
:param name: Application name
|
|
22
|
+
:param vendor: Application vendor
|
|
23
|
+
:param version: Application version
|
|
24
|
+
:return: Unique identifier for the application version in format 'vendor:name:version'
|
|
25
|
+
"""
|
|
26
|
+
app_id = get_application_id(name, vendor)
|
|
27
|
+
version_normalized = version.strip().lower().replace(" ", "_")
|
|
28
|
+
return f"{app_id}:{version_normalized}"
|