diff --git a/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy.py b/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy.py index c6eb8182f878..0243461ce0a2 100644 --- a/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy.py +++ b/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy.py @@ -2053,11 +2053,8 @@ def parse_batch_of_results(current_batch_of_results, max_results_to_add, app): batch_dbot_scores = [] results_reader = results.JSONResultsReader(io.BufferedReader(ResponseReaderWrapper(current_batch_of_results))) for item in results_reader: - if isinstance(item, results.Message): - if "Error in" in item.message: - raise ValueError(item.message) - demisto.debug(f"Splunk-SDK message: {item.message}") - parsed_batch_results.append(convert_to_str(item.message)) + if handle_message(item): + continue elif isinstance(item, dict): if demisto.get(item, 'host'): @@ -2642,7 +2639,7 @@ def handle_message(item: results.Message | dict) -> bool: """ if isinstance(item, results.Message): - demisto.debug(f"Splunk-SDK message: {item.message}") + demisto.info(f"Splunk-SDK message: {item.message}") return True return False diff --git a/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy.yml b/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy.yml index 65dd83ca1281..9dd5d26a6695 100644 --- a/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy.yml +++ b/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy.yml @@ -626,7 +626,7 @@ script: - contextPath: Splunk.UserMapping.SplunkUser description: Splunk user mapping. type: String - dockerimage: demisto/splunksdk-py3:1.0.0.66149 + dockerimage: demisto/splunksdk-py3:1.0.0.66897 isfetch: true ismappable: true isremotesyncin: true diff --git a/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy_test.py b/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy_test.py index 549cf087f564..ce96897a9953 100644 --- a/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy_test.py +++ b/Packs/SplunkPy/Integrations/SplunkPy/SplunkPy_test.py @@ -95,58 +95,60 @@ '"a1d57ed2-1fe6-4800-be7a-26cd89bf686d","SESSIONID":"stY46PpweFToT5JX04CZGMeCvP8=","ORGOID":' \ '"G2SY6MR3ATKA232T","AOID":"G2N2TJETBRAAXAAA","MSGID":"a1d57ed2-1fe6-0000-be7a-26cd89bf686d"}' -SAMPLE_RESPONSE = [{ - '_bkt': 'notable~668~66D21DF4-F4FD-4886-A986-82E72ADCBFE9', - '_cd': '668:17198', - '_indextime': '1596545116', - '_raw': '1596545116, search_name="Endpoint - Recurring Malware Infection - Rule", count="17", ' - 'day_count="8", dest="ACME-workstation-012", info_max_time="1596545100.000000000", ' - 'info_min_time="1595939700.000000000", info_search_time="1596545113.965466000", ' - 'signature="Trojan.Gen.2"', - '_serial': '50', - '_si': ['ip-172-31-44-193', 'notable'], - '_sourcetype': 'stash', - '_time': '2020-08-04T05:45:16.000-07:00', - 'dest': 'ACME-workstation-012', - 'dest_asset_id': '028877d3c80cb9d87900eb4f9c9601ea993d9b63', - 'dest_asset_tag': ['cardholder', 'pci', 'americas'], - 'dest_bunit': 'americas', - 'dest_category': ['cardholder', 'pci'], - 'dest_city': 'Pleasanton', - 'dest_country': 'USA', - 'dest_ip': '192.168.3.12', - 'dest_is_expected': 'TRUE', - 'dest_lat': '37.694452', - 'dest_long': '-121.894461', - 'dest_nt_host': 'ACME-workstation-012', - 'dest_pci_domain': ['trust', 'cardholder'], - 'dest_priority': 'medium', - 'dest_requires_av': 'TRUE', - 'dest_risk_object_type': 'system', - 'dest_risk_score': '15680', - 'dest_should_timesync': 'TRUE', - 'dest_should_update': 'TRUE', - 'host': 'ip-172-31-44-193', - 'host_risk_object_type': 'system', - 'host_risk_score': '0', - 'index': 'notable', - 'linecount': '1', - 'priorities': 'medium', - 'priority': 'medium', - 'risk_score': '15680', - 'rule_description': 'Endpoint - Recurring Malware Infection - Rule', - 'rule_name': 'Endpoint - Recurring Malware Infection - Rule', - 'rule_title': 'Endpoint - Recurring Malware Infection - Rule', - 'security_domain': 'Endpoint - Recurring Malware Infection - Rule', - 'severity': 'unknown', - 'signature': 'Trojan.Gen.2', - 'source': 'Endpoint - Recurring Malware Infection - Rule', - 'sourcetype': 'stash', - 'splunk_server': 'ip-172-31-44-193', - 'urgency': 'low', - 'owner': 'unassigned', - 'event_id': '66D21DF4-F4FD-4886-A986-82E72ADCBFE9@@notable@@5aa44496ec8e5cf45c78ab230189a4ca', -}] +SAMPLE_RESPONSE = [ + results.Message("INFO-TEST", "test message"), + { + '_bkt': 'notable~668~66D21DF4-F4FD-4886-A986-82E72ADCBFE9', + '_cd': '668:17198', + '_indextime': '1596545116', + '_raw': '1596545116, search_name="Endpoint - Recurring Malware Infection - Rule", count="17", ' + 'day_count="8", dest="ACME-workstation-012", info_max_time="1596545100.000000000", ' + 'info_min_time="1595939700.000000000", info_search_time="1596545113.965466000", ' + 'signature="Trojan.Gen.2"', + '_serial': '50', + '_si': ['ip-172-31-44-193', 'notable'], + '_sourcetype': 'stash', + '_time': '2020-08-04T05:45:16.000-07:00', + 'dest': 'ACME-workstation-012', + 'dest_asset_id': '028877d3c80cb9d87900eb4f9c9601ea993d9b63', + 'dest_asset_tag': ['cardholder', 'pci', 'americas'], + 'dest_bunit': 'americas', + 'dest_category': ['cardholder', 'pci'], + 'dest_city': 'Pleasanton', + 'dest_country': 'USA', + 'dest_ip': '192.168.3.12', + 'dest_is_expected': 'TRUE', + 'dest_lat': '37.694452', + 'dest_long': '-121.894461', + 'dest_nt_host': 'ACME-workstation-012', + 'dest_pci_domain': ['trust', 'cardholder'], + 'dest_priority': 'medium', + 'dest_requires_av': 'TRUE', + 'dest_risk_object_type': 'system', + 'dest_risk_score': '15680', + 'dest_should_timesync': 'TRUE', + 'dest_should_update': 'TRUE', + 'host': 'ip-172-31-44-193', + 'host_risk_object_type': 'system', + 'host_risk_score': '0', + 'index': 'notable', + 'linecount': '1', + 'priorities': 'medium', + 'priority': 'medium', + 'risk_score': '15680', + 'rule_description': 'Endpoint - Recurring Malware Infection - Rule', + 'rule_name': 'Endpoint - Recurring Malware Infection - Rule', + 'rule_title': 'Endpoint - Recurring Malware Infection - Rule', + 'security_domain': 'Endpoint - Recurring Malware Infection - Rule', + 'severity': 'unknown', + 'signature': 'Trojan.Gen.2', + 'source': 'Endpoint - Recurring Malware Infection - Rule', + 'sourcetype': 'stash', + 'splunk_server': 'ip-172-31-44-193', + 'urgency': 'low', + 'owner': 'unassigned', + 'event_id': '66D21DF4-F4FD-4886-A986-82E72ADCBFE9@@notable@@5aa44496ec8e5cf45c78ab230189a4ca', + }] EXPECTED = { "action": "allowed", @@ -927,76 +929,132 @@ def test_get_last_update_in_splunk_time(last_update, demisto_params, splunk_time splunk.get_last_update_in_splunk_time(last_update) -@pytest.mark.parametrize("notable_data, func_call_kwargs, expected_closure_data", - [ - # A Notable with a "Closed" status label - ({'status_label': 'Closed', 'event_id': 'id', 'status_end': 'true'}, - {'close_incident': True, 'close_end_statuses': False, 'close_extra_labels': []}, - {'Type': EntryType.NOTE, - 'Contents': { - 'dbotIncidentClose': True, - 'closeReason': 'Notable event was closed on Splunk with status "Closed".', - }, - 'ContentsFormat': EntryFormat.JSON, - }, - ), - - # A Notable with a "New" status label (shouldn't close) - ({'status_label': 'New', 'event_id': 'id', 'status_end': 'false'}, - {'close_incident': True, 'close_end_statuses': False, 'close_extra_labels': []}, - None, - ), - - # A Notable with a custom status label that is on close_extra_labels (should close) - ({'status_label': 'Custom', 'event_id': 'id', 'status_end': 'false'}, - {'close_incident': True, 'close_end_statuses': False, 'close_extra_labels': ['Custom']}, - {'Type': EntryType.NOTE, - 'Contents': { - 'dbotIncidentClose': True, - 'closeReason': 'Notable event was closed on Splunk with status "Custom".', - }, - 'ContentsFormat': EntryFormat.JSON, - }, - ), - - # A Notable with close_extra_labels that don't include status_label (shouldn't close) - ({'status_label': 'Custom', 'event_id': 'id', 'status_end': 'false'}, - {'close_incident': True, 'close_end_statuses': False, 'close_extra_labels': ['A', 'B']}, - None, - ), - - # A Notable that has status_end as true with close_end_statuses as true (should close) - ({'status_label': 'Custom', 'event_id': 'id', 'status_end': 'true'}, - {'close_incident': True, 'close_end_statuses': True, 'close_extra_labels': []}, - {'Type': EntryType.NOTE, - 'Contents': { - 'dbotIncidentClose': True, - 'closeReason': 'Notable event was closed on Splunk with status "Custom".', - }, - 'ContentsFormat': EntryFormat.JSON, - }, - ), - - # A Notable that has status_end as true with close_end_statuses as false (shouldn't close) - ({'status_label': 'Custom', 'event_id': 'id', 'status_end': 'true'}, - {'close_incident': True, 'close_end_statuses': False, 'close_extra_labels': []}, - None, - ), - - # A Notable that is both on close_extra_labels, - # and has status_end as true with close_end_statuses as true (should close) - ({'status_label': 'Custom', 'event_id': 'id', 'status_end': 'true'}, - {'close_incident': True, 'close_end_statuses': True, 'close_extra_labels': ['Custom']}, - {'Type': EntryType.NOTE, - 'Contents': { - 'dbotIncidentClose': True, - 'closeReason': 'Notable event was closed on Splunk with status "Custom".', - }, - 'ContentsFormat': EntryFormat.JSON, - }, - ), - ]) -def test_get_remote_data_command_close_incident(mocker, notable_data: dict, +@pytest.mark.parametrize( + "notable_data, func_call_kwargs, expected_closure_data", + [ + # A Notable with a "Closed" status label + ( + [ + results.Message("INFO-TEST", "test message"), + {"status_label": "Closed", "event_id": "id", "status_end": "true"}, + ], + { + "close_incident": True, + "close_end_statuses": False, + "close_extra_labels": [], + }, + { + "Type": EntryType.NOTE, + "Contents": { + "dbotIncidentClose": True, + "closeReason": 'Notable event was closed on Splunk with status "Closed".', + }, + "ContentsFormat": EntryFormat.JSON, + }, + ), + # A Notable with a "New" status label (shouldn't close) + ( + [ + results.Message("INFO-TEST", "test message"), + {"status_label": "New", "event_id": "id", "status_end": "false"}, + ], + { + "close_incident": True, + "close_end_statuses": False, + "close_extra_labels": [], + }, + None, + ), + # A Notable with a custom status label that is on close_extra_labels (should close) + ( + [ + results.Message("INFO-TEST", "test message"), + {"status_label": "Custom", "event_id": "id", "status_end": "false"}, + ], + { + "close_incident": True, + "close_end_statuses": False, + "close_extra_labels": ["Custom"], + }, + { + "Type": EntryType.NOTE, + "Contents": { + "dbotIncidentClose": True, + "closeReason": 'Notable event was closed on Splunk with status "Custom".', + }, + "ContentsFormat": EntryFormat.JSON, + }, + ), + # A Notable with close_extra_labels that don't include status_label (shouldn't close) + ( + [ + results.Message("INFO-TEST", "test message"), + {"status_label": "Custom", "event_id": "id", "status_end": "false"}, + ], + { + "close_incident": True, + "close_end_statuses": False, + "close_extra_labels": ["A", "B"], + }, + None, + ), + # A Notable that has status_end as true with close_end_statuses as true (should close) + ( + [ + results.Message("INFO-TEST", "test message"), + {"status_label": "Custom", "event_id": "id", "status_end": "true"}, + ], + { + "close_incident": True, + "close_end_statuses": True, + "close_extra_labels": [], + }, + { + "Type": EntryType.NOTE, + "Contents": { + "dbotIncidentClose": True, + "closeReason": 'Notable event was closed on Splunk with status "Custom".', + }, + "ContentsFormat": EntryFormat.JSON, + }, + ), + # A Notable that has status_end as true with close_end_statuses as false (shouldn't close) + ( + [ + results.Message("INFO-TEST", "test message"), + {"status_label": "Custom", "event_id": "id", "status_end": "true"}, + ], + { + "close_incident": True, + "close_end_statuses": False, + "close_extra_labels": [], + }, + None, + ), + # A Notable that is both on close_extra_labels, + # and has status_end as true with close_end_statuses as true (should close) + ( + [ + results.Message("INFO-TEST", "test message"), + {"status_label": "Custom", "event_id": "id", "status_end": "true"}, + ], + { + "close_incident": True, + "close_end_statuses": True, + "close_extra_labels": ["Custom"], + }, + { + "Type": EntryType.NOTE, + "Contents": { + "dbotIncidentClose": True, + "closeReason": 'Notable event was closed on Splunk with status "Custom".', + }, + "ContentsFormat": EntryFormat.JSON, + }, + ), + ], +) +def test_get_remote_data_command_close_incident(mocker, notable_data: list[results.Message | dict], func_call_kwargs: dict, expected_closure_data: dict): class Jobs: def oneshot(self, _, output_mode: str): @@ -1011,13 +1069,13 @@ def __init__(self): mocker.patch.object(demisto, 'params', return_value={'timezone': '0'}) mocker.patch.object(demisto, 'debug') mocker.patch.object(demisto, 'info') - mocker.patch('SplunkPy.results.JSONResultsReader', return_value=[notable_data]) + mocker.patch('SplunkPy.results.JSONResultsReader', return_value=notable_data) mocker.patch.object(demisto, 'results') service = Service() splunk.get_remote_data_command(service, args, mapper=splunk.UserMappingObject(service, False), **func_call_kwargs) results = demisto.results.call_args[0][0] - expected_results = [notable_data] + expected_results = [notable_data[1]] if expected_closure_data: expected_results.append(expected_closure_data) @@ -1031,7 +1089,7 @@ def test_get_remote_data_command_with_message(mocker): Test for the get_remote_data_command function with a message. This test verifies that when the splunk-sdk returns a message, the function correctly logs the message - using demisto.debug(). + using demisto.info(). Args: mocker: The mocker object for patching and mocking. @@ -1039,15 +1097,10 @@ def test_get_remote_data_command_with_message(mocker): Returns: None """ - - class Message: - def __init__(self, message: str): - self.message = message - class Jobs: def oneshot(self, _, output_mode: str): assert output_mode == splunk.OUTPUT_MODE_JSON - return Message("test message") + return results.Message("INFO-test", "test message") class Service: def __init__(self): @@ -1060,17 +1113,16 @@ def __init__(self): "close_extra_labels": ["Custom"], "mapper": splunk.UserMappingObject(Service(), False), } - debug_mock = mocker.patch.object(demisto, "debug") + info_mock = mocker.patch.object(demisto, "info") mocker.patch.object(demisto, "params", return_value={"timezone": "0"}) - mocker.patch.object(demisto, "info") mocker.patch( - "SplunkPy.results.JSONResultsReader", return_value=[Message("test message")] + "SplunkPy.results.JSONResultsReader", return_value=[results.Message("INFO-test", "test message")] ) mocker.patch("SplunkPy.isinstance", return_value=True) splunk.get_remote_data_command(Service(), **func_call_kwargs) - (debug_message,) = debug_mock.call_args_list[1][0] - assert debug_message == "Splunk-SDK message: test message" + (info_message,) = info_mock.call_args_list[0][0] + assert info_message == "Splunk-SDK message: test message" def test_get_modified_remote_data_command(mocker): @@ -1586,15 +1638,15 @@ def test_labels_with_non_str_values(mocker): "bool_val": False, "float_val": 100.0 } - mocked_response = SAMPLE_RESPONSE[0].copy() - mocked_response['_raw'] = json.dumps(raw) + mocked_response: list[results.Message | dict] = SAMPLE_RESPONSE.copy() + mocked_response[1]['_raw'] = json.dumps(raw) mock_last_run = {'time': '2018-10-24T14:13:20'} mock_params = {'fetchQuery': "something", "parseNotableEventsRaw": True} mocker.patch.object(demisto, 'incidents') mocker.patch.object(demisto, 'setLastRun') mocker.patch('demistomock.getLastRun', return_value=mock_last_run) mocker.patch('demistomock.params', return_value=mock_params) - mocker.patch('splunklib.results.JSONResultsReader', return_value=[mocked_response]) + mocker.patch('splunklib.results.JSONResultsReader', return_value=mocked_response) # run service = mocker.patch('splunklib.client.connect', return_value=None) diff --git a/Packs/SplunkPy/ReleaseNotes/3_1_1.md b/Packs/SplunkPy/ReleaseNotes/3_1_1.md new file mode 100644 index 000000000000..b24bee05ed75 --- /dev/null +++ b/Packs/SplunkPy/ReleaseNotes/3_1_1.md @@ -0,0 +1,7 @@ + +#### Integrations + +##### SplunkPy +- Updated the Docker image to: *demisto/splunksdk-py3:1.0.0.66897*. + +- Fixed an issue where the ***splunk-search*** command failed when splunk-sdk returned a message object. diff --git a/Packs/SplunkPy/pack_metadata.json b/Packs/SplunkPy/pack_metadata.json index 3cd96aa1a129..7839a9ee3665 100644 --- a/Packs/SplunkPy/pack_metadata.json +++ b/Packs/SplunkPy/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Splunk", "description": "Run queries on Splunk servers.", "support": "xsoar", - "currentVersion": "3.1.0", + "currentVersion": "3.1.1", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Tests/known_words.txt b/Tests/known_words.txt index 365addb1b35a..490e43d64a78 100644 --- a/Tests/known_words.txt +++ b/Tests/known_words.txt @@ -241,4 +241,6 @@ XSIAM fromversion xpanse JavaScript -RFC \ No newline at end of file +sdk +RFC +