From 4ee330d5abce8d6c959a9f60f45f5319eea03874 Mon Sep 17 00:00:00 2001 From: Joshua Hiller Date: Wed, 10 Sep 2025 20:25:41 -0400 Subject: [PATCH 1/5] Update CHANGELOG.md --- CHANGELOG.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6227a0d7..f9f9e171 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,39 @@ +# Version 1.5.5 +## Added features and functionality ++ Added: Added new __Cloud Security Compliance__ service collection with 2 new operations. + - `_endpoint/__init__.py` + - `_endpoint/_cloud_security_compliance.py` + - `_endpoint/deprecated/__init__.py` + - `_endpoint/deprecated/_cloud_security_compliance.py` + - `__init__.py` + - `cloud_security_compliance.py` + > Unit testing expanded to complete code coverage. + - `tests/test_cloud_security_compliance.py` + +- Added: Added new _WorkflowDefinitionsStatus_ operation to the __Workflows__ service class. + - `_constant/__init__.py` + - `_endpoint/_workflows.py` + - `workflows.py` + > Unit testing expanded to complete code coverage. + - `tests/test_workflows.py` + - Special thanks go out to @dweissbacher for contributing this update and related unit tests! 🙇 + +## Issues resolved ++ Fixed: Resolved path interpolation issue for the `search_id` keyword when using the Uber Class to call the _GetSearchStatusV1_ operation. Closes #1365. + - `_util/_uber.py` + - Thanks go out to @yakeeliuliu for reporting this issue! 🙇 + ++ Fixed: Resolved body payload generation issue with the _userActionV1_ operation within the __UserManagement__ service class. + - `user_management.py` + ++ Fixed: Resolved availability issue with FDR service collection endpoints within the endpoint module. Closes #1371. + - `_endpoint/__init__.py` + > Thanks go out to @Don-Swanson-Adobe for reporting this issue! 🙇 + +## Other + +--- + # Version 1.5.4 ## Added features and functionality + Added: Added _tag_key_ and _tag_value_ as allowed values for the `filter` parameter in the _cloud_security_assets_combined_compliance_by_account_ operation within the __Cloud Security Assets__ service collection. From cdacbf42afd5a15be0b8459f6446e9a4b0d59a87 Mon Sep 17 00:00:00 2001 From: Adam Taveras Date: Fri, 5 Sep 2025 07:48:44 -0400 Subject: [PATCH 2/5] added `GetSensorUsageHourly` as this allows you to pull hourly for Cloud based; added it to test sensor; tested it in production and works since the endpoint does work and provides hourly usage billing that is used for Cloud (reserved hourly) usage --- src/falconpy/_endpoint/_sensor_usage.py | 22 +++++++++++++ src/falconpy/sensor_usage.py | 44 +++++++++++++++++++++++++ tests/test_sensor_usage.py | 3 +- 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/falconpy/_endpoint/_sensor_usage.py b/src/falconpy/_endpoint/_sensor_usage.py index e8c35a0c..fb1c8df2 100644 --- a/src/falconpy/_endpoint/_sensor_usage.py +++ b/src/falconpy/_endpoint/_sensor_usage.py @@ -58,5 +58,27 @@ "in": "query" } ] + ], + [ + "GetSensorUsageHourly", + "GET", + "/billing-dashboards-usage/aggregates/hourly-average/v1", + "Fetches hourly average. Each data point represents the average of how many unique AIDs were seen per week " + "for the previous 28 days.", + "sensor_usage", + [ + { + "type": "string", + "description": "The FQL search filter. Allowed fields:\n\"event_date\" : A specified date that will be " + " final date of the results returned. Specified date cannot be after the default.\n\tFormat: " + "'2024-06-11'\n\tDefault: the current date, minus 2 days, in UTC\n\"period\" : An integer surrounded by single " + "quotes representing the number of days to return.\n\tFormat: '30'\n\tDefault: '28'\n\tMinimum: '1'\n\tMaximum: " + " '395'\n\"selected_cids\" : A comma separated list of CIDs to return data for. Caller must be a parent CID or " + "have special access enabled.\n\tFormat: 'cid_1,cid_2,cid_3'\n\tDefault: for parent CIDs the default is the " + "parent and all children, otherwise the current CID", + "name": "filter", + "in": "query" + } + ] ] ] diff --git a/src/falconpy/sensor_usage.py b/src/falconpy/sensor_usage.py index d9ad0bbf..cf02ecad 100644 --- a/src/falconpy/sensor_usage.py +++ b/src/falconpy/sensor_usage.py @@ -97,4 +97,48 @@ def get_weekly_usage(self: object, parameters: dict = None, **kwargs) -> Union[D params=parameters ) + @force_default(defaults=["parameters"], default_types=["dict"]) + def get_hourly_usage(self: object, parameters: dict = None, **kwargs) -> Union[Dict[str, Union[int, dict]], Result]: + """Fetch hourly sensor usage average used to measure cloud usage. + + Each data point represents the average of how many unique AIDs were seen per week for the previous 28 days. + + Keyword arguments: + filter -- The FQL search filter. + Allowed fields: + event_date - A specified date that will be final date of the results returned. + Specified date cannot be after the default. + Format: '2024-06-11' + Default: the current date, minus 2 days, in UTC + period - An integer surrounded by single quotes representing the number of days to return. + Format: '30' + Default: '28' + Minimum: '1' + Maximum: '395' + selected_cids - A comma delimited list of CIDs to return data for. + Caller must be a parent CID or have special access enabled. + Format: 'cid_1,cid_2,cid_3' + Default: for parent CIDs the default is the parent and all children, + otherwise the current CID + 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#/sensor-usage-api/GetSensorUsageWeekly + Endpoint is not in Swagger file, but allows you to pull `hourly` usage which is used to determine cloud usage + """ + return process_service_request( + calling_object=self, + endpoints=Endpoints, + operation_id="GetSensorUsageHourly", + keywords=kwargs, + params=parameters + ) + GetSensorUsageWeekly = get_weekly_usage + GetSensorUsageHourly = get_hourly_usage diff --git a/tests/test_sensor_usage.py b/tests/test_sensor_usage.py index 8870bfce..a0aab111 100644 --- a/tests/test_sensor_usage.py +++ b/tests/test_sensor_usage.py @@ -23,7 +23,8 @@ class TestSensorUsage: def test_all_code_paths(self): error_checks = True tests = { - "GetWeeklySensorUsage": falcon.get_weekly_usage() + "GetWeeklySensorUsage": falcon.get_weekly_usage(), + "GetHourlySensorUsage": falcon.get_hourly_usage() } for key in tests: if tests[key]["status_code"] not in AllowedResponses: From c8b620988b9060f24cae1120baaa29c424cf3631 Mon Sep 17 00:00:00 2001 From: Subramaniam Arunachalam Date: Tue, 14 Oct 2025 18:13:04 -0700 Subject: [PATCH 3/5] Fix JSONDecodeError import in functions --- .gitignore | 3 ++- src/falconpy/_util/_functions.py | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 0a71eccf..2ac52fce 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.pyc *.swp *.egg +.idea/* env/ .venv/ .eggs/ @@ -16,4 +17,4 @@ __pycache__/ .coverage htmlcov/ Pipfile* -hold \ No newline at end of file +hold diff --git a/src/falconpy/_util/_functions.py b/src/falconpy/_util/_functions.py index 071e5549..bec21789 100644 --- a/src/falconpy/_util/_functions.py +++ b/src/falconpy/_util/_functions.py @@ -41,9 +41,13 @@ from warnings import warn from json import loads try: - from simplejson import JSONDecodeError -except (ImportError, ModuleNotFoundError): # Support import as a module - from json.decoder import JSONDecodeError + from simplejson import JSONDecodeError as SimplejsonJSONDecodeError +except (ImportError, ModuleNotFoundError): + SimplejsonJSONDecodeError = None# Support import as a module + +from json.decoder import JSONDecodeError as StdJSONDecodeError +#create a tuple of all possible JSONDecodeError types for exception handling +JSONDecodeError = (SimplejsonJSONDecodeError, StdJSONDecodeError) if SimplejsonJSONDecodeError else (StdJSONDecodeError,) from typing import Dict, Any, Union, Optional, List, TYPE_CHECKING from copy import deepcopy from logging import Logger From a5134c4e4a44e337f796066a67abe49117beeb47 Mon Sep 17 00:00:00 2001 From: subbu-cs Date: Thu, 6 Nov 2025 14:09:21 -0800 Subject: [PATCH 4/5] Fix lint issues --- src/falconpy/_util/_functions.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/falconpy/_util/_functions.py b/src/falconpy/_util/_functions.py index bec21789..0eae88d3 100644 --- a/src/falconpy/_util/_functions.py +++ b/src/falconpy/_util/_functions.py @@ -43,11 +43,8 @@ try: from simplejson import JSONDecodeError as SimplejsonJSONDecodeError except (ImportError, ModuleNotFoundError): - SimplejsonJSONDecodeError = None# Support import as a module - + SimplejsonJSONDecodeError = None # Support import as a module from json.decoder import JSONDecodeError as StdJSONDecodeError -#create a tuple of all possible JSONDecodeError types for exception handling -JSONDecodeError = (SimplejsonJSONDecodeError, StdJSONDecodeError) if SimplejsonJSONDecodeError else (StdJSONDecodeError,) from typing import Dict, Any, Union, Optional, List, TYPE_CHECKING from copy import deepcopy from logging import Logger @@ -89,6 +86,8 @@ urllib3.disable_warnings(InsecureRequestWarning) +# create a tuple of all possible JSONDecodeError types for exception handling +JSONDecodeError = (SimplejsonJSONDecodeError, StdJSONDecodeError) if SimplejsonJSONDecodeError else (StdJSONDecodeError,) def validate_payload(validator: Dict[str, Any], payload: Dict[str, Union[str, int, dict, list, bytes]], From c0d3df3ae074b43ac7b97092ac6e36efb67e12aa Mon Sep 17 00:00:00 2001 From: Subramaniam Arunachalam Date: Thu, 6 Nov 2025 14:17:03 -0800 Subject: [PATCH 5/5] Fix more lint issues --- src/falconpy/_util/_functions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/falconpy/_util/_functions.py b/src/falconpy/_util/_functions.py index 0eae88d3..f887e87d 100644 --- a/src/falconpy/_util/_functions.py +++ b/src/falconpy/_util/_functions.py @@ -43,7 +43,7 @@ try: from simplejson import JSONDecodeError as SimplejsonJSONDecodeError except (ImportError, ModuleNotFoundError): - SimplejsonJSONDecodeError = None # Support import as a module + SimplejsonJSONDecodeError = None # Support import as a module from json.decoder import JSONDecodeError as StdJSONDecodeError from typing import Dict, Any, Union, Optional, List, TYPE_CHECKING from copy import deepcopy @@ -89,6 +89,7 @@ # create a tuple of all possible JSONDecodeError types for exception handling JSONDecodeError = (SimplejsonJSONDecodeError, StdJSONDecodeError) if SimplejsonJSONDecodeError else (StdJSONDecodeError,) + def validate_payload(validator: Dict[str, Any], payload: Dict[str, Union[str, int, dict, list, bytes]], required: Optional[List[str]] = None