From 217597162be305f6e0cebc114b57496236bb6d96 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Thu, 5 Sep 2024 12:34:20 +0530 Subject: [PATCH 01/26] deduplication code --- .../Integrations/Cybereason/Cybereason.py | 14 ++++++- .../CybereasonPreProcessingExample.py | 39 ++++++++++++------- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 9f3e80f66328..577f6421864b 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -1477,13 +1477,25 @@ def malop_to_incident(malop: str) -> dict: if not isinstance(malop, dict): raise ValueError("Cybereason raw response is not valid, malop is not dict") + status = 0 + if malop.get('status', ''): + malopStatus = malop.get('status', '') + else: + malopStatus = malop.get('simpleValues', '').get('managementStatus', '').get('values', '')[0] + if (malopStatus == "Active") or (malopStatus == "UNREAD"): + status = 0 + elif (malopStatus == "Remediated") or (malopStatus == "TODO"): + status = 1 + elif (malopStatus == "Closed") or (malopStatus == "RESOLVED"): + status = 2 guid_string = malop.get('guidString', '') if not guid_string: guid_string = malop.get('guid', '') incident = { 'rawJSON': json.dumps(malop), 'name': 'Cybereason Malop ' + guid_string, - 'labels': [{'type': 'GUID', 'value': guid_string}]} + 'labels': [{'type': 'GUID', 'value': guid_string}], + 'status': status } return incident diff --git a/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample.py b/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample.py index c2254e33cd1b..1d4bd9b8248b 100644 --- a/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample.py +++ b/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample.py @@ -6,24 +6,33 @@ def get_guid_from_system_incident(incident: Dict[str, Any]) -> str: malop_guid = '' for label in incident['labels']: - if label['type'] == 'guidString': + if label['type'] == 'GUID': malop_guid = label['value'] break return malop_guid res = True -incident = demisto.incidents()[0] -malop_guid = get_guid_from_system_incident(incident) - -response = demisto.executeCommand('getIncidents', {'query': '-status:Closed and malopguid: {}'.format(malop_guid)}) -malop_incident = response[0]['Contents']['data'] - -if malop_incident: - # Malop was already fetched - updating the relevant incident - res = False - malop_incident = malop_incident[0] - incident['id'] = malop_incident['id'] - demisto.executeCommand('setIncident', incident) - -CommandResults(raw_response=res) +incident = demisto.incidents() +for inc in incident: + malop_guid = get_guid_from_system_incident(inc) + response = execute_command( + 'getIncidents', + {'query': f'name:"Cybereason Malop {malop_guid}"'} + ) + malop_incident = response['data'] + demisto.debug(f"malop incident - {malop_incident}") + if malop_incident: + # Malop was already fetched - updating the relevant incident + res = False + malop_incident = malop_incident[0] + entries: list[dict[str, Any]] = [] + entries.append({'Contents': f'Duplicate incident from cybereason: {inc.get("name")}'}) + entries.append({'Type': EntryType.NOTE, 'ContentsFormat': 'json', 'Contents': json.dumps(inc)}) + entries_str = json.dumps(entries) + execute_command('addEntries', {'id': malop_incident['id'], 'entries': entries_str}) + malop_incident_id = malop_incident['id'] + malop_incident_status = inc['status'] + demisto.debug(f"Updating incident status to : {malop_incident_status}") + execute_command('setIncident', {'id': malop_incident_id, 'status': malop_incident_status}) + demisto.results(res) From be78c85b51be5aa829dbf09d355825e9077fd5c5 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Fri, 11 Oct 2024 12:22:15 +0530 Subject: [PATCH 02/26] fetchfile-progress --- Packs/Cybereason/Integrations/Cybereason/Cybereason.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 577f6421864b..02fd1738f1c9 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -1787,9 +1787,12 @@ def get_batch_id(client: Client, suspect_files_guids: dict) -> list: del suspect_files_guids[file_status['fileName']] for suspect_file in list(suspect_files_guids.keys()): malop_comment = f'Could not download the file {suspect_file} from source machine, even after waiting for 80 seconds.' + demisto.log(malop_comment) + + if new_malop_comments == []: raise DemistoException(malop_comment) - - return new_malop_comments + else: + return new_malop_comments def fetchfile_progress(client: Client): From 73e6752760111f77d8089af29b93c4df94b35b11 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 15 Oct 2024 15:22:57 +0530 Subject: [PATCH 03/26] malop-processes command date filter changes --- Packs/Cybereason/Integrations/Cybereason/Cybereason.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 02fd1738f1c9..5b2c219e648c 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -670,7 +670,8 @@ def malop_processes_command(client: Client, args: dict): if date_time != 'None': date_time_parser = dateparser.parse(date_time) if not date_time_parser: - raise DemistoException("dateTime could not be parsed. Please enter a valid time parameter.") + date_time_parser = dateparser.parse('Fri, 12 Dec 2010') + demisto.log("Returning all the processes since the entered date is not valid.") date_time_parser = date_time_parser.timestamp() milliseconds = int(date_time_parser * 1000) filter_input = [{"facetName": "creationTime", "filterType": "GreaterThan", "values": [milliseconds], "isResult": True}] From 189d7c272f8b978b2a6293a26a3035c7b2c15ce2 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Mon, 21 Oct 2024 06:24:53 +0530 Subject: [PATCH 04/26] Test file changes --- Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py | 5 +++-- .../CybereasonPreProcessingExample_test.py | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index 4e1c68f0c24a..4decb86cfbd7 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -972,11 +972,12 @@ def test_close_fetchfile_command(mocker): def test_malop_to_incident(mocker): from Cybereason import malop_to_incident args = { - "guidString": "12345A" + "guidString": "12345A", + "status": 0 } command_output = malop_to_incident(args) - assert command_output['name'] == "Cybereason Malop 12345A" + assert ((command_output['name'] == "Cybereason Malop 12345A") and (command_output['status'] == 0)) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") diff --git a/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample_test.py b/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample_test.py index 64360e7af6cc..62caa42014b0 100644 --- a/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample_test.py +++ b/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample_test.py @@ -14,7 +14,10 @@ def test_main(mocker): test_data = { 'labels': [ {'type': 'x', 'value': 'not found'}, - {'type': 'guidString', 'value': '12345678'} + {'type': 'guidString', 'value': '12345678'}, + {'type': 'x', 'value': 'nothing'}, + {'type': 'GUID', 'value': '12345678'}, + {'type': 'y', 'value': 'nanana'} ] } From 070bd363e68e75a0f64c5d57a421818ad6e46985 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Mon, 21 Oct 2024 07:14:21 +0530 Subject: [PATCH 05/26] Integration script changes --- Packs/Cybereason/Integrations/Cybereason/Cybereason.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 5b2c219e648c..3afe642335a2 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -1481,7 +1481,7 @@ def malop_to_incident(malop: str) -> dict: status = 0 if malop.get('status', ''): malopStatus = malop.get('status', '') - else: + elif malop.get('simpleValues', ''): malopStatus = malop.get('simpleValues', '').get('managementStatus', '').get('values', '')[0] if (malopStatus == "Active") or (malopStatus == "UNREAD"): status = 0 From 851f78e1f8d6db0191385b47eb475371f11fca0e Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Mon, 21 Oct 2024 07:35:37 +0530 Subject: [PATCH 06/26] integration test file changes --- Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index 4decb86cfbd7..f1ec29a76a81 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -973,7 +973,7 @@ def test_malop_to_incident(mocker): from Cybereason import malop_to_incident args = { "guidString": "12345A", - "status": 0 + "status": 1 } command_output = malop_to_incident(args) From 3c4fae21b6354a3c6896c387a0a1a9a238e730ca Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Mon, 21 Oct 2024 10:16:57 +0530 Subject: [PATCH 07/26] removing demisto.log from the integration script --- Packs/Cybereason/Integrations/Cybereason/Cybereason.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 3afe642335a2..442c0b7d80bb 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -671,7 +671,7 @@ def malop_processes_command(client: Client, args: dict): date_time_parser = dateparser.parse(date_time) if not date_time_parser: date_time_parser = dateparser.parse('Fri, 12 Dec 2010') - demisto.log("Returning all the processes since the entered date is not valid.") + demisto.info("Returning all the processes since the entered date is not valid.") date_time_parser = date_time_parser.timestamp() milliseconds = int(date_time_parser * 1000) filter_input = [{"facetName": "creationTime", "filterType": "GreaterThan", "values": [milliseconds], "isResult": True}] @@ -1788,7 +1788,7 @@ def get_batch_id(client: Client, suspect_files_guids: dict) -> list: del suspect_files_guids[file_status['fileName']] for suspect_file in list(suspect_files_guids.keys()): malop_comment = f'Could not download the file {suspect_file} from source machine, even after waiting for 80 seconds.' - demisto.log(malop_comment) + demisto.info(malop_comment) if new_malop_comments == []: raise DemistoException(malop_comment) From 1f6dddf4fe915b719e8b5b4141b8f795e7cd9cef Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 12:01:04 +0530 Subject: [PATCH 08/26] mapping changes --- .../Integrations/Cybereason/Cybereason.py | 84 +++++++++++++++++-- .../Cybereason/Cybereason_test.py | 2 +- 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 442c0b7d80bb..46a576748703 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -723,7 +723,8 @@ def malop_processes_command(client: Client, args: dict): for output in outputs: # Remove whitespaces from dictionary keys context.append({key.translate({32: None}): value for key, value in output.items()}) - + demisto.info(f"context, {context}") + demisto.info(f"outputs, {outputs}") return CommandResults( readable_output=tableToMarkdown('Cybereason Malop Processes', outputs, headers=PROCESS_HEADERS, removeNull=True), outputs_prefix='Cybereason.Process', @@ -755,7 +756,6 @@ def malop_processes(client: Client, malop_guids: list, filter_value: list) -> di 'templateContext': 'MALOP', 'queryTimeout': None } - return client.cybereason_api_call('POST', '/rest/visualsearch/query/simple', json_body=json_body) @@ -1480,21 +1480,73 @@ def malop_to_incident(malop: str) -> dict: status = 0 if malop.get('status', ''): - malopStatus = malop.get('status', '') + malopStatus = (malop.get('status', 'UNREAD')) elif malop.get('simpleValues', ''): - malopStatus = malop.get('simpleValues', '').get('managementStatus', '').get('values', '')[0] + malopStatus = (malop.get('simpleValues', {}).get('managementStatus', {}).get('values', ['UNREAD'])[0]) if (malopStatus == "Active") or (malopStatus == "UNREAD"): status = 0 elif (malopStatus == "Remediated") or (malopStatus == "TODO"): status = 1 elif (malopStatus == "Closed") or (malopStatus == "RESOLVED"): status = 2 + else: + status = 0 + guid_string = malop.get('guidString', '') if not guid_string: guid_string = malop.get('guid', '') + + if malop.get("isEdr", '') or malop.get("edr", '') or malop.get('simpleValues', ''): + link = SERVER + '/#/malop/' + guid_string + else: + link = SERVER + '/#/detection-malop/' + guid_string + if malop.get("isEdr", '') or malop.get("edr", '') or malop.get('simpleValues', ''): + isEdr = True + else: + isEdr = False + + if malop.get('simpleValues'): + malopCreationTime = malop.get('simpleValues', {}).get('creationTime', {}).get('values', ['2010-01-01'])[0] + malopUpdateTime = malop.get('simpleValues', {}).get('malopLastUpdateTime', {}).get('values', ['2010-01-01'])[0] + else: + malopCreationTime = str(malop.get('creationTime', '2010-01-01')) + malopUpdateTime = str(malop.get('lastUpdateTime', '2010-01-01')) + + if malop.get('elementValues'): + if malop.get('elementValues', {}).get('rootCauseElements', {}).get('elementValues', ''): + rootCauseElementName = (malop.get('elementValues', {}).get('rootCauseElements', {}).get('elementValues', '')[0]).get('name', '') + rootCauseElementType = (malop.get('elementValues', {}).get('rootCauseElements', {}).get('elementValues', '')[0]).get('elementType', '') + else: + rootCauseElementName = '' + rootCauseElementType = '' + else: + rootCauseElementName = malop.get('primaryRootCauseName' , '') + rootCauseElementType = malop.get('rootCauseElementType', '') + + if malop.get('malopDetectionType'): + detectionType = malop.get('malopDetectionType', '') + else: + detectionType = (malop.get('simpleValues', {}).get('detectionType', {}).get('values', [''])[0]) + + malopGroup = malop.get('group', '') + + severity = malop.get('severity', '') + incident = { - 'rawJSON': json.dumps(malop), + 'rawjson': json.dumps(malop), 'name': 'Cybereason Malop ' + guid_string, + 'dbotmirrorid': guid_string, + 'CustomFields': { + 'malopcreationtime': malopCreationTime, + 'malopupdatetime': malopUpdateTime, + 'maloprootcauseelementname': rootCauseElementName, + 'maloprootcauseelementtype': rootCauseElementType, + 'malopseverity': severity, + 'malopdetectiontype': detectionType, + 'malopedr': isEdr, + 'malopurl': link, + 'malopgroup': malopGroup + }, 'labels': [{'type': 'GUID', 'value': guid_string}], 'status': status } @@ -1543,7 +1595,15 @@ def fetch_incidents(client: Client): if int(malop_update_time) > int(max_update_time): max_update_time = malop_update_time - incident = malop_to_incident(malop) + guid_string = malop.get('guidString', '') + if not guid_string: + guid_string = malop.get('guid', '') + + try: + incident = malop_to_incident(malop) + except Exception: + demisto.debug(f"edr malop got failed to convert into incident : {guid_string} and malop : {malop}") + continue incidents.append(incident) # Enable Polling for Cybereason EPP Malops @@ -1556,7 +1616,15 @@ def fetch_incidents(client: Client): if malop_update_time > max_update_time: max_update_time = malop_update_time - incident = malop_to_incident(non_edr_malops) + guid_string = malop.get('guidString', '') + if not guid_string: + guid_string = malop.get('guid', '') + + try: + incident = malop_to_incident(non_edr_malops) + except Exception: + demisto.debug(f"non edr malop got failed to convert into incident : {guid_string} and malop : {non_edr_malops}") + continue incidents.append(incident) demisto.debug(f"Fetching the length of incidents list if epp in enabled : {len(incidents)}") @@ -2214,4 +2282,4 @@ def main(): if __name__ in ('__main__', 'builtin', 'builtins'): - main() + main() \ No newline at end of file diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index f1ec29a76a81..a77254eab4f9 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -977,7 +977,7 @@ def test_malop_to_incident(mocker): } command_output = malop_to_incident(args) - assert ((command_output['name'] == "Cybereason Malop 12345A") and (command_output['status'] == 0)) + assert ((command_output['name'] == "Cybereason Malop 12345A") and (command_output['status'] == 1)) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") From eb9c29cda789dd9f8e8744e5a75fe95b76059f8f Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 14:50:19 +0530 Subject: [PATCH 09/26] pre-commit resolution --- Packs/Cybereason/Integrations/Cybereason/Cybereason.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 46a576748703..307dbf9fc94c 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -665,15 +665,17 @@ def malop_processes_command(client: Client, args: dict): malop_guids = args.get('malopGuids') machine_name = str(args.get('machineName')) date_time = str(args.get('dateTime')) - + + milliseconds = 0 filter_input = [] + if date_time != 'None': date_time_parser = dateparser.parse(date_time) if not date_time_parser: - date_time_parser = dateparser.parse('Fri, 12 Dec 2010') demisto.info("Returning all the processes since the entered date is not valid.") - date_time_parser = date_time_parser.timestamp() - milliseconds = int(date_time_parser * 1000) + if date_time_parser: + date_time_parser = date_time_parser.timestamp() + milliseconds = int(date_time_parser * 1000) filter_input = [{"facetName": "creationTime", "filterType": "GreaterThan", "values": [milliseconds], "isResult": True}] if isinstance(malop_guids, str): From 1d9628f4192da379d8b5af462234c191d2a89fb9 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 16:37:05 +0530 Subject: [PATCH 10/26] precommit resolution --- .../Integrations/Cybereason/Cybereason.py | 46 +++++++++++++------ .../Cybereason/Cybereason_test.py | 2 +- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 307dbf9fc94c..48663ff35738 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -161,6 +161,7 @@ def cybereason_api_call( error_msg = 'Authentication failed, verify the credentials are correct.' raise ValueError( f'Failed to process the API response. {str(error_msg)} {str(error_content)} - {str(e)}') + return None def error_handler(self, res: requests.Response): # Handle error responses gracefully @@ -416,6 +417,7 @@ def query_connections_command(client: Client, args: dict): outputs_prefix='Cybereason.Connection', outputs_key_field='Name', outputs=context) + return None def query_connections(client: Client, machine: str, ip: str, filter_input: str) -> dict: @@ -665,17 +667,17 @@ def malop_processes_command(client: Client, args: dict): malop_guids = args.get('malopGuids') machine_name = str(args.get('machineName')) date_time = str(args.get('dateTime')) - + milliseconds = 0 filter_input = [] - + if date_time != 'None': date_time_parser = dateparser.parse(date_time) if not date_time_parser: demisto.info("Returning all the processes since the entered date is not valid.") if date_time_parser: - date_time_parser = date_time_parser.timestamp() - milliseconds = int(date_time_parser * 1000) + epoch_time = date_time_parser.timestamp() + milliseconds = int(epoch_time) * 1000 filter_input = [{"facetName": "creationTime", "filterType": "GreaterThan", "values": [milliseconds], "isResult": True}] if isinstance(malop_guids, str): @@ -919,6 +921,7 @@ def kill_process_command(client: Client, args: dict): action_status, ['Remediation status'])} \n Reason: {dict_safe_get( action_status, ['Reason'])} \n Remediation ID: {dict_safe_get(action_status, ['Remediation ID'])}''' raise DemistoException(failure_response) + return None else: raise DemistoException('Machine must be connected to Cybereason in order to perform this action.') @@ -943,6 +946,7 @@ def quarantine_file_command(client: Client, args: dict): action_status, ['Remediation status'])} \n Reason: {dict_safe_get( action_status, ['Reason'])} \n Remediation ID: {dict_safe_get(action_status, ['Remediation ID'])}''' raise DemistoException(failure_response) + return None else: raise DemistoException('Machine must be connected to Cybereason in order to perform this action.') @@ -967,6 +971,7 @@ def unquarantine_file_command(client: Client, args: dict): action_status, ['Remediation status'])} \n Reason: {dict_safe_get( action_status, ['Reason'])} \n Remediation ID: {dict_safe_get(action_status, ['Remediation ID'])}''' raise DemistoException(failure_response) + return None else: raise DemistoException('Machine must be connected to Cybereason in order to perform this action.') @@ -991,6 +996,7 @@ def block_file_command(client: Client, args: dict): action_status, ['Remediation status'])} \n Reason: {dict_safe_get( action_status, ['Reason'])} \n Remediation ID: {dict_safe_get(action_status, ['Remediation ID'])}''' raise DemistoException(failure_response) + return None else: raise DemistoException('Machine must be connected to Cybereason in order to perform this action.') @@ -1015,6 +1021,7 @@ def delete_registry_key_command(client: Client, args: dict): action_status, ['Remediation status'])} \n Reason: {dict_safe_get( action_status, ['Reason'])} \n Remediation ID: {dict_safe_get(action_status, ['Remediation ID'])}''' raise DemistoException(failure_response) + return None else: raise DemistoException('Machine must be connected to Cybereason in order to perform this action.') @@ -1039,6 +1046,7 @@ def kill_prevent_unsuspend_command(client: Client, args: dict): action_status, ['Remediation status'])} \n" Reason: {dict_safe_get( action_status, ['Reason'])} \n Remediation ID: {dict_safe_get(action_status, ['Remediation ID'])}''' raise DemistoException(failure_response) + return None else: raise DemistoException('Machine must be connected to Cybereason in order to perform this action.') @@ -1063,6 +1071,7 @@ def unsuspend_process_command(client: Client, args: dict): action_status, ['Remediation status'])} \n Reason: {dict_safe_get( action_status, ['Reason'])} \n Remediation ID: {dict_safe_get(action_status, ['Remediation ID'])}''' raise DemistoException(failure_response) + return None else: raise DemistoException('Machine must be connected to Cybereason in order to perform this action.') @@ -1216,6 +1225,7 @@ def query_file_command(client: Client, args: dict) -> Any: outputs=cybereason_outputs) else: raise DemistoException('No results found.') + return None def query_file(client: Client, filters: list) -> dict: @@ -1306,6 +1316,7 @@ def query_domain_command(client: Client, args: dict) -> Any: outputs=cybereason_outputs) else: raise DemistoException('No results found.') + return None def query_domain(client: Client, filters: list) -> dict: @@ -1367,6 +1378,7 @@ def query_user_command(client: Client, args: dict): outputs=cybereason_outputs) else: raise DemistoException('No results found.') + return None def query_user(client: Client, filters: list) -> dict: @@ -1516,22 +1528,24 @@ def malop_to_incident(malop: str) -> dict: if malop.get('elementValues'): if malop.get('elementValues', {}).get('rootCauseElements', {}).get('elementValues', ''): - rootCauseElementName = (malop.get('elementValues', {}).get('rootCauseElements', {}).get('elementValues', '')[0]).get('name', '') - rootCauseElementType = (malop.get('elementValues', {}).get('rootCauseElements', {}).get('elementValues', '')[0]).get('elementType', '') + rootCauseElementName = (malop.get('elementValues', {}).get('rootCauseElements', {}).get('elementValues', + '')[0]).get('name', '') + rootCauseElementType = (malop.get('elementValues', {}).get('rootCauseElements', {}).get('elementValues', '')[0] + ).get('elementType', '') else: rootCauseElementName = '' rootCauseElementType = '' else: - rootCauseElementName = malop.get('primaryRootCauseName' , '') + rootCauseElementName = malop.get('primaryRootCauseName', '') rootCauseElementType = malop.get('rootCauseElementType', '') if malop.get('malopDetectionType'): detectionType = malop.get('malopDetectionType', '') else: - detectionType = (malop.get('simpleValues', {}).get('detectionType', {}).get('values', [''])[0]) + detectionType = (malop.get('simpleValues', {}).get('detectionType', {}).get('values', [''])[0]) + + malopGroup = malop.get('group', '') - malopGroup = malop.get('group', '') - severity = malop.get('severity', '') incident = { @@ -1550,7 +1564,7 @@ def malop_to_incident(malop: str) -> dict: 'malopgroup': malopGroup }, 'labels': [{'type': 'GUID', 'value': guid_string}], - 'status': status } + 'status': status} return incident @@ -1600,7 +1614,7 @@ def fetch_incidents(client: Client): guid_string = malop.get('guidString', '') if not guid_string: guid_string = malop.get('guid', '') - + try: incident = malop_to_incident(malop) except Exception: @@ -1621,7 +1635,7 @@ def fetch_incidents(client: Client): guid_string = malop.get('guidString', '') if not guid_string: guid_string = malop.get('guid', '') - + try: incident = malop_to_incident(non_edr_malops) except Exception: @@ -1807,6 +1821,7 @@ def start_fetchfile_command(client: Client, args: dict): return CommandResults(readable_output="Successfully started fetching file for the given malop") except Exception: raise Exception("Failed to start fetch file process") + return None def start_fetchfile(client: Client, element_id: str, user_name: str) -> dict: @@ -1859,7 +1874,7 @@ def get_batch_id(client: Client, suspect_files_guids: dict) -> list: for suspect_file in list(suspect_files_guids.keys()): malop_comment = f'Could not download the file {suspect_file} from source machine, even after waiting for 80 seconds.' demisto.info(malop_comment) - + if new_malop_comments == []: raise DemistoException(malop_comment) else: @@ -1912,6 +1927,7 @@ def malware_query_command(client: Client, args: dict): if limit_range > 0: filter_response = malware_query_filter(client, needs_attention, malware_type, malware_status, time_stamp, limit_range) return CommandResults(raw_response=filter_response) + return None else: raise DemistoException("Limit cannot be zero or a negative number.") @@ -2284,4 +2300,4 @@ def main(): if __name__ in ('__main__', 'builtin', 'builtins'): - main() \ No newline at end of file + main() diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index a77254eab4f9..85100a731f2e 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -977,7 +977,7 @@ def test_malop_to_incident(mocker): } command_output = malop_to_incident(args) - assert ((command_output['name'] == "Cybereason Malop 12345A") and (command_output['status'] == 1)) + all((command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1)) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") From 01f5715f126cba04e8d1f2e23da5342a84ad741f Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 16:45:34 +0530 Subject: [PATCH 11/26] test file update --- Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index 85100a731f2e..edea83367cc0 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -977,7 +977,7 @@ def test_malop_to_incident(mocker): } command_output = malop_to_incident(args) - all((command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1)) + assert all((command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1)) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") From 99892b53891e58f6739a48f01c73393a6da3d9f4 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 16:55:34 +0530 Subject: [PATCH 12/26] cybereason_test file fix --- Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index edea83367cc0..49466c4dfc3d 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -977,7 +977,7 @@ def test_malop_to_incident(mocker): } command_output = malop_to_incident(args) - assert all((command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1)) + assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1)]) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") From 071bfc1453b52124314bdcde62055485c3fed65c Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 17:07:02 +0530 Subject: [PATCH 13/26] malop to incident test case update --- Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index 49466c4dfc3d..f2ec26142631 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -977,7 +977,7 @@ def test_malop_to_incident(mocker): } command_output = malop_to_incident(args) - assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1)]) + assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 0)]) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") From 61899f54a3ee9dccc156449d1e04b81935462914 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 17:29:33 +0530 Subject: [PATCH 14/26] adding test cases to complete the checks --- .../Cybereason/Cybereason_test.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index f2ec26142631..ecd1b1d104ef 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -982,6 +982,37 @@ def test_malop_to_incident(mocker): with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") assert exc_info.match(r"Cybereason raw response is not valid") + + +def test_malop_to_incident_status(mocker): + from Cybereason import malop_to_incident + args = { + "guidString": "12345A", + "status": "Remediated" + } + command_output = malop_to_incident(args) + + assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1)]) + + with pytest.raises(Exception) as exc_info: + command_output = malop_to_incident("args") + assert exc_info.match(r"Cybereason raw response is not valid") + + +def test_malop_to_incident_status_closed(mocker): + from Cybereason import malop_to_incident + args = { + "guidString": "12345A", + "status": "Closed" + } + command_output = malop_to_incident(args) + + assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 2)]) + + with pytest.raises(Exception) as exc_info: + command_output = malop_to_incident("args") + assert exc_info.match(r"Cybereason raw response is not valid") + def test_get_pylum_id(mocker): From 657f04c3f05a351ae36d0b85580a1dab36213e76 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 17:42:18 +0530 Subject: [PATCH 15/26] adding test case coverage --- .../Cybereason/Cybereason_test.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index ecd1b1d104ef..3ed315278a52 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -982,23 +982,29 @@ def test_malop_to_incident(mocker): with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") assert exc_info.match(r"Cybereason raw response is not valid") - + def test_malop_to_incident_status(mocker): from Cybereason import malop_to_incident args = { "guidString": "12345A", - "status": "Remediated" - } + "status": "Remediated", + 'simpleValues': { + 'creationTime': { + 'values': ["2345"] + } + } + } command_output = malop_to_incident(args) - assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1)]) + assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1), + (command_output['CustomFields']['malopcreationtime'])]) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") assert exc_info.match(r"Cybereason raw response is not valid") - - + + def test_malop_to_incident_status_closed(mocker): from Cybereason import malop_to_incident args = { @@ -1014,7 +1020,6 @@ def test_malop_to_incident_status_closed(mocker): assert exc_info.match(r"Cybereason raw response is not valid") - def test_get_pylum_id(mocker): from Cybereason import get_pylum_id, Client HEADERS = {'Content-Type': 'application/json', 'Connection': 'close'} From e6ee17f6942adbb1919d2c78907d1350e493fe93 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 19:52:08 +0530 Subject: [PATCH 16/26] adding more test coverage --- .../Cybereason/Cybereason_test.py | 72 +++++++++---------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index 3ed315278a52..05af73eb3fcb 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -973,47 +973,45 @@ def test_malop_to_incident(mocker): from Cybereason import malop_to_incident args = { "guidString": "12345A", - "status": 1 - } - command_output = malop_to_incident(args) - - assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 0)]) - - with pytest.raises(Exception) as exc_info: - command_output = malop_to_incident("args") - assert exc_info.match(r"Cybereason raw response is not valid") - - -def test_malop_to_incident_status(mocker): - from Cybereason import malop_to_incident - args = { - "guidString": "12345A", - "status": "Remediated", - 'simpleValues': { - 'creationTime': { - 'values': ["2345"] + "status": 1, + "simpleValues": { + "detectionType": { + "values": [ + "EXTENSION_MANIPULATION" + ] + }, + "creationTime": { + "values": [ + "1721798910159" + ] + }, + "malopLastUpdateTime": { + "values": [ + "1728032260900" + ] + }, + }, + "elementValues": { + "rootCauseElements": { + "elementValues": [ + { + "elementType": "File", + "name": "avg_secure_browser_setup.pdf.exe" + } + ] } - } - } - command_output = malop_to_incident(args) - - assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1), - (command_output['CustomFields']['malopcreationtime'])]) - - with pytest.raises(Exception) as exc_info: - command_output = malop_to_incident("args") - assert exc_info.match(r"Cybereason raw response is not valid") - - -def test_malop_to_incident_status_closed(mocker): - from Cybereason import malop_to_incident - args = { - "guidString": "12345A", - "status": "Closed" + }, + 'isEdr': True } command_output = malop_to_incident(args) - assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 2)]) + assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 0), + (command_output['CustomFields']['malopcreationtime'] == "1721798910159"), + (command_output['CustomFields']['malopupdatetime'] == "1728032260900"), + (command_output['CustomFields']['malopdetectiontype'] == "EXTENSION_MANIPULATION"), + (command_output['CustomFields']['maloprootcauseelementname'] == "avg_secure_browser_setup.pdf.exe"), + (command_output['CustomFields']['maloprootcauseelementtype'] == "File"), + (command_output['malopedr']), (command_output['dbotmirrorid'] == "12345A")]) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") From 0becdd333142c96f087911110f4fd49c8efde8d2 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 20:49:56 +0530 Subject: [PATCH 17/26] fixing error in test file --- Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index 05af73eb3fcb..eadb33354c10 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -1011,7 +1011,7 @@ def test_malop_to_incident(mocker): (command_output['CustomFields']['malopdetectiontype'] == "EXTENSION_MANIPULATION"), (command_output['CustomFields']['maloprootcauseelementname'] == "avg_secure_browser_setup.pdf.exe"), (command_output['CustomFields']['maloprootcauseelementtype'] == "File"), - (command_output['malopedr']), (command_output['dbotmirrorid'] == "12345A")]) + (command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345A")]) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") From 1db60017b4b8a1b92544899ecb32c3d17d3b7d05 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Tue, 29 Oct 2024 21:56:38 +0530 Subject: [PATCH 18/26] adding test cases --- .../Integrations/Cybereason/Cybereason.py | 4 +- .../Cybereason/Cybereason_test.py | 71 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 48663ff35738..6c9f3622a6a5 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -1512,11 +1512,9 @@ def malop_to_incident(malop: str) -> dict: if malop.get("isEdr", '') or malop.get("edr", '') or malop.get('simpleValues', ''): link = SERVER + '/#/malop/' + guid_string - else: - link = SERVER + '/#/detection-malop/' + guid_string - if malop.get("isEdr", '') or malop.get("edr", '') or malop.get('simpleValues', ''): isEdr = True else: + link = SERVER + '/#/detection-malop/' + guid_string isEdr = False if malop.get('simpleValues'): diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index eadb33354c10..b4fd6fc8b425 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -1016,6 +1016,77 @@ def test_malop_to_incident(mocker): with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") assert exc_info.match(r"Cybereason raw response is not valid") + + +def test_malop_to_incident_2(mocker): + from Cybereason import malop_to_incident + args = { + "guidString": "12345A", + "status": "UNREAD", + "simpleValues": { + "detectionType": { + "values": [ + "ABCD" + ] + }, + "creationTime": { + "values": [ + "1721" + ] + }, + "malopLastUpdateTime": { + "values": [ + "17280" + ] + }, + }, + "elementValues": { + "rootCauseElements": { + "elementValues": [ + { + "elementType": "ABCD", + "name": "fileName" + } + ] + } + } + } + command_output = malop_to_incident(args) + + assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 0), + (command_output['CustomFields']['malopcreationtime'] == "1721"), + (command_output['CustomFields']['malopupdatetime'] == "17280"), + (command_output['CustomFields']['malopdetectiontype'] == "ABCD"), + (command_output['CustomFields']['maloprootcauseelementname'] == "fileName"), + (command_output['CustomFields']['maloprootcauseelementtype'] == "ABCD"), + (command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345A")]) + + with pytest.raises(Exception) as exc_info: + command_output = malop_to_incident("args") + assert exc_info.match(r"Cybereason raw response is not valid") + + +def test_malop_to_incident_3(mocker): + from Cybereason import malop_to_incident + args = { + "guidString": "12345A", + "status": "Remediated", + "malopDetectionType": "ABCD", + "creationTime": "23456", + "lastUpdateTime": "6789", + "edr": False + } + command_output = malop_to_incident(args) + + assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1), + (command_output['CustomFields']['malopcreationtime'] == "23456"), + (command_output['CustomFields']['malopupdatetime'] == "6789"), + (command_output['CustomFields']['malopdetectiontype'] == "ABCD"), + (not command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345A")]) + + with pytest.raises(Exception) as exc_info: + command_output = malop_to_incident("args") + assert exc_info.match(r"Cybereason raw response is not valid") def test_get_pylum_id(mocker): From f1217817bec40681802d4e04bf8a0152e1480157 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Wed, 30 Oct 2024 00:50:10 +0530 Subject: [PATCH 19/26] Test Case for pre commit hooks --- .../Cybereason/Cybereason_test.py | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index b4fd6fc8b425..7c701572aee1 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -1016,12 +1016,12 @@ def test_malop_to_incident(mocker): with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") assert exc_info.match(r"Cybereason raw response is not valid") - + def test_malop_to_incident_2(mocker): from Cybereason import malop_to_incident args = { - "guidString": "12345A", + "guidString": "12345B", "status": "UNREAD", "simpleValues": { "detectionType": { @@ -1053,23 +1053,23 @@ def test_malop_to_incident_2(mocker): } command_output = malop_to_incident(args) - assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 0), + assert all([(command_output['name'] == "Cybereason Malop 12345B"), (command_output['status'] == 0), (command_output['CustomFields']['malopcreationtime'] == "1721"), (command_output['CustomFields']['malopupdatetime'] == "17280"), (command_output['CustomFields']['malopdetectiontype'] == "ABCD"), (command_output['CustomFields']['maloprootcauseelementname'] == "fileName"), (command_output['CustomFields']['maloprootcauseelementtype'] == "ABCD"), - (command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345A")]) + (command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345B")]) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") assert exc_info.match(r"Cybereason raw response is not valid") - - + + def test_malop_to_incident_3(mocker): from Cybereason import malop_to_incident args = { - "guidString": "12345A", + "guidString": "12345C", "status": "Remediated", "malopDetectionType": "ABCD", "creationTime": "23456", @@ -1078,11 +1078,34 @@ def test_malop_to_incident_3(mocker): } command_output = malop_to_incident(args) - assert all([(command_output['name'] == "Cybereason Malop 12345A"), (command_output['status'] == 1), + assert all([(command_output['name'] == "Cybereason Malop 12345C"), (command_output['status'] == 1), + (command_output['CustomFields']['malopcreationtime'] == "23456"), + (command_output['CustomFields']['malopupdatetime'] == "6789"), + (command_output['CustomFields']['malopdetectiontype'] == "ABCD"), + (not command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345C")]) + + with pytest.raises(Exception) as exc_info: + command_output = malop_to_incident("args") + assert exc_info.match(r"Cybereason raw response is not valid") + + +def test_malop_to_incident_4(mocker): + from Cybereason import malop_to_incident + args = { + "guidString": "12345D", + "status": "RESOLVED", + "malopDetectionType": "ABCD", + "creationTime": "23456", + "lastUpdateTime": "6789", + "edr": True + } + command_output = malop_to_incident(args) + + assert all([(command_output['name'] == "Cybereason Malop 12345D"), (command_output['status'] == 2), (command_output['CustomFields']['malopcreationtime'] == "23456"), (command_output['CustomFields']['malopupdatetime'] == "6789"), (command_output['CustomFields']['malopdetectiontype'] == "ABCD"), - (not command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345A")]) + (command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345D")]) with pytest.raises(Exception) as exc_info: command_output = malop_to_incident("args") From 2dfebf4004adc515315da814786fc974797956e1 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Wed, 30 Oct 2024 04:51:13 +0530 Subject: [PATCH 20/26] More Test Cases for pre commit test criteria --- .../Cybereason/Cybereason_test.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index 7c701572aee1..9dee7f9f4ff6 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -1112,6 +1112,48 @@ def test_malop_to_incident_4(mocker): assert exc_info.match(r"Cybereason raw response is not valid") +def test_malop_to_incident_5(mocker): + from Cybereason import malop_to_incident + args = { + "guidString": "12345D", + "status": "", + "malopDetectionType": "ABCD", + "creationTime": "23456", + "lastUpdateTime": "6789" + } + command_output = malop_to_incident(args) + + assert all([(command_output['name'] == "Cybereason Malop 12345D"), (command_output['status'] == 0), + (command_output['CustomFields']['malopcreationtime'] == "23456"), + (command_output['CustomFields']['malopupdatetime'] == "6789"), + (command_output['CustomFields']['malopdetectiontype'] == "ABCD"), + (not command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345D")]) + + with pytest.raises(Exception) as exc_info: + command_output = malop_to_incident("args") + assert exc_info.match(r"Cybereason raw response is not valid") + + +def test_malop_to_incident_6(mocker): + from Cybereason import malop_to_incident + args = { + "guidString": "12345D", + "creationTime": 23456, + "lastUpdateTime": 6789 + } + command_output = malop_to_incident(args) + + assert all([(command_output['name'] == "Cybereason Malop 12345D"), (command_output['status'] == 0), + (command_output['CustomFields']['malopcreationtime'] == "23456"), + (command_output['CustomFields']['malopupdatetime'] == "6789"), + (command_output['CustomFields']['malopdetectiontype'] == ""), + (not command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345D")]) + + with pytest.raises(Exception) as exc_info: + command_output = malop_to_incident("args") + assert exc_info.match(r"Cybereason raw response is not valid") + + def test_get_pylum_id(mocker): from Cybereason import get_pylum_id, Client HEADERS = {'Content-Type': 'application/json', 'Connection': 'close'} From 50454d0cb756117075a34aecc5057e2b08e7e701 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Wed, 30 Oct 2024 05:30:06 +0530 Subject: [PATCH 21/26] error fix in for the test cases --- Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index 9dee7f9f4ff6..e697f2daebcd 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -1116,7 +1116,7 @@ def test_malop_to_incident_5(mocker): from Cybereason import malop_to_incident args = { "guidString": "12345D", - "status": "", + "status": "123", "malopDetectionType": "ABCD", "creationTime": "23456", "lastUpdateTime": "6789" @@ -1138,6 +1138,7 @@ def test_malop_to_incident_6(mocker): from Cybereason import malop_to_incident args = { "guidString": "12345D", + "status": 3, "creationTime": 23456, "lastUpdateTime": 6789 } From db5486c8e922a79e941344258752e617192ea5b9 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Wed, 30 Oct 2024 06:09:28 +0530 Subject: [PATCH 22/26] test case improvement --- Packs/Cybereason/Integrations/Cybereason/Cybereason.py | 1 + Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 6c9f3622a6a5..cd8a6c067349 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -1493,6 +1493,7 @@ def malop_to_incident(malop: str) -> dict: raise ValueError("Cybereason raw response is not valid, malop is not dict") status = 0 + malopStatus = "" if malop.get('status', ''): malopStatus = (malop.get('status', 'UNREAD')) elif malop.get('simpleValues', ''): diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index e697f2daebcd..9dee7f9f4ff6 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -1116,7 +1116,7 @@ def test_malop_to_incident_5(mocker): from Cybereason import malop_to_incident args = { "guidString": "12345D", - "status": "123", + "status": "", "malopDetectionType": "ABCD", "creationTime": "23456", "lastUpdateTime": "6789" @@ -1138,7 +1138,6 @@ def test_malop_to_incident_6(mocker): from Cybereason import malop_to_incident args = { "guidString": "12345D", - "status": 3, "creationTime": 23456, "lastUpdateTime": 6789 } From 53a8606be2b360cb0c28eaa4da6a16e8f8d602cb Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Wed, 30 Oct 2024 12:25:32 +0530 Subject: [PATCH 23/26] Increasing test case to complete the pre-commit check --- .../Cybereason/Cybereason_test.py | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py index 9dee7f9f4ff6..9d3fea6e3fc5 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason_test.py @@ -1154,6 +1154,56 @@ def test_malop_to_incident_6(mocker): assert exc_info.match(r"Cybereason raw response is not valid") +def test_malop_to_incident_7(mocker): + from Cybereason import malop_to_incident + args = { + "guidString": "12345B", + "simpleValues": { + "detectionType": { + "values": [ + "ABCD" + ] + }, + "creationTime": { + "values": [ + "1721" + ] + }, + "malopLastUpdateTime": { + "values": [ + "17280" + ] + }, + "managementStatus": { + "values": ["REOPEN"] + } + }, + "elementValues": { + "rootCauseElements": { + "elementValues": [ + { + "elementType": "ABCD", + "name": "fileName" + } + ] + } + } + } + command_output = malop_to_incident(args) + + assert all([(command_output['name'] == "Cybereason Malop 12345B"), (command_output['status'] == 0), + (command_output['CustomFields']['malopcreationtime'] == "1721"), + (command_output['CustomFields']['malopupdatetime'] == "17280"), + (command_output['CustomFields']['malopdetectiontype'] == "ABCD"), + (command_output['CustomFields']['maloprootcauseelementname'] == "fileName"), + (command_output['CustomFields']['maloprootcauseelementtype'] == "ABCD"), + (command_output['CustomFields']['malopedr']), (command_output['dbotmirrorid'] == "12345B")]) + + with pytest.raises(Exception) as exc_info: + command_output = malop_to_incident("args") + assert exc_info.match(r"Cybereason raw response is not valid") + + def test_get_pylum_id(mocker): from Cybereason import get_pylum_id, Client HEADERS = {'Content-Type': 'application/json', 'Connection': 'close'} From 1c4599fe44cb1faa7b884a375f0b6bc9cf3d3577 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Wed, 30 Oct 2024 18:21:37 +0530 Subject: [PATCH 24/26] autopep8 error resolution --- .../CybereasonPreProcessingExample.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample.py b/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample.py index 1d4bd9b8248b..270918b74426 100644 --- a/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample.py +++ b/Packs/Cybereason/Scripts/CybereasonPreProcessingExample/CybereasonPreProcessingExample.py @@ -1,9 +1,8 @@ import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 -from typing import Dict -def get_guid_from_system_incident(incident: Dict[str, Any]) -> str: +def get_guid_from_system_incident(incident: dict[str, Any]) -> str: malop_guid = '' for label in incident['labels']: if label['type'] == 'GUID': @@ -17,9 +16,9 @@ def get_guid_from_system_incident(incident: Dict[str, Any]) -> str: for inc in incident: malop_guid = get_guid_from_system_incident(inc) response = execute_command( - 'getIncidents', - {'query': f'name:"Cybereason Malop {malop_guid}"'} - ) + 'getIncidents', + {'query': f'name:"Cybereason Malop {malop_guid}"'} + ) malop_incident = response['data'] demisto.debug(f"malop incident - {malop_incident}") if malop_incident: From 097c188857237e02bb61af50b7c0120dcfa15206 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Mon, 4 Nov 2024 17:31:49 +0530 Subject: [PATCH 25/26] readme file --- .../Integrations/Cybereason/README.md | 32 +++++++++++++++++++ Packs/Cybereason/ReleaseNotes/2_1_18.md | 21 ++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 Packs/Cybereason/ReleaseNotes/2_1_18.md diff --git a/Packs/Cybereason/Integrations/Cybereason/README.md b/Packs/Cybereason/Integrations/Cybereason/README.md index 35397cb19c95..7d0795bfb1e2 100644 --- a/Packs/Cybereason/Integrations/Cybereason/README.md +++ b/Packs/Cybereason/Integrations/Cybereason/README.md @@ -21,6 +21,38 @@ This integration was integrated and tested with version 21.2 of Cybereason 4. Click **Test** to validate the URLs, token, and connection. +## Cybereason MalOp to XSOAR Incident Map + +This involves the mapping of response fields to XSOAR incidents, enhancing the ability to manage and track security incidents effectively. + +### Overview + +1. **Incident Mapping:** The integration maps specific response fields to corresponding incident fields within XSOAR, ensuring that all relevant information is captured accurately. +2. **Custom Fields:** In addition to standard incident fields, custom fields have been introduced to accommodate unique data requirements specific to our workflow. These fields provide flexibility and enhance the granularity of the incident information. +- `malopcreationtime` +- `malopupdatetime` +- `maloprootcauseelementname` +- `maloprootcauseelementtype` +- `malopseverity` +- `malopdetectiontype` +- `malopedr` +- `malopurl` +- `malopgroup` + +These custom fields provide flexibility and enhance the granularity of the incident information. + +### Fetchin MalOps + +The functionality for fetching MalOps is implemented through the `fetch_incidents` function. This function is responsible for retrieving MalOps and subsequently converting them into XSOAR incidents. + +* **Conversion Process:** The conversion from MalOps to incidents is handled by the `malop_to_incident` function. This function processes MalOps one by one, ensuring each is correctly mapped to its corresponding incident structure. + +### Usage + +1. **Configure Custom Fields:** Ensure that all custom fields are properly set up in XSOAR before running the fetch function. +2. **Run Fetch Incidents:** Execute the `fetch_incidents` function to initiate the retrieval and conversion process. +3. **Monitor Incidents:** Once the MalOps are converted, they will appear as incidents in XSOAR, allowing for effective incident management. + ## Commands You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. diff --git a/Packs/Cybereason/ReleaseNotes/2_1_18.md b/Packs/Cybereason/ReleaseNotes/2_1_18.md new file mode 100644 index 000000000000..535d51bafff5 --- /dev/null +++ b/Packs/Cybereason/ReleaseNotes/2_1_18.md @@ -0,0 +1,21 @@ + +#### Integrations + +##### Cybereason + +- **Custom Fields Added**: Introduced the following custom fields for enhanced incident information: +- `malopcreationtime` +- `malopupdatetime` +- `maloprootcauseelementname` +- `maloprootcauseelementtype` +- `malopseverity` +- `malopdetectiontype` +- `malopedr` +- `malopurl` +- `malopgroup` + +#### Scripts + +##### CybereasonPreProcessingExample + +- Fixed preprocessing script to deal with incident duplication. From ae9668f4e2e480a35e7709ad6c960ddd29f5e500 Mon Sep 17 00:00:00 2001 From: sudhanshu-metron Date: Mon, 4 Nov 2024 17:36:51 +0530 Subject: [PATCH 26/26] metadata file --- Packs/Cybereason/pack_metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/Cybereason/pack_metadata.json b/Packs/Cybereason/pack_metadata.json index 1890c0d2c7b0..810a89ffba69 100644 --- a/Packs/Cybereason/pack_metadata.json +++ b/Packs/Cybereason/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Cybereason", "description": "Endpoint detection and response to manage and query malops, connections and processes.", "support": "partner", - "currentVersion": "2.1.17", + "currentVersion": "2.1.18", "author": "Cybereason", "url": "https://nest.cybereason.com/", "email": "support@cybereason.com",