diff --git a/.github/wordlist.txt b/.github/wordlist.txt index 31ac3e0d7..2d2a8d41d 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -1388,4 +1388,7 @@ Oke Okumo Moomaw Esha -Kumar \ No newline at end of file +Kumar +gansel +Ansel +zipp \ No newline at end of file diff --git a/AUTHORS.md b/AUTHORS.md index ac318d10e..8856402cf 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -99,7 +99,8 @@ This has been a critical element in the development of the FalconPy project. + `David-M-Berry` + Oke Okumo, `@okewoma` + Alexander Moomaw, `@alhumaw` -+ Esha Kumar, `@exk200006` ++ Esha Kumar, `@exk200006` ++ Griffin Ansel, `@gansel51` ## Sponsors diff --git a/CHANGELOG.md b/CHANGELOG.md index a8670ad42..c084ce2d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,55 @@ +# Version 1.4.5 +## Added features and functionality ++ Added: Added new __Host Migration__ service collection with 10 new operations. + - `__init__.py` + - `_endpoint/__init__.py` + - `_endpoint/_host_migration.py` + - `host_migration.py` + > Unit testing expanded to complete code coverage. + - `tests/test_host_migration.py` + ++ Added: Added new __Certificate Based Exclusions__ service collection with six new operations. + - `__init__.py` + - `_endpoint/__init__.py` + - `_endpoint/_certificate_based_exclusions.py` + - `_endpoint/deprecated/_certificate_based_exclusions.py` + - `_payload/__init__.py` + - `_payload/_certificate_based_exclusions.py` + - `certificate_based_exclusions.py` + > Unit testing expanded to complete code coverage. + - `tests/test_certificate_based_exclusions.py` + ++ Added: Added new __Compliance Assessments__ service collection with 11 new operations. + - `__init__.py` + - `_endpoint/__init__.py` + - `_endpoint/_compliance_assessments.py` + - `compliance_assessments.py` + > Unit testing expanded to complete code coverage. + - `tests/test_compliance_assessments.py` + +## Issues resolved ++ Fixed: Resolved comparison issue with version check helper method. + - `_version.py` + +## Other ++ Added: USGOV2 cloud region added to Base URL enumerator. + - `_enum/_base_url.py` + ++ Added: Automatic base URL detection from context objects when available. + - `_auth_object/_falcon_interface.py` + ++ Pinned: `setuptools` package pinned to version __70.3.0__ to avoid failures with new iterations of setuptools in Azure environments. + - `requirements.txt` + - `requirements-dev.txt` + - `setup.py` + - `dev-setup.py` + - Thanks go out to @gansel51 for identifying this issue and contributing a fix! 🙇 + ++ Pinned: `zipp` package pinned to version __3.19.1__ to avoid a potential vulnerability. + - `requirements-dev.txt` + +--- + # Version 1.4.4 ## Added features and functionality + Added: Added new __API Integrations__ service collection with two new operations, __GetCombinedPluginConfigs__ and __ExecuteCommand__. diff --git a/dev_setup.py b/dev_setup.py index ea082068b..048b03351 100644 --- a/dev_setup.py +++ b/dev_setup.py @@ -134,6 +134,7 @@ "pytest-cov", "pytest", "bandit", + "setuptools~=70.3.0" ], }, classifiers=[ diff --git a/requirements-dev.txt b/requirements-dev.txt index a73e96dbd..b9229d821 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -17,4 +17,5 @@ pytest-cov>=2.11.1 # via -r requirements-dev.in pytest>=6.2.2 # via -r requirements-dev.in ipython>=8.10.0 # via -r requirements-dev.in, pinned by Snyk to avoid SNYK-PYTHON-IPYTHON-3318382 pydocstyle>=6.1.0 -setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid SNYK-PYTHON-SETUPTOOLS-3113904 +setuptools~=70.3.0 # pinning to avoid failures with new iterations of setuptools +zipp>=3.19.1 # not directly required, pinned by Snyk diff --git a/requirements.txt b/requirements.txt index 565623229..bf51ad5ff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,4 @@ # pip-compile requirements.in # requests # via -r requirements.in -urllib3 # via -r requirements.in, requests - +urllib3 # via -r requirements.in, requests diff --git a/setup.py b/setup.py index 9881a4a5e..1d95cb9ad 100644 --- a/setup.py +++ b/setup.py @@ -91,6 +91,7 @@ "pytest-cov", "pytest", "bandit", + "setuptools~=70.3.0" ], }, classifiers=[ diff --git a/src/falconpy/__init__.py b/src/falconpy/__init__.py index 066336d0f..e0fe8febf 100644 --- a/src/falconpy/__init__.py +++ b/src/falconpy/__init__.py @@ -90,7 +90,9 @@ from .alerts import Alerts from .api_integrations import APIIntegrations from .api_complete import APIHarness, APIHarnessV2 +from .certificate_based_exclusions import CertificateBasedExclusions from .cloud_snapshots import CloudSnapshots +from .compliance_assessments import ComplianceAssessments from .configuration_assessment_evaluation_logic import ConfigurationAssessmentEvaluationLogic from .configuration_assessment import ConfigurationAssessment from .container_alerts import ContainerAlerts @@ -119,6 +121,7 @@ from .foundry_logscale import FoundryLogScale from .host_group import HostGroup from .hosts import Hosts +from .host_migration import HostMigration from .identity_protection import IdentityProtection from .image_assessment_policies import ImageAssessmentPolicies from .incidents import Incidents @@ -198,7 +201,8 @@ "SDKDeprecationWarning", "ConfigurationAssessmentEvaluationLogic", "ConfigurationAssessment", "ContainerAlerts", "ContainerDetections", "ContainerImages", "ContainerPackages", "ContainerVulnerabilities", "DriftIndicators", "UnidentifiedContainers", - "ImageAssessmentPolicies", "APIIntegrations", "ThreatGraph", "ExposureManagement" + "ImageAssessmentPolicies", "APIIntegrations", "ThreatGraph", "ExposureManagement", + "CertificateBasedExclusions", "ComplianceAssessments", "HostMigration" ] """ This is free and unencumbered software released into the public domain. diff --git a/src/falconpy/_auth_object/_falcon_interface.py b/src/falconpy/_auth_object/_falcon_interface.py index 8bc9e4ad1..edc5abb84 100644 --- a/src/falconpy/_auth_object/_falcon_interface.py +++ b/src/falconpy/_auth_object/_falcon_interface.py @@ -73,7 +73,7 @@ class FalconInterface(BaseFalconAuth): # The default constructor for all authentication objects. Ingests provided credentials # and sets the necessary class attributes based upon the authentication detail received. # pylint: disable=R0912,R0913,R0914 - def __init__(self, + def __init__(self, # noqa: C901 access_token: Optional[Union[str, bool]] = False, base_url: Optional[str] = "https://api.crowdstrike.com", creds: Optional[Dict[str, str]] = None, @@ -167,7 +167,8 @@ def __init__(self, if cvar.cs_cloud: self._config.base_url = confirm_base_url(cvar.cs_cloud) except AttributeError: - pass + if self.token_value: + self._config.base_url = confirm_base_url(os.getenv("CS_CLOUD", "auto")) self._auth_style = "CONTEXT" break except AttributeError: diff --git a/src/falconpy/_endpoint/__init__.py b/src/falconpy/_endpoint/__init__.py index 45dad8fee..765ef0fa8 100644 --- a/src/falconpy/_endpoint/__init__.py +++ b/src/falconpy/_endpoint/__init__.py @@ -36,13 +36,16 @@ from .deprecated import _report_executions_deprecated from .deprecated import _scheduled_reports_deprecated from .deprecated import _zero_trust_assessment_deprecated +from .deprecated import _certificate_based_exclusions_deprecated from .deprecated import _deprecated_operation_mapping from .deprecated import _deprecated_class_mapping from ._alerts import _alerts_endpoints from ._api_integrations import _api_integrations_endpoints +from ._certificate_based_exclusions import _certificate_based_exclusions_endpoints from ._cloud_connect_aws import _cloud_connect_aws_endpoints from ._cloud_snapshots import _cloud_snapshots_endpoints +from ._compliance_assessments import _complianceassessments_endpoints from ._configuration_assessment_evaluation_logic import _configuration_assessment_evaluation_logic_endpoints from ._configuration_assessment import _configuration_assessment_endpoints from ._container_alerts import _container_alerts_endpoints @@ -69,6 +72,7 @@ from ._foundry_logscale import _foundry_logscale_endpoints from ._host_group import _host_group_endpoints from ._hosts import _hosts_endpoints +from ._host_migration import _host_migration_endpoints from ._identity_protection import _identity_protection_endpoints from ._image_assessment_policies import _image_assessment_policies_endpoints from ._incidents import _incidents_endpoints @@ -112,8 +116,10 @@ api_endpoints: List[Any] = [] api_endpoints.extend(_alerts_endpoints) api_endpoints.extend(_api_integrations_endpoints) +api_endpoints.extend(_certificate_based_exclusions_endpoints) api_endpoints.extend(_cloud_connect_aws_endpoints) api_endpoints.extend(_cloud_snapshots_endpoints) +api_endpoints.extend(_complianceassessments_endpoints) api_endpoints.extend(_configuration_assessment_evaluation_logic_endpoints) api_endpoints.extend(_configuration_assessment_endpoints) api_endpoints.extend(_container_alerts_endpoints) @@ -140,6 +146,7 @@ api_endpoints.extend(_foundry_logscale_endpoints) api_endpoints.extend(_host_group_endpoints) api_endpoints.extend(_hosts_endpoints) +api_endpoints.extend(_host_migration_endpoints) api_endpoints.extend(_identity_protection_endpoints) api_endpoints.extend(_image_assessment_policies_endpoints) api_endpoints.extend(_incidents_endpoints) @@ -182,6 +189,7 @@ # Deprecated endpoints deprecated_endpoints = [] +deprecated_endpoints.extend(_certificate_based_exclusions_deprecated) deprecated_endpoints.extend(_custom_ioa_deprecated) deprecated_endpoints.extend(_d4c_registration_deprecated) deprecated_endpoints.extend(_discover_deprecated) diff --git a/src/falconpy/_endpoint/_certificate_based_exclusions.py b/src/falconpy/_endpoint/_certificate_based_exclusions.py new file mode 100644 index 000000000..81e03459d --- /dev/null +++ b/src/falconpy/_endpoint/_certificate_based_exclusions.py @@ -0,0 +1,171 @@ +"""Internal API endpoint constant library. + + _______ __ _______ __ __ __ +| _ .----.-----.--.--.--.--| | _ | |_.----|__| |--.-----. +|. 1___| _| _ | | | | _ | 1___| _| _| | <| -__| +|. |___|__| |_____|________|_____|____ |____|__| |__|__|__|_____| +|: 1 | |: 1 | +|::.. . | CROWDSTRIKE FALCON |::.. . | FalconPy +`-------' `-------' + +OAuth2 API - Customer SDK + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +""" + +_certificate_based_exclusions_endpoints = [ + [ + "cb_exclusions_get_v1", + "GET", + "/exclusions/entities/cert-based-exclusions/v1", + "Find all exclusion IDs matching the query with filter", + "certificate_based_exclusions", + [ + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "The ids of the exclusions to retrieve", + "name": "ids", + "in": "query", + "required": True + } + ] + ], + [ + "cb_exclusions_create_v1", + "POST", + "/exclusions/entities/cert-based-exclusions/v1", + "Create new Certificate Based Exclusions.", + "certificate_based_exclusions", + [ + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "cb_exclusions_update_v1", + "PATCH", + "/exclusions/entities/cert-based-exclusions/v1", + "Updates existing Certificate Based Exclusions", + "certificate_based_exclusions", + [ + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "cb_exclusions_delete_v1", + "DELETE", + "/exclusions/entities/cert-based-exclusions/v1", + "Delete the exclusions by id", + "certificate_based_exclusions", + [ + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "The ids of the exclusions to delete", + "name": "ids", + "in": "query", + "required": True + }, + { + "type": "string", + "description": "The comment why these exclusions were deleted", + "name": "comment", + "in": "query" + } + ] + ], + [ + "certificates_get_v1", + "GET", + "/exclusions/entities/certificates/v1", + "Retrieves certificate signing information for a file", + "certificate_based_exclusions", + [ + { + "type": "string", + "description": "The SHA256 Hash of the file to retrieve certificate signing info for", + "name": "ids", + "in": "query", + "required": True + } + ] + ], + [ + "cb_exclusions_query_v1", + "GET", + "/exclusions/queries/cert-based-exclusions/v1", + "Search for cert-based exclusions.", + "certificate_based_exclusions", + [ + { + "type": "string", + "description": "The filter expression that should be used to limit the results.", + "name": "filter", + "in": "query" + }, + { + "type": "integer", + "description": "The offset to start retrieving records from", + "name": "offset", + "in": "query" + }, + { + "maximum": 100, + "type": "integer", + "description": "The maximum records to return. [1-100]", + "name": "limit", + "in": "query" + }, + { + "enum": [ + "created_by", + "created_on", + "modified_by", + "modified_on", + "name" + ], + "type": "string", + "description": "The sort expression that should be used to sort the results.", + "name": "sort", + "in": "query" + } + ] + ] +] diff --git a/src/falconpy/_endpoint/_compliance_assessments.py b/src/falconpy/_endpoint/_compliance_assessments.py new file mode 100644 index 000000000..44a808255 --- /dev/null +++ b/src/falconpy/_endpoint/_compliance_assessments.py @@ -0,0 +1,299 @@ +"""Internal API endpoint constant library. + + _______ __ _______ __ __ __ +| _ .----.-----.--.--.--.--| | _ | |_.----|__| |--.-----. +|. 1___| _| _ | | | | _ | 1___| _| _| | <| -__| +|. |___|__| |_____|________|_____|____ |____|__| |__|__|__|_____| +|: 1 | |: 1 | +|::.. . | CROWDSTRIKE FALCON |::.. . | FalconPy +`-------' `-------' + +OAuth2 API - Customer SDK + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +""" + +_complianceassessments_endpoints = [ + [ + "extAggregateClusterAssessments", + "GET", + "/container-compliance/aggregates/compliance-by-clusters/v2", + "get the assessments for each cluster", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\ncloud_info.cluster_name: Kubernetes cluster name\ncloud_info.cloud_region: Cloud " + "region\ncompliance_finding.framework: Compliance finding framework (available values: " + "CIS)\ncloud_info.cloud_account_id: Cloud account ID\ncloud_info.namespace: Kubernetes namespace\ncid: Customer " + "ID\ncloud_info.cloud_provider: Cloud provider\n", + "name": "filter", + "in": "query" + } + ] + ], + [ + "extAggregateImageAssessments", + "GET", + "/container-compliance/aggregates/compliance-by-images/v2", + "get the assessments for each image", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\ncloud_info.cluster_name: Kubernetes cluster name\ncompliance_finding.id: Compliance finding " + "ID\nimage_digest: Image digest (sha256 digest)\nimage_registry: Image registry\nimage_tag: Image " + "tag\nimage_id: Image ID\ncloud_info.cloud_provider: Cloud provider\nasset_type: asset type (container, " + "image)\ncompliance_finding.severity: Compliance finding severity; available values: 4, 3, 2, 1 (4: critical, " + "3: high, 2: medium, 1:low)\ncompliance_finding.framework: Compliance finding framework (available values: " + "CIS)\nimage_repository: Image repository\ncloud_info.cloud_account_id: Cloud account ID\ncloud_info.namespace: " + " Kubernetes namespace\ncloud_info.cloud_region: Cloud region\ncompliance_finding.name: Compliance finding " + "Name\ncid: Customer ID\n", + "name": "filter", + "in": "query" + }, + { + "type": "string", + "description": "'after' value from the last response. Keep it empty for the first request.", + "name": "after", + "in": "query" + }, + { + "type": "string", + "description": "number of images to return in the response after 'after' key. Keep it empty for the " + "default number of 10000", + "name": "limit", + "in": "query" + } + ] + ], + [ + "extAggregateRulesAssessments", + "GET", + "/container-compliance/aggregates/compliance-by-rules/v2", + "get the assessments for each rule", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\nimage_registry: Image registry\nimage_repository: Image repository\ncompliance_finding.framework: " + "Compliance finding framework (available values: CIS)\ncloud_info.cloud_region: Cloud " + "region\ncloud_info.cloud_account_id: Cloud account ID\ncloud_info.cloud_provider: Cloud " + "provider\ncompliance_finding.id: Compliance finding ID\ncompliance_finding.severity: Compliance finding " + "severity; available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low)\ncloud_info.cluster_name: " + "Kubernetes cluster name\nimage_id: Image ID\nimage_tag: Image tag\ncompliance_finding.name: Compliance finding " + "Name\nimage_digest: Image digest (sha256 digest)\ncid: Customer ID\n", + "name": "filter", + "in": "query" + } + ] + ], + [ + "extAggregateFailedContainersByRulesPath", + "GET", + "/container-compliance/aggregates/failed-containers-by-rules/v2", + "get the containers grouped into rules on which they failed", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\ncloud_info.cloud_region: Cloud region\nimage_registry: Image registry\ncloud_info.cloud_account_id: " + "Cloud account ID\ncompliance_finding.name: Compliance finding Name\nimage_tag: Image " + "tag\ncloud_info.cluster_name: Kubernetes cluster name\ncompliance_finding.framework: Compliance finding " + "framework (available values: CIS)\ncloud_info.cloud_provider: Cloud provider\ncompliance_finding.id: " + "Compliance finding ID\ncompliance_finding.severity: Compliance finding severity; available values: 4, 3, 2, 1 " + "(4: critical, 3: high, 2: medium, 1:low)\ncid: Customer ID\nimage_id: Image ID\nimage_digest: Image digest " + "(sha256 digest)\ncloud_info.namespace: Kubernetes namespace\nimage_repository: Image repository\n", + "name": "filter", + "in": "query" + } + ] + ], + [ + "extAggregateFailedContainersCountBySeverity", + "GET", + "/container-compliance/aggregates/failed-containers-count-by-severity/v2", + "get the failed containers count grouped into severity levels", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\ncloud_info.namespace: Kubernetes namespace\ncloud_info.cloud_provider: Cloud " + "provider\ncompliance_finding.id: Compliance finding ID\nimage_registry: Image " + "registry\ncompliance_finding.name: Compliance finding Name\ncompliance_finding.severity: Compliance finding " + "severity; available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low)\ncloud_info.cluster_name: " + "Kubernetes cluster name\ncloud_info.cloud_account_id: Cloud account ID\nimage_id: Image ID\nimage_digest: " + "Image digest (sha256 digest)\nimage_repository: Image repository\nimage_tag: Image " + "tag\ncompliance_finding.framework: Compliance finding framework (available values: CIS)\ncid: Customer " + "ID\ncloud_info.cloud_region: Cloud region\n", + "name": "filter", + "in": "query" + } + ] + ], + [ + "extAggregateFailedImagesByRulesPath", + "GET", + "/container-compliance/aggregates/failed-images-by-rules/v2", + "get the images grouped into rules on which they failed", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\nimage_repository: Image repository\nimage_tag: Image tag\ncloud_info.cluster_name: Kubernetes " + "cluster name\ncloud_info.cloud_region: Cloud region\ncloud_info.cloud_account_id: Cloud account " + "ID\nimage_registry: Image registry\ncompliance_finding.name: Compliance finding " + "Name\ncompliance_finding.framework: Compliance finding framework (available values: " + "CIS)\ncloud_info.namespace: Kubernetes namespace\ncid: Customer ID\ncompliance_finding.severity: Compliance " + "finding severity; available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, " + "1:low)\ncloud_info.cloud_provider: Cloud provider\ncompliance_finding.id: Compliance finding ID\nimage_id: " + "Image ID\nimage_digest: Image digest (sha256 digest)\n", + "name": "filter", + "in": "query" + } + ] + ], + [ + "extAggregateFailedImagesCountBySeverity", + "GET", + "/container-compliance/aggregates/failed-images-count-by-severity/v2", + "get the failed images count grouped into severity levels", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\nimage_tag: Image tag\ncompliance_finding.name: Compliance finding Name\ncompliance_finding.severity: " + " Compliance finding severity; available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, " + "1:low)\ncloud_info.cloud_account_id: Cloud account ID\nimage_digest: Image digest (sha256 " + "digest)\nimage_registry: Image registry\nimage_id: Image ID\ncloud_info.namespace: Kubernetes " + "namespace\ncompliance_finding.framework: Compliance finding framework (available values: " + "CIS)\nimage_repository: Image repository\ncloud_info.cloud_provider: Cloud provider\ncid: Customer " + "ID\ncloud_info.cloud_region: Cloud region\ncloud_info.cluster_name: Kubernetes cluster " + "name\ncompliance_finding.id: Compliance finding ID\n", + "name": "filter", + "in": "query" + } + ] + ], + [ + "extAggregateFailedRulesByClusters", + "GET", + "/container-compliance/aggregates/failed-rules-by-clusters/v2", + "get the failed rules for each cluster grouped into severity levels", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\ncompliance_finding.name: Compliance finding Name\nimage_digest: Image digest (sha256 " + "digest)\nimage_tag: Image tag\ncloud_info.cloud_account_id: Cloud account ID\nimage_id: Image " + "ID\nimage_registry: Image registry\ncloud_info.cloud_region: Cloud region\nasset_type: asset type (container, " + "image)\ncompliance_finding.severity: Compliance finding severity; available values: 4, 3, 2, 1 (4: critical, " + "3: high, 2: medium, 1:low)\ncid: Customer ID\ncompliance_finding.id: Compliance finding " + "ID\ncompliance_finding.framework: Compliance finding framework (available values: " + "CIS)\ncloud_info.cluster_name: Kubernetes cluster name\nimage_repository: Image " + "repository\ncloud_info.cloud_provider: Cloud provider\n", + "name": "filter", + "in": "query" + } + ] + ], + [ + "extAggregateFailedRulesByImages", + "GET", + "/container-compliance/aggregates/failed-rules-by-images/v2", + "get images with failed rules, rule count grouped by severity for each image", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\ncompliance_finding.id: Compliance finding ID\nimage_tag: Image tag\ncloud_info.cluster_name: " + "Kubernetes cluster name\nimage_registry: Image registry\ncloud_info.cloud_provider: Cloud " + "provider\ncompliance_finding.name: Compliance finding Name\ncid: Customer ID\ncloud_info.cloud_region: Cloud " + "region\ncloud_info.cloud_account_id: Cloud account ID\nasset_type: asset type (container, " + "image)\ncompliance_finding.severity: Compliance finding severity; available values: 4, 3, 2, 1 (4: critical, " + "3: high, 2: medium, 1:low)\nimage_id: Image ID\nimage_digest: Image digest (sha256 " + "digest)\ncompliance_finding.framework: Compliance finding framework (available values: CIS)\nimage_repository: " + "Image repository\ncloud_info.namespace: Kubernetes namespace\n", + "name": "filter", + "in": "query" + } + ] + ], + [ + "extAggregateFailedRulesCountBySeverity", + "GET", + "/container-compliance/aggregates/failed-rules-count-by-severity/v2", + "get the failed rules count grouped into severity levels", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported Filters:\ncid: " + "Customer ID\ncloud_info.cloud_region: Cloud region\ncompliance_finding.id: Compliance finding ID\nimage_id: " + "Image ID\nimage_tag: Image tag\nimage_digest: Image digest (sha256 digest)\ncompliance_finding.framework: " + "Compliance finding framework (available values: CIS)\nimage_repository: Image " + "repository\ncloud_info.cloud_account_id: Cloud account ID\ncompliance_finding.severity: Compliance finding " + "severity; available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low)\nasset_type: asset type " + "(container, image)\ncloud_info.cluster_name: Kubernetes cluster name\ncloud_info.cloud_provider: Cloud " + "provider\nimage_registry: Image registry\ncompliance_finding.name: Compliance finding Name\n", + "name": "filter", + "in": "query" + } + ] + ], + [ + "extAggregateRulesByStatus", + "GET", + "/container-compliance/aggregates/rules-by-status/v2", + "get the rules grouped by their statuses", + "complianceassessments", + [ + { + "type": "string", + "description": "Filter results using a query in Falcon Query Language (FQL). Supported " + "Filters:\ncompliance_finding.id: Compliance finding ID\nimage_tag: Image tag\ncompliance_finding.name: " + "Compliance finding Name\nasset_type: asset type (container, image)\ncompliance_finding.severity: Compliance " + "finding severity; available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low)\ncid: Customer " + "ID\ncontainer_name: Container name\ncloud_info.cluster_name: Kubernetes cluster name\nimage_repository: Image " + "repository\ncloud_info.cloud_provider: Cloud provider\nimage_registry: Image " + "registry\ncompliance_finding.framework: Compliance finding framework (available values: " + "CIS)\ncloud_info.cloud_region: Cloud region\ncloud_info.cloud_account_id: Cloud account ID\nimage_id: Image " + "ID\nimage_digest: Image digest (sha256 digest)\ncontainer_id: Container ID\n", + "name": "filter", + "in": "query" + } + ] + ] +] diff --git a/src/falconpy/_endpoint/_host_migration.py b/src/falconpy/_endpoint/_host_migration.py new file mode 100644 index 000000000..7e9de151e --- /dev/null +++ b/src/falconpy/_endpoint/_host_migration.py @@ -0,0 +1,327 @@ +"""Internal API endpoint constant library. + + _______ __ _______ __ __ __ +| _ .----.-----.--.--.--.--| | _ | |_.----|__| |--.-----. +|. 1___| _| _ | | | | _ | 1___| _| _| | <| -__| +|. |___|__| |_____|________|_____|____ |____|__| |__|__|__|_____| +|: 1 | |: 1 | +|::.. . | CROWDSTRIKE FALCON |::.. . | FalconPy +`-------' `-------' + +OAuth2 API - Customer SDK + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +""" + +_host_migration_endpoints = [ + [ + "HostMigrationAggregatesV1", + "POST", + "/host-migration/aggregates/host-migrations/v1", + "Get host migration aggregates as specified via json in request body.", + "host_migration", + [ + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "MigrationAggregatesV1", + "POST", + "/host-migration/aggregates/migrations/v1", + "Get migration aggregates as specified via json in request body.", + "host_migration", + [ + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "HostMigrationsActionsV1", + "POST", + "/host-migration/entities/host-migrations-actions/v1", + "Perform an action on host migrations.", + "host_migration", + [ + { + "type": "string", + "description": "The migration job to perform actions on", + "name": "id", + "in": "query", + "required": True + }, + { + "enum": [ + "remove_hosts", + "remove_host_groups", + "add_host_groups" + ], + "type": "string", + "description": "The action to perform", + "name": "action_name", + "in": "query", + "required": True + }, + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "GetHostMigrationsV1", + "POST", + "/host-migration/entities/host-migrations/GET/v1", + "Get host migration details.", + "host_migration", + [ + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "GetMigrationDestinationsV1", + "POST", + "/host-migration/entities/migration-destinations/GET/v1", + "Get destinations for a migration.", + "host_migration", + [ + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "MigrationsActionsV1", + "POST", + "/host-migration/entities/migrations-actions/v1", + "Perform an action on a migration job.", + "host_migration", + [ + { + "enum": [ + "delete_migration", + "rename_migration", + "start_migration", + "cancel_migration" + ], + "type": "string", + "description": "The action to perform", + "name": "action_name", + "in": "query", + "required": True + }, + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "GetMigrationsV1", + "GET", + "/host-migration/entities/migrations/v1", + "Get migration job details.", + "host_migration", + [ + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "The migration jobs of interest.", + "name": "ids", + "in": "query", + "required": True + } + ] + ], + [ + "CreateMigrationV1", + "POST", + "/host-migration/entities/migrations/v1", + "Create a device migration job.", + "host_migration", + [ + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "GetHostMigrationIDsV1", + "GET", + "/host-migration/queries/host-migrations/v1", + "Query host migration IDs.", + "host_migration", + [ + { + "type": "string", + "description": "The migration job to query", + "name": "id", + "in": "query", + "required": True + }, + { + "type": "integer", + "description": "The offset to start retrieving records from", + "name": "offset", + "in": "query" + }, + { + "type": "integer", + "description": "The maximum records to return. [1-10000]", + "name": "limit", + "in": "query" + }, + { + "enum": [ + "hostname|asc", + "hostname|desc", + "hostname", + "status|asc", + "status|desc", + "status", + "migration_id|asc", + "migration_id|desc", + "migration_id", + "created_time|asc", + "created_time|desc", + "created_time", + "host_migration_id|asc", + "host_migration_id|desc", + "host_migration_id", + "groups|asc", + "groups|desc", + "groups", + "hostgroups|asc", + "hostgroups|desc", + "hostgroups", + "source_cid|asc", + "source_cid|desc", + "source_cid", + "id|asc", + "id|desc", + "id", + "static_host_groups|asc", + "static_host_groups|desc", + "static_host_groups", + "target_cid|asc", + "target_cid|desc", + "target_cid" + ], + "type": "string", + "description": "The property to sort by.", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "description": "The filter expression that should be used to limit the results. Valid fields: " + "host_migration_id, groups, hostgroups, hostname, status, migration_id, created_time, static_host_groups, " + "target_cid, source_cid, id", + "name": "filter", + "in": "query" + } + ] + ], + [ + "GetMigrationIDsV1", + "GET", + "/host-migration/queries/migrations/v1", + "Query migration jobs.", + "host_migration", + [ + { + "type": "integer", + "description": "The offset to start retrieving records from", + "name": "offset", + "in": "query" + }, + { + "type": "integer", + "description": "The maximum records to return. [1-10000]", + "name": "limit", + "in": "query" + }, + { + "enum": [ + "target_cid|asc", + "target_cid|desc", + "target_cid", + "status|asc", + "status|desc", + "status", + "migration_status|asc", + "migration_status|desc", + "migration_status", + "created_by|asc", + "created_by|desc", + "created_by", + "created_time|asc", + "created_time|desc", + "created_time", + "name|asc", + "name|desc", + "name", + "id|asc", + "id|desc", + "id", + "migration_id|asc", + "migration_id|desc", + "migration_id" + ], + "type": "string", + "description": "The property to sort by.", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "description": "The filter expression that should be used to limit the results. Valid fields: " + "target_cid, status, migration_status, created_by, created_time, name, id, migration_id", + "name": "filter", + "in": "query" + } + ] + ] +] diff --git a/src/falconpy/_endpoint/deprecated/__init__.py b/src/falconpy/_endpoint/deprecated/__init__.py index 82d7c9bf7..5bd72ac17 100644 --- a/src/falconpy/_endpoint/deprecated/__init__.py +++ b/src/falconpy/_endpoint/deprecated/__init__.py @@ -49,6 +49,7 @@ from ._scheduled_reports import _scheduled_reports_endpoints from ._zero_trust_assessment import _zero_trust_assessment_endpoints from ._mapping import _deprecated_op_mapping, _deprecated_cls_mapping +from ._certificate_based_exclusions import _certificate_based_exclusions_endpoints _custom_ioa_deprecated = _custom_ioa_endpoints _d4c_registration_deprecated = _d4c_registration_endpoints @@ -67,5 +68,6 @@ _report_executions_deprecated = _report_executions_endpoints _scheduled_reports_deprecated = _scheduled_reports_endpoints _zero_trust_assessment_deprecated = _zero_trust_assessment_endpoints +_certificate_based_exclusions_deprecated = _certificate_based_exclusions_endpoints _deprecated_operation_mapping = _deprecated_op_mapping _deprecated_class_mapping = _deprecated_cls_mapping diff --git a/src/falconpy/_endpoint/deprecated/_certificate_based_exclusions.py b/src/falconpy/_endpoint/deprecated/_certificate_based_exclusions.py new file mode 100644 index 000000000..b32a10a31 --- /dev/null +++ b/src/falconpy/_endpoint/deprecated/_certificate_based_exclusions.py @@ -0,0 +1,171 @@ +"""Internal API endpoint constant library (deprecated operations). + + _______ __ _______ __ __ __ +| _ .----.-----.--.--.--.--| | _ | |_.----|__| |--.-----. +|. 1___| _| _ | | | | _ | 1___| _| _| | <| -__| +|. |___|__| |_____|________|_____|____ |____|__| |__|__|__|_____| +|: 1 | |: 1 | +|::.. . | CROWDSTRIKE FALCON |::.. . | FalconPy +`-------' `-------' + +OAuth2 API - Customer SDK + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +""" + +_certificate_based_exclusions_endpoints = [ + [ + "cb-exclusions.get.v1", + "GET", + "/exclusions/entities/cert-based-exclusions/v1", + "Find all exclusion IDs matching the query with filter", + "certificate_based_exclusions", + [ + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "The ids of the exclusions to retrieve", + "name": "ids", + "in": "query", + "required": True + } + ] + ], + [ + "cb-exclusions.create.v1", + "POST", + "/exclusions/entities/cert-based-exclusions/v1", + "Create new Certificate Based Exclusions.", + "certificate_based_exclusions", + [ + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "cb-exclusions.update.v1", + "PATCH", + "/exclusions/entities/cert-based-exclusions/v1", + "Updates existing Certificate Based Exclusions", + "certificate_based_exclusions", + [ + { + "name": "body", + "in": "body", + "required": True + } + ] + ], + [ + "cb-exclusions.delete.v1", + "DELETE", + "/exclusions/entities/cert-based-exclusions/v1", + "Delete the exclusions by id", + "certificate_based_exclusions", + [ + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "The ids of the exclusions to delete", + "name": "ids", + "in": "query", + "required": True + }, + { + "type": "string", + "description": "The comment why these exclusions were deleted", + "name": "comment", + "in": "query" + } + ] + ], + [ + "certificates.get.v1", + "GET", + "/exclusions/entities/certificates/v1", + "Retrieves certificate signing information for a file", + "certificate_based_exclusions", + [ + { + "type": "string", + "description": "The SHA256 Hash of the file to retrieve certificate signing info for", + "name": "ids", + "in": "query", + "required": True + } + ] + ], + [ + "cb-exclusions.query.v1", + "GET", + "/exclusions/queries/cert-based-exclusions/v1", + "Search for cert-based exclusions.", + "certificate_based_exclusions", + [ + { + "type": "string", + "description": "The filter expression that should be used to limit the results.", + "name": "filter", + "in": "query" + }, + { + "type": "integer", + "description": "The offset to start retrieving records from", + "name": "offset", + "in": "query" + }, + { + "maximum": 100, + "type": "integer", + "description": "The maximum records to return. [1-100]", + "name": "limit", + "in": "query" + }, + { + "enum": [ + "created_by", + "created_on", + "modified_by", + "modified_on", + "name" + ], + "type": "string", + "description": "The sort expression that should be used to sort the results.", + "name": "sort", + "in": "query" + } + ] + ] +] diff --git a/src/falconpy/_enum/_base_url.py b/src/falconpy/_enum/_base_url.py index eb2690caf..c5fcd3317 100644 --- a/src/falconpy/_enum/_base_url.py +++ b/src/falconpy/_enum/_base_url.py @@ -50,4 +50,5 @@ class BaseURL(Enum): US2 = "api.us-2.crowdstrike.com" EU1 = "api.eu-1.crowdstrike.com" USGOV1 = "api.laggar.gcw.crowdstrike.com" + USGOV2 = "api.us-gov-2.crowdstrike.mil" AUTO = "api.crowdstrike.com" diff --git a/src/falconpy/_payload/__init__.py b/src/falconpy/_payload/__init__.py index 6ec88e10f..0f7510c03 100644 --- a/src/falconpy/_payload/__init__.py +++ b/src/falconpy/_payload/__init__.py @@ -53,6 +53,7 @@ from ._sensor_update_policy import sensor_policy_payload from ._response_policy import response_policy_payload from ._real_time_response import command_payload, data_payload +from ._certificate_based_exclusions import certificate_based_exclusions_payload from ._cloud_connect_aws import aws_registration_payload from ._ioc import indicator_payload, indicator_update_payload, indicator_report_payload from ._d4c_registration import ( @@ -130,5 +131,5 @@ "image_policy_payload", "image_exclusions_payload", "image_group_payload", "workflow_definition_payload", "workflow_human_input", "workflow_mock_payload", "cspm_service_account_validate_payload", "api_plugin_command_payload", "mobile_enrollment_payload", - "filevantage_start_payload", "fem_asset_payload" + "filevantage_start_payload", "fem_asset_payload", "certificate_based_exclusions_payload", ] diff --git a/src/falconpy/_payload/_certificate_based_exclusions.py b/src/falconpy/_payload/_certificate_based_exclusions.py new file mode 100644 index 000000000..29a1c0689 --- /dev/null +++ b/src/falconpy/_payload/_certificate_based_exclusions.py @@ -0,0 +1,104 @@ +"""Internal payload handling library - Certificate Based Exclusions. + + _______ __ _______ __ __ __ +| _ .----.-----.--.--.--.--| | _ | |_.----|__| |--.-----. +|. 1___| _| _ | | | | _ | 1___| _| _| | <| -__| +|. |___|__| |_____|________|_____|____ |____|__| |__|__|__|_____| +|: 1 | |: 1 | +|::.. . | CROWDSTRIKE FALCON |::.. . | FalconPy +`-------' `-------' + +OAuth2 API - Customer SDK + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +""" + +from typing import Dict, List, Union + + +def certificate_based_exclusions_payload(passed_keywords: dict) -> Dict[str, List[Dict[str, Union[str, int]]]]: + """Create a properly formatted payload for exclusion creation. + + { + "resources": [ + { + "applied_globally": true, + "certificate": { + "issuer": "string", + "serial": "string", + "subject": "string", + "thumbprint": "string", + "valid_from": "2024-07-17T16:55:01.502Z", + "valid_to": "2024-07-17T16:55:01.502Z" + }, + "children_cids": [ + "string" + ], + "comment": "string", + "created_by": "string", + "created_on": "2024-07-17T16:55:01.502Z", + "description": "string", + "host_groups": [ + "string" + ], + "modified_by": "string", + "modified_on": "2024-07-17T16:55:01.502Z", + "name": "string", + "status": "string" + } + ] + } + """ + returned = { + "resources": [] + } + item = {} + keys = [ + "applied_globally", "certificate", "comment", "created_by", "created_on", + "description", "modified_by", "modified_on", "name", "status", + ] + certificate_keys = [ + "issuer", "serial", "subject", "thumbprint", "valid_from", "valid_to" + ] + list_keys = ["children_cids", "host_groups"] + for key in keys: + if passed_keywords.get(key, None): + if key == "certificate": + item["certificate"] = {} + for cert_key in certificate_keys: + item["certificate"][cert_key] = passed_keywords.get(cert_key, None) + else: + item[key] = passed_keywords.get(key, None) + for key in list_keys: + if passed_keywords.get(key, None): + provided = passed_keywords.get(key, None) + if isinstance(provided, str): + provided = provided.split(",") + item[key] = provided + + returned["resources"].append(item) + + return returned diff --git a/src/falconpy/_version.py b/src/falconpy/_version.py index 802144761..368f156ef 100644 --- a/src/falconpy/_version.py +++ b/src/falconpy/_version.py @@ -35,7 +35,7 @@ For more information, please refer to """ -_VERSION = '1.4.4' +_VERSION = '1.4.5' _MAINTAINER = 'Joshua Hiller' _AUTHOR = 'CrowdStrike' _AUTHOR_EMAIL = 'falconpy@crowdstrike.com' @@ -71,7 +71,6 @@ def version(compare: str = None, agent_string: bool = None): returned = f"{_TITLE}/{str(_VERSION)}" else: ver = _VERSION.split(".") - major_minor = float(f"{ver[0]}.{ver[1]}") if isinstance(compare, str): compare = compare.strip() elif isinstance(compare, (int, float)): @@ -79,22 +78,19 @@ def version(compare: str = None, agent_string: bool = None): if compare: returned = False chk = compare.split(".") - chk_major = 0 - chk_minor = 0 - chk_patch = 0 - if chk: - chk_major = chk[0] - if len(chk) > 1: - chk_minor = chk[1] - if len(chk) > 2: - chk_patch = int(chk[2]) try: - chk_major_minor = float(f"{chk_major}.{chk_minor}") + chk_major = int(chk[0]) if chk else 0 + chk_minor = int(chk[1]) if len(chk) > 1 else 0 + chk_patch = int(chk[2]) if len(chk) > 2 else 0 except ValueError as bad_value: raise ValueError("Invalid version comparison value specified") from bad_value - if major_minor > chk_major_minor: - returned = True - elif major_minor == chk_major_minor and int(ver[2]) >= chk_patch: + if int(ver[0]) > chk_major: returned = True + elif int(ver[0]) == chk_major: + if int(ver[1]) > chk_minor: + returned = True + elif int(ver[1]) == chk_minor: + if int(ver[2]) >= chk_patch: + returned = True return returned diff --git a/src/falconpy/certificate_based_exclusions.py b/src/falconpy/certificate_based_exclusions.py new file mode 100644 index 000000000..baa0f9324 --- /dev/null +++ b/src/falconpy/certificate_based_exclusions.py @@ -0,0 +1,282 @@ +"""CrowdStrike Falcon Certificate Based Exclusions API interface class. + + _______ __ _______ __ __ __ +| _ .----.-----.--.--.--.--| | _ | |_.----|__| |--.-----. +|. 1___| _| _ | | | | _ | 1___| _| _| | <| -__| +|. |___|__| |_____|________|_____|____ |____|__| |__|__|__|_____| +|: 1 | |: 1 | +|::.. . | CROWDSTRIKE FALCON |::.. . | FalconPy +`-------' `-------' + +OAuth2 API - Customer SDK + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +""" + +from typing import Dict, Union +from ._util import force_default, process_service_request, handle_single_argument +from ._service_class import ServiceClass +from ._payload import certificate_based_exclusions_payload +from ._endpoint._certificate_based_exclusions import _certificate_based_exclusions_endpoints as Endpoints + + +class CertificateBasedExclusions(ServiceClass): + """The only requirement to instantiate an instance of this class is one of the following. + + - a valid client_id and client_secret provided as keywords. + - a credential dictionary with client_id and client_secret containing valid API credentials + { + "client_id": "CLIENT_ID_HERE", + "client_secret": "CLIENT_SECRET_HERE" + } + - a previously-authenticated instance of the authentication service class (oauth2.py) + - a valid token provided by the authentication service class (oauth2.py) + """ + + @force_default(defaults=["parameters"], default_types=["dict"]) + def get_exclusions(self: object, *args, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Find all exclusion IDs matching the query with filter. + + Keyword arguments: + ids -- One or more exclusion IDs . String or list of strings. + parameters - full parameters payload, not required if ids is provided as a keyword. + + Arguments: When not specified, the first argument to this method is assumed to be 'ids'. + All others are ignored. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/certificate-based-exclusions/cb-exclusions.get.v1 + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="cb_exclusions_get_v1", + keywords=kwargs, + params=handle_single_argument(args, parameters, "ids") + ) + + @force_default(defaults=["body"], default_types=["dict"]) + def create_exclusions(self: object, body: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Create new Certificate Based Exclusions. + + Keyword arguments: + body -- full body payload, not required if using other keywords. + { + "resources": [ + { + "applied_globally": true, + "certificate": { + "issuer": "string", + "serial": "string", + "subject": "string", + "thumbprint": "string", + "valid_from": "2024-07-17T16:55:01.502Z", + "valid_to": "2024-07-17T16:55:01.502Z" + }, + "children_cids": [ + "string" + ], + "comment": "string", + "created_by": "string", + "created_on": "2024-07-17T16:55:01.502Z", + "description": "string", + "host_groups": [ + "string" + ], + "modified_by": "string", + "modified_on": "2024-07-17T16:55:01.502Z", + "name": "string", + "status": "string" + } + ] + } + + Returns: dict object containing API response. + + HTTP Method: POST + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/certificate-based-exclusions/cb-exclusions.create.v1 + """ + if not body: + body = certificate_based_exclusions_payload(passed_keywords=kwargs) + + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="cb_exclusions_create_v1", + body=body, + keywords=kwargs + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def delete_exclusions(self: object, *args, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Delete a set of exclusions by specifying their IDs. + + Keyword arguments: + ids -- List of exclusion IDs to delete. String or list of strings. + parameters -- full parameters payload, not required if ids is provided as a keyword. + comment - The comment why these exclusions were deleted. String. + + Arguments: When not specified, the first argument to this method is assumed to be 'ids'. + All others are ignored. + + Returns: dict object containing API response. + + HTTP Method: DELETE + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/certificate-based-exclusions/cb-exclusions.delete.v1 + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="cb_exclusions_delete_v1", + keywords=kwargs, + params=handle_single_argument(args, parameters, "ids") + ) + + @force_default(defaults=["body"], default_types=["dict"]) + def update_exclusions(self: object, body: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Update Certificate Based Exclusions. + + Keyword arguments: + body -- full body payload, not required if using other keywords. + { + "resources": [ + { + "applied_globally": true, + "certificate": { + "issuer": "string", + "serial": "string", + "subject": "string", + "thumbprint": "string", + "valid_from": "2024-07-17T16:55:01.502Z", + "valid_to": "2024-07-17T16:55:01.502Z" + }, + "children_cids": [ + "string" + ], + "comment": "string", + "created_by": "string", + "created_on": "2024-07-17T16:55:01.502Z", + "description": "string", + "host_groups": [ + "string" + ], + "modified_by": "string", + "modified_on": "2024-07-17T16:55:01.502Z", + "name": "string", + "status": "string" + } + ] + } + + Returns: dict object containing API response. + + HTTP Method: PATCH + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/certificate-based-exclusions/cb-exclusions.update.v1 + """ + if not body: + body = certificate_based_exclusions_payload(passed_keywords=kwargs) + + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="cb_exclusions_update_v1", + body=body + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def get_certificates(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Retrieve vulnerability and package related info for this customer. + + Keyword arguments: + ids - The SHA256 Hash of the file to retrieve certificate signing info for. String. + parameters -- Full parameters payload dictionary. Not required if using other keywords. + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/certificate-based-exclusions/certificates.get.v1 + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="certificates_get_v1", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def query_certificates(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Search for cert-based exclusions. + + Keyword arguments: + filter -- The filter expression that should be used to limit the results. FQL syntax. + limit -- The maximum records to return. [1-500]. Defaults to 100. + Use with the offset parameter to manage pagination of results. + offset -- The offset to start retrieving records from. Integer. + Use with the limit parameter to manage pagination of results. + parameters - full parameters payload, not required if using other keywords. + sort -- The property to sort by (e.g. alias.desc or state.asc). FQL syntax. + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/certificate-based-exclusions/cb-exclusions.query.v1 + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="cb_exclusions_query_v1", + keywords=kwargs, + params=parameters + ) + + # These method names align to the operation IDs in the API but + # do not conform to snake_case / PEP8 and are defined here for + # backwards compatibility / ease of use purposes + cb_exclusions_get_v1 = get_exclusions + cb_exclusions_create_v1 = create_exclusions + cb_exclusions_delete_v1 = delete_exclusions + cb_exclusions_update_v1 = update_exclusions + certificates_get_v1 = get_certificates + cb_exclusions_query_v1 = query_certificates diff --git a/src/falconpy/compliance_assessments.py b/src/falconpy/compliance_assessments.py new file mode 100644 index 000000000..2cf00d3c7 --- /dev/null +++ b/src/falconpy/compliance_assessments.py @@ -0,0 +1,511 @@ +"""CrowdStrike Falcon Certificate Based Exclusions API interface class. + + _______ __ _______ __ __ __ +| _ .----.-----.--.--.--.--| | _ | |_.----|__| |--.-----. +|. 1___| _| _ | | | | _ | 1___| _| _| | <| -__| +|. |___|__| |_____|________|_____|____ |____|__| |__|__|__|_____| +|: 1 | |: 1 | +|::.. . | CROWDSTRIKE FALCON |::.. . | FalconPy +`-------' `-------' + +OAuth2 API - Customer SDK + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +""" + +from typing import Dict, Union +from ._util import force_default, process_service_request +from ._service_class import ServiceClass +from ._endpoint._compliance_assessments import _complianceassessments_endpoints as Endpoints + + +class ComplianceAssessments(ServiceClass): + """The only requirement to instantiate an instance of this class is one of the following. + + - a valid client_id and client_secret provided as keywords. + - a credential dictionary with client_id and client_secret containing valid API credentials + { + "client_id": "CLIENT_ID_HERE", + "client_secret": "CLIENT_SECRET_HERE" + } + - a previously-authenticated instance of the authentication service class (oauth2.py) + - a valid token provided by the authentication service class (oauth2.py) + """ + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_cluster_assessments(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the assessments for each cluster. + + Keyword arguments: + filter -- Filter results using a query in Falcon Query Language (FQL). String. + Supported filters: + cloud_info.cluster_name: Kubernetes cluster name, + cloud_info.cloud_region: Cloud region, + compliance_finding.framework: Compliance finding framework (available values: CIS), + cloud_info.cloud_account_id: Cloud account ID, + cloud_info.namespace: Kubernetes namespace, + cid: Customer ID cloud_info.cloud_provider: Cloud provider + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateClusterAssessments + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateClusterAssessments", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_image_assessments(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the assessments for each cluster. + + Keyword arguments: + filter -- Filter results using a query in Falcon Query Language (FQL). String. + Supported filters: + cloud_info.cluster_name: Kubernetes cluster name + compliance_finding.id: Compliance finding ID + image_digest: Image digest (sha256 digest) + image_registry: Image registry + image_tag: Image tag + image_id: Image ID + cloud_info.cloud_provider: Cloud provider + asset_type: asset type (container image) + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + compliance_finding.framework: Compliance finding framework (available values: CIS) + image_repository: Image repository + cloud_info.cloud_account_id: Cloud account ID + cloud_info.namespace: Kubernetes namespace + cloud_info.cloud_region: Cloud region + compliance_finding.name: Compliance finding Name + cid: Customer ID + after -- 'after' value from the last response. Keep it empty for the first request. String. + limit -- number of images to return in the response after 'after' key. + Keep it empty for the default number of 10000. String. + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateImageAssessments + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateImageAssessments", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_rules_assessments(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the assessments for each rule. + + Keyword arguments: + filter -- "Filter results using a query in Falcon Query Language (FQL). Supported Filters: + image_registry: Image registry + image_repository: Image repository + compliance_finding.framework: Compliance finding framework (available values: CIS) + cloud_info.cloud_region: Cloud region + cloud_info.cloud_account_id: Cloud account ID + cloud_info.cloud_provider: Cloud provider + compliance_finding.id: Compliance finding ID + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + cloud_info.cluster_name: Kubernetes cluster name + image_id: Image ID + image_tag: Image tag + compliance_finding.name: Compliance finding Name + image_digest: Image digest (sha256 digest) + cid: Customer ID + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateRulesAssessments + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateRulesAssessments", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_failed_containers_by_rules(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the containers grouped into rules on which they failed. + + Keyword arguments: + filter -- "Filter results using a query in Falcon Query Language (FQL). Supported Filters: + cloud_info.cloud_region: Cloud region + image_registry: Image registry + cloud_info.cloud_account_id: Cloud account ID + compliance_finding.name: Compliance finding Name + image_tag: Image tag + cloud_info.cluster_name: Kubernetes cluster name + compliance_finding.framework: Compliance finding framework (available values: CIS) + cloud_info.cloud_provider: Cloud provider + compliance_finding.id: Compliance finding ID + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + cid: Customer ID + image_id: Image ID + image_digest: Image digest (sha256 digest) + cloud_info.namespace: Kubernetes namespace + image_repository: Image repository + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateFailedContainersByRulesPath + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateFailedContainersByRulesPath", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_failed_containers_count_by_severity(self: object, + parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the failed containers count grouped into severity levels. + + Keyword arguments: + filter -- "Filter results using a query in Falcon Query Language (FQL). Supported Filters: + cloud_info.namespace: Kubernetes namespace + cloud_info.cloud_provider: Cloud provider + compliance_finding.id: Compliance finding ID + image_registry: Image registry + compliance_finding.name: Compliance finding Name + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + cloud_info.cluster_name: Kubernetes cluster name + cloud_info.cloud_account_id: Cloud account ID + image_id: Image ID + image_digest: Image digest (sha256 digest) + image_repository: Image repository + image_tag: Image tag + compliance_finding.framework: Compliance finding framework (available values: CIS) + cid: Customer ID + cloud_info.cloud_region: Cloud region + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateFailedContainersCountBySeverity + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateFailedContainersCountBySeverity", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_failed_images_by_rules(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the images grouped into rules on which they failed. + + Keyword arguments: + filter -- "Filter results using a query in Falcon Query Language (FQL). Supported Filters: + image_repository: Image repository + image_tag: Image tag + cloud_info.cluster_name: Kubernetes cluster name + cloud_info.cloud_region: Cloud region + cloud_info.cloud_account_id: Cloud account ID + image_registry: Image registry + compliance_finding.name: Compliance finding Name + compliance_finding.framework: Compliance finding framework (available values: CIS) + cloud_info.namespace: Kubernetes namespace + cid: Customer ID + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + cloud_info.cloud_provider: Cloud provider + compliance_finding.id: Compliance finding ID + image_id: Image ID + image_digest: Image digest (sha256 digest) + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateFailedImagesByRulesPath + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateFailedImagesByRulesPath", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_failed_images_count_by_severity(self: object, + parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the failed images count grouped into severity levels. + + Keyword arguments: + filter -- "Filter results using a query in Falcon Query Language (FQL). Supported Filters: + image_tag: Image tag + compliance_finding.name: Compliance finding Name + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + cloud_info.cloud_account_id: Cloud account ID + image_digest: Image digest (sha256 digest) + image_registry: Image registry + image_id: Image ID + cloud_info.namespace: Kubernetes namespace + compliance_finding.framework: Compliance finding framework (available values: CIS) + image_repository: Image repository + cloud_info.cloud_provider: Cloud provider + cid: Customer ID + cloud_info.cloud_region: Cloud region + cloud_info.cluster_name: Kubernetes cluster name + compliance_finding.id: Compliance finding ID + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateFailedImagesCountBySeverity + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateFailedImagesCountBySeverity", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_failed_rules_by_clusters(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the failed rules for each cluster grouped into severity levels. + + Keyword arguments: + filter -- "Filter results using a query in Falcon Query Language (FQL). Supported Filters: + compliance_finding.name: Compliance finding Name + image_digest: Image digest (sha256 digest) + image_tag: Image tag + cloud_info.cloud_account_id: Cloud account ID + image_id: Image ID + image_registry: Image registry + cloud_info.cloud_region: Cloud region + asset_type: asset type (container, image) + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + cid: Customer ID + compliance_finding.id: Compliance finding ID + compliance_finding.framework: Compliance finding framework (available values: CIS) + cloud_info.cluster_name: Kubernetes cluster name + image_repository: Image repository + cloud_info.cloud_provider: Cloud provider + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateFailedRulesByClusters + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateFailedRulesByClusters", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_failed_rules_by_image(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get images with failed rules, rule count grouped by severity for each image. + + Keyword arguments: + filter -- "Filter results using a query in Falcon Query Language (FQL). Supported Filters: + compliance_finding.id: Compliance finding ID + image_tag: Image tag + cloud_info.cluster_name: Kubernetes cluster name + image_registry: Image registry + cloud_info.cloud_provider: Cloud provider + compliance_finding.name: Compliance finding Name + cid: Customer ID + cloud_info.cloud_region: Cloud region + cloud_info.cloud_account_id: Cloud account ID + asset_type: asset type (container, image) + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + image_id: Image ID + image_digest: Image digest (sha256 digest) + compliance_finding.framework: Compliance finding framework (available values: CIS) + image_repository: Image repository + cloud_info.namespace: Kubernetes namespace + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateFailedRulesByImages + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateFailedRulesByImages", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_failed_rules_count_by_severity(self: object, + parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the failed rules count grouped into severity levels. + + Keyword arguments: + filter -- "Filter results using a query in Falcon Query Language (FQL). Supported Filters: + cid: Customer ID + cloud_info.cloud_region: Cloud region + compliance_finding.id: Compliance finding ID + image_id: Image ID + image_tag: Image tag + image_digest: Image digest (sha256 digest) + compliance_finding.framework: Compliance finding framework (available values: CIS) + image_repository: Image repository + cloud_info.cloud_account_id: Cloud account ID + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + asset_type: asset type (container, image) + cloud_info.cluster_name: Kubernetes cluster name + cloud_info.cloud_provider: Cloud provider + image_registry: Image registry + compliance_finding.name: Compliance finding Name + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateFailedRulesCountBySeverity + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateFailedRulesCountBySeverity", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def aggregate_rules_by_status(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get the rules grouped by their statuses. + + Keyword arguments: + filter -- "Filter results using a query in Falcon Query Language (FQL). Supported Filters: + compliance_finding.id: Compliance finding ID + image_tag: Image tag + compliance_finding.name: Compliance finding Name + asset_type: asset type (container, image) + compliance_finding.severity: Compliance finding severity; + available values: 4, 3, 2, 1 (4: critical, 3: high, 2: medium, 1:low) + cid: Customer ID + container_name: Container name + cloud_info.cluster_name: Kubernetes cluster name + image_repository: Image repository + cloud_info.cloud_provider: Cloud provider + image_registry: Image registry + compliance_finding.framework: Compliance finding framework (available values: CIS) + cloud_info.cloud_region: Cloud region + cloud_info.cloud_account_id: Cloud account ID + image_id: Image ID + image_digest: Image digest (sha256 digest) + container_id: Container ID + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/complianceAssessments/extAggregateRulesByStatus + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="extAggregateRulesByStatus", + keywords=kwargs, + params=parameters + ) + # These method names align to the operation IDs in the API but + # do not conform to snake_case / PEP8 and are defined here for + # backwards compatibility / ease of use purposes + extAggregateClusterAssessments = aggregate_cluster_assessments + extAggregateImageAssessments = aggregate_image_assessments + extAggregateRulesAssessments = aggregate_rules_assessments + extAggregateFailedContainersByRulesPath = aggregate_failed_containers_by_rules + extAggregateFailedContainersCountBySeverity = aggregate_failed_containers_count_by_severity + extAggregateFailedImagesByRulesPath = aggregate_failed_images_by_rules + extAggregateFailedImagesCountBySeverity = aggregate_failed_images_count_by_severity + extAggregateFailedRulesByClusters = aggregate_failed_rules_by_clusters + extAggregateFailedRulesByImages = aggregate_failed_rules_by_image + extAggregateFailedRulesCountBySeverity = aggregate_failed_rules_count_by_severity + extAggregateRulesByStatus = aggregate_rules_by_status diff --git a/src/falconpy/host_migration.py b/src/falconpy/host_migration.py new file mode 100644 index 000000000..4bfd388a8 --- /dev/null +++ b/src/falconpy/host_migration.py @@ -0,0 +1,651 @@ +"""CrowdStrike Falcon Certificate Based Exclusions API interface class. + + _______ __ _______ __ __ __ +| _ .----.-----.--.--.--.--| | _ | |_.----|__| |--.-----. +|. 1___| _| _ | | | | _ | 1___| _| _| | <| -__| +|. |___|__| |_____|________|_____|____ |____|__| |__|__|__|_____| +|: 1 | |: 1 | +|::.. . | CROWDSTRIKE FALCON |::.. . | FalconPy +`-------' `-------' + +OAuth2 API - Customer SDK + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +""" + +from typing import Dict, Union +from ._util import force_default, process_service_request, generate_error_result, handle_single_argument +from ._service_class import ServiceClass +from ._endpoint._host_migration import _host_migration_endpoints as Endpoints +from ._payload import generic_payload_list, aggregate_payload + + +class HostMigration(ServiceClass): + """The only requirement to instantiate an instance of this class is one of the following. + + - a valid client_id and client_secret provided as keywords. + - a credential dictionary with client_id and client_secret containing valid API credentials + { + "client_id": "CLIENT_ID_HERE", + "client_secret": "CLIENT_SECRET_HERE" + } + - a previously-authenticated instance of the authentication service class (oauth2.py) + - a valid token provided by the authentication service class (oauth2.py) + """ + + @force_default(defaults=["body"], default_types=["list"]) + def aggregate_host_migration(self: object, body: list = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get host migration aggregates as specified via json in request body. + + Keyword arguments: + body -- full body payload, not required if using other keywords. + { + "resources": [ + { + "date_ranges": [ + { + "from": "string", + "to": "string" + } + ], + "exclude": "string", + "extended_bounds": { + "max": "string", + "min": "string" + }, + "field": "string", + "filter": "string", + "from": 0, + "include": "string", + "interval": "string", + "max_doc_count": 0, + "min_doc_count": 0, + "missing": "string", + "name": "string", + "q": "string", + "ranges": [ + { + "From": 0, + "To": 0 + } + ], + "size": 0, + "sort": "string", + "sub_aggregates": [ + null + ], + "time_zone": "string", + "type": "string" + } + ] + } + + Supported Types: + Both types support the following FQL filter properties: + groups, hostgroups, static_host_groups, hostname, status, + target_cid, source_cid, migration_id, id, host_migration_id, created_time. + The values groups and hostgroups are aliases for static_host_groups. + The value host_migration_id is an alias for id + + Type 1 - Terms + "type": "terms" + Supported field values: + groups, hostgroups, static_host_groups, hostname, + status, target_cid, source_cid, migration_id, id, host_migration_id. + sort must be done on the same value as field and include a direction (asc or desc). + Supports all FQL fields except for groups, hostgroups, or static_host_groups. + Examples sort value: status|asc or created_by|desc + + Type 2 - Date Range + "type": "date_range" + Supported field fields: created_time. + Does not support sort, size, or from. + + Returns: dict object containing API response. + + HTTP Method: POST + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/HostMigrationAggregatesV1 + """ + if not body: + body = [aggregate_payload(submitted_keywords=kwargs)] + + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="HostMigrationAggregatesV1", + body=body + ) + + @force_default(defaults=["body"], default_types=["list"]) + def aggregate_migration(self: object, body: list = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get migration aggregates as specified via json in request body. + + Keyword arguments: + body -- full body payload, not required if using other keywords. + { + "resources": [ + { + "date_ranges": [ + { + "from": "string", + "to": "string" + } + ], + "exclude": "string", + "extended_bounds": { + "max": "string", + "min": "string" + }, + "field": "string", + "filter": "string", + "from": 0, + "include": "string", + "interval": "string", + "max_doc_count": 0, + "min_doc_count": 0, + "missing": "string", + "name": "string", + "q": "string", + "ranges": [ + { + "From": 0, + "To": 0 + } + ], + "size": 0, + "sort": "string", + "sub_aggregates": [ + null + ], + "time_zone": "string", + "type": "string" + } + ] + } + + Supported Types: + Both types support the following FQL filter props: + name, id, migration_id, target_cid, status, migration_status, created_by, created_time. + The value migration_status is an alias for status. + The value migration_id is an alias for id. + + + Type 1 - Terms + "type": "terms" + Supported field values: name, id, migration_id, target_cid, status, migration_status, created_by. + sort on terms type must be done on the same value as field and include a direction (asc or desc). + Supports all supported FQL fields. + Examples sort value: status|asc or created_by|desc. + + Type 2 - Date Range + "type": "date_range" + Supported field fields: created_time. + Does not support sort, size, or from. + + Returns: dict object containing API response. + + HTTP Method: POST + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/MigrationAggregatesV1 + """ + if not body: + body = [aggregate_payload(submitted_keywords=kwargs)] + + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="MigrationAggregatesV1", + body=body + ) + + @force_default(defaults=["body", "parameters"], default_types=["dict"]) + def perform_host_migration_action(self: object, + body: dict = None, + parameters: dict = None, + **kwargs) -> Dict[str, Union[int, dict]]: + """Perform an action on host migrations. + + Keyword arguments: + id -- The migration job to perform actions on. String. + + action_name -- The action to perform + Available values: remove_hosts, remove_host_groups, add_host_groups + + body -- full body payload, not required if using other keywords. + { + "resources": [ + { + "action_parameters": [ + { + "name": "string", + "value": "string" + } + ], + "filter": "string", + "ids": [ + "string" + ] + } + ] + } + + Available Actions: + These actions only works if the migration has not started. + + add_host_groups adds static host groups to the selected hosts in a migration. + This action accepts the following action parameter: { "name": "host_group": "value": "$host_group_id" }. + Action parameters can be repeated to add multiple static host groups in a single request. + + remove_host_groups removes static host groups from the selected hosts in a migration. + This action accepts the following action parameter: { "name": "host_group": "value": "$host_group_id" }. + Action parameters can be repeated to remove multiple static host groups in a single request. + + remove_hosts removes the selected hosts from a migration. + This action does not accept any action parameters. + + FQL Filter supports the following fields: + groups, hostgroups, static_host_groups, + hostname, status, target_cid, source_cid, + migration_id, id, host_migration_id, created_time. + + Returns: dict object containing API response. + + HTTP Method: POST + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/HostMigrationsActionsV1 + """ + if not body: + body = generic_payload_list(submitted_keywords=kwargs, + payload_value="ids" + ) + if kwargs.get("filter", None): + body["filter"] = kwargs.get("filter") + # Passing an action_parameters list will override the filter keyword + if kwargs.get("action_parameters", None): + body["action_parameters"] = kwargs.get("action_parameters", None) + + _allowed_actions = ['remove_hosts', 'remove_host_groups', 'add_host_groups'] + operation_id = "HostMigrationsActionsV1" + if kwargs.get("action_name").lower() in _allowed_actions: + returned = process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id=operation_id, + body=body, + keywords=kwargs, + params=parameters + ) + else: + returned = generate_error_result("Invalid value specified for action_name parameter.") + + return returned + + @force_default(defaults=["body"], default_types=["dict"]) + def get_host_migration_details(self: object, body: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get migration aggregates as specified via json in request body. + + Keyword arguments: + body -- full body payload, not required if using other keywords. + { + "resources":[ + { + "ids":[ + "string" + ] + } + ] + } + + Returns: dict object containing API response. + + Events + The events field describes actions that have occurred to the host migration entity. + Each object is defined by the action field. + When user is present, it is the user who performed the action. time is when the action occurred. + + Status Details + The status_details field is an optional field that + provides some more details about the status of a failed host migration. + It may be omitted or empty from a response. + + + + HTTP Method: POST + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/GetHostMigrationsV1 + """ + if not body: + body = generic_payload_list(submitted_keywords=kwargs, + payload_value="ids" + ) + + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="GetHostMigrationsV1", + body=body + ) + + @force_default(defaults=["body"], default_types=["dict"]) + def get_migration_destination(self: object, body: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get destinations for a migration. + + Keyword arguments: + body -- full body payload, not required if using other keywords. + { + "resources": [ + { + "device_ids": [ + "string" + ], + "filter": "string" + } + ] + } + + Returns: dict object containing API response. + + HTTP Method: POST + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/GetMigrationDestinationsV1 + """ + if not body: + if kwargs.get("device_ids", None): + body = generic_payload_list(submitted_keywords=kwargs, + payload_value="device_ids" + ) + else: + body["filter"] = kwargs.get("filter", None) + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="GetMigrationDestinationsV1", + body=body + ) + + @force_default(defaults=["body", "parameters"], default_types=["dict"]) + def perform_migration_job_action(self: object, + body: dict = None, + parameters: dict = None, + **kwargs) -> Dict[str, Union[int, dict]]: + """Perform an action on host migrations. + + Keyword arguments: + action_name -- The action to perform + Available values: remove_hosts, remove_host_groups, add_host_groups + body -- full body payload, not required if using other keywords. + { + "resources": [ + { + "action_parameters": [ + { + "name": "string", + "value": "string" + } + ], + "filter": "string", + "ids": [ + "string" + ] + } + ] + } + + Available Actions: + These actions only works if the migration has not started. + + add_host_groups adds static host groups to the selected hosts in a migration. + This action accepts the following action parameter: { "name": "host_group": "value": "$host_group_id" }. + Action parameters can be repeated to add multiple static host groups in a single request. + + remove_host_groups removes static host groups from the selected hosts in a migration. + This action accepts the following action parameter: { "name": "host_group": "value": "$host_group_id" }. + Action parameters can be repeated to remove multiple static host groups in a single request. + + remove_hosts removes the selected hosts from a migration. + This action does not accept any action parameters. + + FQL Filter supports the following fields: + groups, hostgroups, static_host_groups, + hostname, status, target_cid, source_cid, + migration_id, id, host_migration_id, created_time. + + Returns: dict object containing API response. + + HTTP Method: POST + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/MigrationsActionsV1 + """ + if not body: + body = generic_payload_list(submitted_keywords=kwargs, + payload_value="ids" + ) + if kwargs.get("filter", None): + body["filter"] = kwargs.get("filter") + # Passing an action_parameters list will override the filter keyword + if kwargs.get("action_parameters", None): + body["action_parameters"] = kwargs.get("action_parameters", None) + + _allowed_actions = ['start_migration', 'cancel_migration', 'rename_migration', 'delete_migration'] + operation_id = "MigrationsActionsV1" + if kwargs.get("action_name", "Not Specified").lower() in _allowed_actions: + returned = process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id=operation_id, + body=body, + keywords=kwargs, + params=parameters + ) + else: + returned = generate_error_result("Invalid value specified for action_name parameter.") + + return returned + + @force_default(defaults=["parameters"], default_types=["dict"]) + def get_migration_job_details(self: object, *args, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Get migration job details. + + Keyword arguments: + ids -- The migration jobs of interest. + parameters -- full parameters payload, not required if ids is provided as a keyword. + + Arguments: When not specified, the first argument to this method is assumed to be 'ids'. + All others are ignored. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/GetMigrationsV1 + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="GetMigrationsV1", + keywords=kwargs, + params=handle_single_argument(args, parameters, "ids") + ) + + @force_default(defaults=["body"], default_types=["dict"]) + def create_migration(self: object, body: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Create a device migration job. + + Keyword arguments: + body -- full body payload, not required if using other keywords. + { + "resources": [ + { + "device_ids": [ + "string" + ], + "filter": "string", + "name": "string", + "target_cid": "string + } + ] + } + + Returns: dict object containing API response. + + HTTP Method: POST + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/CreateMigrationV1 + """ + if not body: + body = generic_payload_list(submitted_keywords=kwargs, + payload_value="device_ids" + ) + if kwargs.get("filter", None): + body["filter"] = kwargs.get("filter", None) + if kwargs.get("name", None): + body["name"] = kwargs.get("name", None) + if kwargs.get("target_cid", None): + body["target_cid"] = kwargs.get("target_cid", None) + + operation_id = "CreateMigrationV1" + + returned = process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id=operation_id, + body=body + ) + + return returned + + @force_default(defaults=["parameters"], default_types=["dict"]) + def query_host_migration_ids(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Query host migration IDs. + + Provide a FQL filter and paging details. + + Returns a set of Agent IDs which match the filter criteria. + + Keyword arguments: + filter -- The filter expression that should be used to limit the results. + Valid fields: host_migration_id, groups, hostgroups, hostname, + status, migration_id, created_time, static_host_groups, target_cid, source_cid, id + id -- The migration job to query. String. + limit -- The maximum records to return. [1-10000] + offset -- The offset to start retrieving records from + parameters - full parameters payload, not required if using other keywords. + sort -- The property to sort by. FQL syntax (e.g. name|asc). + Available values : + hostname|asc, hostname|desc, hostname, + status|asc, status|desc, status, migration_id|asc, + migration_id|desc, migration_id, created_time|asc, + created_time|desc, created_time, host_migration_id|asc, + host_migration_id|desc, host_migration_id, groups|asc, + groups|desc, groups, hostgroups|asc, hostgroups|desc, + hostgroups, source_cid|asc, source_cid|desc, source_cid, + id|asc, id|desc, id, static_host_groups|asc, static_host_groups|desc, + static_host_groups, target_cid|asc, target_cid|desc, target_cid + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/GetHostMigrationIDsV1 + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="GetHostMigrationIDsV1", + keywords=kwargs, + params=parameters + ) + + @force_default(defaults=["parameters"], default_types=["dict"]) + def query_migration_jobs(self: object, parameters: dict = None, **kwargs) -> Dict[str, Union[int, dict]]: + """Query host migration jobs. + + Provide a FQL filter and paging details. + + Returns a set of Agent IDs which match the filter criteria. + + Keyword arguments: + filter -- The filter expression that should be used to limit the results. + Valid fields: target_cid, status, migration_status, created_by, + created_time, name, id, migration_id + limit -- The maximum records to return. [1-10000] + offset -- The offset to start retrieving records from + parameters - full parameters payload, not required if using other keywords. + sort -- The property to sort by. FQL syntax (e.g. name|asc). + Available values : + target_cid|asc, target_cid|desc, target_cid, + status|asc, status|desc, status, + migration_status|asc, migration_status|desc, migration_status, + created_by|asc, created_by|desc, created_by, + created_time|asc, created_time|desc, created_time, + name|asc, name|desc, name, + id|asc, id|desc, id, migration_id|asc, + migration_id|desc, migration_id + + + + This method only supports keywords for providing arguments. + + Returns: dict object containing API response. + + HTTP Method: GET + + Swagger URL + https://assets.falcon.crowdstrike.com/support/api/swagger.html#/host-migration/GetMigrationIDsV1 + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="GetMigrationIDsV1", + keywords=kwargs, + params=parameters + ) + + # These method names align to the operation IDs in the API but + # do not conform to snake_case / PEP8 and are defined here for + # backwards compatibility / ease of use purposes + HostMigrationAggregatesV1 = aggregate_host_migration + MigrationAggregatesV1 = aggregate_migration + HostMigrationsActionsV1 = perform_host_migration_action + GetHostMigrationsV1 = get_host_migration_details + GetMigrationDestinationsV1 = get_migration_destination + MigrationsActionsV1 = perform_migration_job_action + GetMigrationsV1 = get_migration_job_details + CreateMigrationV1 = create_migration + GetHostMigrationIDsV1 = query_host_migration_ids + GetMigrationIDsV1 = query_migration_jobs diff --git a/tests/test_alerts.py b/tests/test_alerts.py index fc7ccd26f..493e05c4c 100644 --- a/tests/test_alerts.py +++ b/tests/test_alerts.py @@ -2,6 +2,7 @@ # This class tests the Alerts service class import os import sys +import pytest # Authentication via the test_authorization.py from tests import test_authorization as Authorization @@ -9,6 +10,7 @@ sys.path.append(os.path.abspath('src')) # Classes to test - manually imported from sibling folder from falconpy import Alerts +from falconpy._util import service_request auth = Authorization.TestAuthorization() config = auth.getConfigObject() @@ -104,3 +106,30 @@ def alerts_run_all_tests(self): def test_all_functionality(self): assert self.alerts_run_all_tests() is True + + def test_token_refresh(self): + returned = False + falconWithObject = Alerts(auth_object=config) + check = falconWithObject.auth_object.token() + if check["status_code"] == 429: + pytest.skip("Rate limit hit") + + if not falconWithObject.token_expired(): + falconWithObject.auth_object.token_expiration = 0 # Forcibly expire the current token + if falconWithObject.query_alerts_v2(parameters={"limit": 1})["status_code"] in AllowedResponses: + returned = True + + assert(returned) + + def test_force_attribute_error(self): + returned = False + FULL_URL = falcon.base_url+'/alerts/queries/alerts/v2' + if service_request(caller=self, + method="GET", + endpoint=FULL_URL, + headers=falcon.headers, + verify=falcon.ssl_verify + )["status_code"] in AllowedResponses: + returned = True + + assert(returned) \ No newline at end of file diff --git a/tests/test_authentications.py b/tests/test_authentications.py index ef462bb76..d63ad36fe 100644 --- a/tests/test_authentications.py +++ b/tests/test_authentications.py @@ -281,6 +281,9 @@ def test_version_check(self): def test_version_compare(self): assert bool(version("1.2.16")) # Will be true as this method is released in 1.3+ + def test_version_compare_quick(self): + assert bool(version("0.9")) # Will be true as this method is released in 1.3+ + def test_version_compare_exact_match(self): assert bool(version(version())) # Should be a while before we hit that... diff --git a/tests/test_certificate_based_exclusions.py b/tests/test_certificate_based_exclusions.py new file mode 100644 index 000000000..71a5cf5be --- /dev/null +++ b/tests/test_certificate_based_exclusions.py @@ -0,0 +1,44 @@ +# test_certificate_based_exclusions.py +# This class tests the CertificateBasedExclusions service class + +# import json +import os +import sys +import pytest + +# Authentication via the test_authorization.py +from tests import test_authorization as Authorization + +# Classes to test - manually imported from sibling folder +from falconpy import CertificateBasedExclusions +# Import our sibling src folder into the path +sys.path.append(os.path.abspath('src')) + +auth = Authorization.TestAuthorization() +config = auth.getConfigObject() +falcon = CertificateBasedExclusions(auth_object=config) +AllowedResponses = [200, 201, 207, 400, 404, 429, 500] + + +class TestCertificateBasedExclusions: + @pytest.mark.skipif(config.base_url == "https://api.laggar.gcw.crowdstrike.com", + reason="Unit testing unavailable on US-GOV-1" + ) + def test_all_code_paths(self): + error_checks = True + tests = { + "get_exclusions": falcon.get_exclusions(ids="1234567"), + "create_exclusions": falcon.create_exclusions(body={}), + "create_exclusions": falcon.create_exclusions(certificate="something", subject="science_fiction"), + "create_exclusions": falcon.create_exclusions(comment="something", host_groups="12345678,87654321"), + "delete_exclusions": falcon.delete_exclusions(ids="1234567"), + "update_exclusions": falcon.update_exclusions(body={}), + "get_certificates": falcon.get_certificates(ids="1234567"), + "query_certificates": falcon.query_certificates() + } + for key in tests: + if tests[key]["status_code"] not in AllowedResponses: + error_checks = False + # print(key) + # print(tests[key]) + assert error_checks diff --git a/tests/test_cloud_connect_aws.py b/tests/test_cloud_connect_aws.py index 70230d84a..d826cde46 100644 --- a/tests/test_cloud_connect_aws.py +++ b/tests/test_cloud_connect_aws.py @@ -13,6 +13,8 @@ from falconpy import oauth2 as FalconAuth from falconpy._util import service_request +pytest.skip(allow_module_level=True) + auth = Authorization.TestAuthorization() config = auth.getConfigObject() diff --git a/tests/test_cloud_snapshots.py b/tests/test_cloud_snapshots.py index 58285c053..3435349a7 100644 --- a/tests/test_cloud_snapshots.py +++ b/tests/test_cloud_snapshots.py @@ -43,7 +43,7 @@ def run_tests(self): ) def test_get_credentials(self): """Pytest harness hook""" - assert bool(falcon.get_credentials()["status_code"] in AllowedResponses) is True + assert bool(falcon.get_credentials()["status_code"] in [*AllowedResponses, 500]) is True @pytest.mark.skipif(config.base_url == "https://api.laggar.gcw.crowdstrike.com", reason="Unit testing unavailable on US-GOV-1" diff --git a/tests/test_compliance_assessments.py b/tests/test_compliance_assessments.py new file mode 100644 index 000000000..a69930d83 --- /dev/null +++ b/tests/test_compliance_assessments.py @@ -0,0 +1,43 @@ +# test_certificate_based_exclusions.py +# This class tests the CertificateBasedExclusions service class + +# import json +import os +import sys + +# Authentication via the test_authorization.py +from tests import test_authorization as Authorization + +# Classes to test - manually imported from sibling folder +from falconpy import ComplianceAssessments +# Import our sibling src folder into the path +sys.path.append(os.path.abspath('src')) + +auth = Authorization.TestAuthorization() +config = auth.getConfigObject() +falcon = ComplianceAssessments(auth_object=config) +AllowedResponses = [200, 201, 207, 400, 404, 429, 500] + + +class TestCertificateBasedExclusions: + def test_all_code_paths(self): + error_checks = True + tests = { + "aggregate_cluster_assessments": falcon.aggregate_cluster_assessments(), + "aggregate_image_assessments": falcon.aggregate_image_assessments(), + "aggregate_rules_assessments": falcon.aggregate_rules_assessments(filter="compliance_finding.severity: '4'"), + "aggregate_failed_containers_by_rules": falcon.aggregate_failed_containers_by_rules(), + "aggregate_failed_containers_count_by_severity": falcon.aggregate_failed_containers_count_by_severity(), + "aggregate_failed_images_by_rules": falcon.aggregate_failed_images_by_rules(), + "aggregate_failed_images_count_by_severity": falcon.aggregate_failed_images_count_by_severity(), + "aggregate_failed_rules_by_clusters": falcon.aggregate_failed_rules_by_clusters(), + "aggregate_failed_rules_by_image": falcon.aggregate_failed_rules_by_image(), + "aggregate_failed_rules_count_by_severity": falcon.aggregate_failed_rules_count_by_severity(), + "aggregate_rules_by_status": falcon.aggregate_rules_by_status() + } + for key in tests: + if tests[key]["status_code"] not in AllowedResponses: + error_checks = False + # print(key) + # print(tests[key]) + assert error_checks diff --git a/tests/test_container_detections.py b/tests/test_container_detections.py index be52c9a44..fc7c4627e 100644 --- a/tests/test_container_detections.py +++ b/tests/test_container_detections.py @@ -34,6 +34,6 @@ def test_all_code_paths(self): for key in tests: if tests[key]["status_code"] not in AllowedResponses: error_checks = False - print(key) - print(tests[key]) + # print(key) + # print(tests[key]) assert error_checks diff --git a/tests/test_cspm_registration.py b/tests/test_cspm_registration.py index c1443267d..ceaa3bc1b 100644 --- a/tests/test_cspm_registration.py +++ b/tests/test_cspm_registration.py @@ -27,15 +27,20 @@ def cspm_get_azure_user_scripts_attachment(self): """ Download and confirm the Azure user script attachment """ + returned = False test_result = falcon.GetCSPMAzureUserScriptsAttachment() if type(test_result) == bytes: - return True + returned = True else: if test_result["body"]["errors"][0]["message"] == "No accounts found": - return True + returned = True + elif test_result["status_code"] == 500: + # This operation is deprecated + returned = True else: pytest.skip("Script attachment download failure.") # return False + return returned def cspm_generate_errors(self): """ @@ -125,7 +130,7 @@ def test_get_aws_account_scripts_attachment(self): """Pytest harness hook""" check = falcon.GetCSPMAwsAccountScriptsAttachment() if isinstance(check, dict): - assert bool(check["status_code"] in AllowedResponses) + assert bool(check["status_code"] in [*AllowedResponses, 500]) else: assert bool(type(falcon.GetCSPMAwsAccountScriptsAttachment()) == bytes) is True diff --git a/tests/test_d4c_registration.py b/tests/test_d4c_registration.py index 04121b6fa..e65391d4a 100644 --- a/tests/test_d4c_registration.py +++ b/tests/test_d4c_registration.py @@ -3,6 +3,7 @@ """ import os import sys +import pytest # Authentication via test_authorization.py from tests import test_authorization as Authorization # Import our sibling src folder into the path @@ -120,6 +121,9 @@ def d4c_generate_errors(self): return error_checks + @pytest.mark.skipif(config.base_url == "https://api.eu-1.crowdstrike.com", + reason="Unit testing unavailable on EU-1" + ) def test_GetCSPMAzureUserScriptsAttachment(self): """ Pytest harness hook diff --git a/tests/test_fdr.py b/tests/test_fdr.py index 33cddbe85..d4e405ebf 100644 --- a/tests/test_fdr.py +++ b/tests/test_fdr.py @@ -16,7 +16,7 @@ auth = Authorization.TestAuthorization() config = auth.getConfigObject() falcon = FDR(auth_object=config) -AllowedResponses = [200, 201, 207, 429, 500] +AllowedResponses = [200, 201, 207, 403, 429, 500] class TestFDR: def test_all_code_paths(self): diff --git a/tests/test_host_migration.py b/tests/test_host_migration.py new file mode 100644 index 000000000..854b397c8 --- /dev/null +++ b/tests/test_host_migration.py @@ -0,0 +1,71 @@ +# test_certificate_based_exclusions.py +# This class tests the CertificateBasedExclusions service class + +# import json +import os +import sys + +# Authentication via the test_authorization.py +from tests import test_authorization as Authorization + +# Classes to test - manually imported from sibling folder +from falconpy import HostMigration +# Import our sibling src folder into the path +sys.path.append(os.path.abspath('src')) + +auth = Authorization.TestAuthorization() +config = auth.getConfigObject() +falcon = HostMigration(auth_object=config) +AllowedResponses = [200, 201, 207, 400, 403, 404, 429, 500] + + +class TestHostMigration: + def test_all_code_paths(self): + error_checks = True + tests = { + "aggregate_host_migration": falcon.aggregate_host_migration(body={}), + "aggregate_migration": falcon.aggregate_migration(body={}), + "perform_host_migration_action": falcon.perform_host_migration_action(id="1234567", + action_name="remove_hosts", + ids="1234567", + action_parameters=[{ + "name": "group_id", + "value": "1234567"}]), + "perform_host_migration_action_two": falcon.perform_host_migration_action(id="1234567", + action_name="kablooie", + ids="1234567", + action_parameters=[{ + "name": "group_id", + "value": "1234567"}], + filter="something"), + "get_host_migration_details": falcon.get_host_migration_details(ids="12345678"), + "get_migration_destination": falcon.get_migration_destination(filter="filter"), + "get_migration_destination_also": falcon.get_migration_destination(device_ids="12345678,87654321"), + "perform_migration_job_action": falcon.perform_migration_job_action(action_name="rename_migration", + filter="filter", + ids="12345677", + action_parameters=[{ + "name": "my_migration", + "value": "new_migration"}]), + "perform_migration_job_action_too": falcon.perform_migration_job_action(action_name="kaboom", + filter="filter", + ids="12345677", + action_parameters=[{ + "name": "my_migration", + "value": "new_migration"}]), + "get_migration_job_details": falcon.get_migration_job_details(ids=12345678), + "create_migration": falcon.create_migration(filter="test: 'test'", + name="name", + target_cid="cid", + device_ids=["12345678"]), + "query_host_migration_ids": falcon.query_host_migration_ids(id="12345678", + limit=1, + filter="test:'test'"), + "query_migration_jobs": falcon.query_migration_jobs() + } + for key in tests: + if tests[key]["status_code"] not in AllowedResponses: + error_checks = False + # print(key) + # print(tests[key]) + assert error_checks diff --git a/tests/test_image_assessment_policies.py b/tests/test_image_assessment_policies.py index b9c612293..d9da069ae 100644 --- a/tests/test_image_assessment_policies.py +++ b/tests/test_image_assessment_policies.py @@ -4,6 +4,7 @@ # import json import os import sys +import pytest # Authentication via the test_authorization.py from tests import test_authorization as Authorization @@ -20,6 +21,9 @@ class TestImageAssessmentPolicies: + @pytest.mark.skipif(config.base_url == "https://api.us-2.crowdstrike.com", + reason="Unit testing unavailable on US-2" + ) def test_all_code_paths(self): error_checks = True tests = { diff --git a/tests/test_ml_exclusions.py b/tests/test_ml_exclusions.py index f4dc5376c..3e42958d3 100644 --- a/tests/test_ml_exclusions.py +++ b/tests/test_ml_exclusions.py @@ -37,7 +37,7 @@ def serviceMLE_GenerateErrors(self): value="Charlie", excluded_from=["blocking"] ), - "update_exclusion": falcon.update_exclusions(body={}), + "update_exclusion": falcon.update_exclusions(body={"id": "12345678"}), "update_exclusion_also": falcon.update_exclusions(comment="Unit Testing", groups="12345,67890", id="12345678", diff --git a/tests/test_result_object.py b/tests/test_result_object.py index c8afaa9f6..03e2d9197 100644 --- a/tests/test_result_object.py +++ b/tests/test_result_object.py @@ -772,6 +772,8 @@ def test_pythonic_deprecation_warnings(self): try: old_discover.get_aws_settings() _success = True - except: - pass + except APIError as bad_class: + if bad_class.code == 500: + _success = True # This op is fully deprecated + assert _success diff --git a/tests/test_sensor_visibility_exclusions.py b/tests/test_sensor_visibility_exclusions.py index a424afa4e..564a2c086 100644 --- a/tests/test_sensor_visibility_exclusions.py +++ b/tests/test_sensor_visibility_exclusions.py @@ -13,7 +13,7 @@ auth = Authorization.TestAuthorization() config = auth.getConfigObject() falcon = SensorVisibilityExclusions(auth_object=config) -AllowedResponses = [200, 401, 404, 429] +AllowedResponses = [200, 400, 401, 404, 429] class TestSVExclusions: @@ -31,17 +31,17 @@ def sve_test_all_paths(self): tests = { "get_sv_exclusions": falcon.get_exclusions(ids="12345678"), "create_exclusion": falcon.create_exclusions(body={}), - "create_exclusion_too": falcon.create_exclusions(comment="Unit Testing", - groups=["1234578"], - value="Charlie" + "create_exclusion_too": falcon.create_exclusions(comment="Unit Testing", + groups=["1234578"], + value="Charlie" + ), + "update_exclusion": falcon.update_exclusions(body={"id": "12345678"}), + "update_exclusion_also": falcon.update_exclusions(comment="Unit Testing", + groups=["12345678"], + id="12345678", + value="Bananas" ), - "update_exclusion": falcon.update_exclusions(body={}), - "update_exclusion_also": falcon.update_exclusions(comment="Unit Testing", - groups=["12345678"], - id="12345678", - value="Bananas" - ), - "delete_exclusion": falcon.delete_exclusions(ids="12345678"), + "delete_exclusion": falcon.delete_exclusions(ids="12345678"), } for key in tests: if tests[key]["status_code"] == 500: diff --git a/tests/test_zero_trust_assessment.py b/tests/test_zero_trust_assessment.py index 8454c6e1d..cf5bc741d 100644 --- a/tests/test_zero_trust_assessment.py +++ b/tests/test_zero_trust_assessment.py @@ -61,7 +61,7 @@ def test_context_authentication_no_base(self): tok = request_context.set(req) zta = ZeroTrustAssessment(pythonic=True, debug=config.debug) request_context.reset(tok) - assert bool(zta.get_audit().status_code == 200) + assert bool(zta.get_assessments_by_score(filter="score:>30").status_code == 200) @pytest.mark.skipif(config.base_url != "https://api.crowdstrike.com", reason="Unit testing unavailable in this region" @@ -87,7 +87,7 @@ def test_context_authentication(self): req.cs_cloud = config.base_url another_request_context.set(req) zta = ZeroTrustAssessment(pythonic=True, debug=config.debug) - assert bool(zta.get_audit().status_code == 200) + assert bool(zta.get_assessments_by_score(filter="score:>30").status_code == 200) # This should be the last test executed, log out the token @staticmethod diff --git a/util/coverage.config b/util/coverage.config index 3c610ceb3..19be8809b 100644 --- a/util/coverage.config +++ b/util/coverage.config @@ -4,3 +4,6 @@ source = src/falconpy omit = # Ignore debug.py src/falconpy/debug.py + # Deprecated + src/falconpy/cloud_connect_aws.py + src/falconpy/_payload/_cloud_connect_aws.py