diff --git a/crowdstrikeoauthapi.json b/crowdstrikeoauthapi.json index 3cd91e7..e299b6b 100644 --- a/crowdstrikeoauthapi.json +++ b/crowdstrikeoauthapi.json @@ -75,39 +75,51 @@ "description": "Maximum events to get while POLL NOW", "default": 2000 }, + "max_incidents": { + "data_type": "numeric", + "order": 7, + "description": "Maximum incidents to get for scheduled and interval polling", + "default": 1000 + }, + "max_incidents_poll_now": { + "data_type": "numeric", + "order": 8, + "description": "Maximum incidents to get while POLL NOW", + "default": 100 + }, "ingest_incidents": { "data_type": "boolean", - "order": 7, - "description": "Should ingest incidents in addition to detections during scheduled and interval polling", + "order": 9, + "description": "Should ingest incidents during polling", "default": false }, "collate": { "data_type": "boolean", - "order": 8, + "order": 10, "description": "Merge containers for hostname and eventname", "default": true }, "merge_time_interval": { "data_type": "numeric", - "order": 9, + "order": 11, "description": "Merge same containers within specified seconds", "default": 0 }, "max_crlf": { "data_type": "numeric", - "order": 10, + "order": 12, "default": 50, "description": "Maximum allowed continuous blank lines" }, "preprocess_script": { "data_type": "file", "description": "Script with functions to preprocess containers and artifacts", - "order": 11 + "order": 13 }, "detonate_timeout": { "data_type": "numeric", "description": "Timeout for detonation result in minutes (Default: 15 minutes)", - "order": 12, + "order": 14, "default": 15 } }, diff --git a/crowdstrikeoauthapi_connector.py b/crowdstrikeoauthapi_connector.py index 22b777a..d757204 100644 --- a/crowdstrikeoauthapi_connector.py +++ b/crowdstrikeoauthapi_connector.py @@ -298,14 +298,13 @@ def _check_data(self, action_result, param, max_limit=None, sort_data=None): return action_result.set_status(phantom.APP_SUCCESS) - def _save_results(self, results, param): - + def _save_results(self, results, param, is_incident=False): reused_containers = 0 - containers_processed = 0 - for i, result in enumerate(results): + artifact_type = 'incident' if is_incident else 'event' - self.send_progress("Adding event artifact # {0}".format(i)) + for i, result in enumerate(results): + self.send_progress("Adding {} artifact # {}".format(artifact_type, i)) # result is a dictionary of a single container and artifacts if "container" not in result: self.debug_print("Skipping empty container # {0}".format(i)) @@ -2596,18 +2595,26 @@ def _validate_on_poll_config_params(self, action_result, config): max_events = self._validate_integers( action_result, config.get("max_events_poll_now", DEFAULT_POLLNOW_EVENTS_COUNT), "max_events_poll_now" ) + self.debug_print("Validating 'max_incidents_poll_now' asset configuration parameter") + max_incidents = self._validate_integers( + action_result, config.get("max_incidents_poll_now", DEFAULT_POLLNOW_INCIDENTS_COUNT), "max_incidents_poll_now" + ) except Exception as ex: - self.debug_print("Error occurred while validating 'max_events_poll_now' asset configuration parameter") + self.debug_print("Error occurred while validating poll now parameters") max_events = "{}: {}".format(DEFAULT_POLLNOW_EVENTS_COUNT, self._get_error_message_from_exception(ex)) + max_incidents = "{}: {}".format(DEFAULT_POLLNOW_INCIDENTS_COUNT, self._get_error_message_from_exception(ex)) else: # Scheduled and Interval Polling try: self.debug_print("Validating 'max_events' asset configuration parameter") max_events = self._validate_integers(action_result, config.get("max_events", DEFAULT_EVENTS_COUNT), "max_events") + self.debug_print("Validating 'max_incidents' asset configuration parameter") + max_incidents = self._validate_integers(action_result, config.get("max_incidents", DEFAULT_INCIDENTS_COUNT), "max_incidents") except Exception as ex: max_events = "{}: {}".format(DEFAULT_EVENTS_COUNT, self._get_error_message_from_exception(ex)) + max_incidents = "{}: {}".format(DEFAULT_INCIDENTS_COUNT, self._get_error_message_from_exception(ex)) - return max_crlf, merge_time_interval, max_events, ingest_incidents + return max_crlf, merge_time_interval, max_events, max_incidents, ingest_incidents def _on_poll(self, param): @@ -2623,7 +2630,7 @@ def _on_poll(self, param): config = self.get_config() - max_crlf, merge_time_interval, max_events, ingest_incidents = self._validate_on_poll_config_params(action_result, config) + max_crlf, merge_time_interval, max_events, max_incidents, ingest_incidents = self._validate_on_poll_config_params(action_result, config) if max_crlf is None or merge_time_interval is None or max_events is None: return action_result.get_status() @@ -2635,7 +2642,7 @@ def _on_poll(self, param): # Handle incident ingestion if enabled if ingest_incidents: - ret_val = self._poll_incidents(action_result, param, max_events) + ret_val = self._poll_incidents(action_result, param, max_incidents) if phantom.is_fail(ret_val): return action_result.get_status() @@ -2767,11 +2774,11 @@ def _poll_detection_events(self, action_result, param, config, max_crlf, max_eve return phantom.APP_SUCCESS - def _poll_incidents(self, action_result, param, max_events): + def _poll_incidents(self, action_result, param, max_incidents): self.save_progress("Starting incident ingestion...") try: # Get incidents - params = {"limit": max_events, "sort": "modified_timestamp.asc"} + params = {"limit": max_incidents, "sort": "modified_timestamp.asc"} if not self.is_poll_now(): try: @@ -2811,7 +2818,7 @@ def _poll_incidents(self, action_result, param, max_events): # Process incidents through parser self.save_progress(f"Processing {len(incidents)} incidents...") incident_results = incidents_parser.process_incidents(incidents) - self._save_results(incident_results, param) + self._save_results(incident_results, param, True) self.save_progress("Successfully processed incidents") else: self.save_progress("No incidents found in response") diff --git a/crowdstrikeoauthapi_consts.py b/crowdstrikeoauthapi_consts.py index bc6df09..a94f12b 100644 --- a/crowdstrikeoauthapi_consts.py +++ b/crowdstrikeoauthapi_consts.py @@ -66,6 +66,8 @@ DEFAULT_POLLNOW_EVENTS_COUNT = 2000 DEFAULT_EVENTS_COUNT = 10000 DEFAULT_BLANK_LINES_ALLOWABLE_LIMIT = 50 +DEFAULT_POLLNOW_INCIDENTS_COUNT = 100 +DEFAULT_INCIDENTS_COUNT = 1000 # Status messages for the app CROWDSTRIKE_SUCC_CONNECTIVITY_TEST = "Test connectivity passed" diff --git a/release_notes/unreleased.md b/release_notes/unreleased.md index fbcb2fd..6756fc6 100644 --- a/release_notes/unreleased.md +++ b/release_notes/unreleased.md @@ -1 +1,5 @@ **Unreleased** + +* Added support for ingesting incidents during polling (disabled by default) [PAPP-35103] +* Added 'run query' action for general CrowdStrike query support [PAPP-35103] +* Updated 'create session' to support offline command queueing using 'queue_offline' parameter (disabled by default) [PAPP-35103] \ No newline at end of file