diff --git a/Packs/ThreatConnect/Integrations/ThreatConnectV3/ThreatConnectV3.py b/Packs/ThreatConnect/Integrations/ThreatConnectV3/ThreatConnectV3.py index d34a9202dc2f..802429a4e779 100644 --- a/Packs/ThreatConnect/Integrations/ThreatConnectV3/ThreatConnectV3.py +++ b/Packs/ThreatConnect/Integrations/ThreatConnectV3/ThreatConnectV3.py @@ -411,23 +411,30 @@ def integration_test(client: Client, args: dict) -> None: # pragma: no cover return_results('ok') -def get_last_run_time(groups: list) -> str: - latest_date = datetime(1, 1, 1, 0, 0) +def get_last_run_time(groups: list, last_run: str) -> str: + latest_date = dateparser.parse(last_run) + if not latest_date: + raise DemistoException(f'There was a problem parsing {last_run=} with dateparser.parse') + for group in groups: - group_date = datetime.strptime(group.get('dateAdded'), '%Y-%m-%dT%H:%M:%SZ') - if group_date > latest_date: + try: + group_date = datetime.strptime(group.get('dateAdded'), '%Y-%m-%dT%H:%M:%SZ') + except Exception as e: + demisto.debug(f'Error parsing group date, value {group.get("dateAdded")=} error message {e}') + raise e + + if group_date and group_date > latest_date: latest_date = group_date + return latest_date.isoformat() def convert_to_dict(arr: list): - new_dict = {} - for item in arr: - new_dict[item] = True + new_dict = {item: True for item in arr} return new_dict -def fetch_incidents(client: Client, args: dict) -> None: # pragma: no cover +def fetch_incidents(client: Client, *args) -> str: params = demisto.params() tags = params.get('tags', '') if tags == 'None': @@ -443,15 +450,19 @@ def fetch_incidents(client: Client, args: dict) -> None: # pragma: no cover last_run = f"{params.get('first_fetch') or '3 days'} ago" last_run = dateparser.parse(last_run) + last_run = str(last_run) response = list_groups(client, {}, group_type=group_type, fields=fields, return_raw=True, tag=tags, status=status, from_date=last_run, limit=max_fetch, sort='&sorting=dateAdded%20ASC') - incidents = [] - for incident in response: - incidents.append(detection_to_incident(incident, incident.get('dateAdded'))) + incidents: list = [] + incidents.extend( + detection_to_incident(incident, incident.get('dateAdded')) + for incident in response + ) demisto.incidents(incidents) - set_last = get_last_run_time(response) - demisto.debug('Setting last run to: ' + set_last) + set_last = get_last_run_time(response, last_run) + demisto.debug(f'Setting last run to: {set_last}') demisto.setLastRun({'last': set_last}) + return set_last def tc_fetch_incidents_command(client: Client, args: dict) -> None: # pragma: no cover diff --git a/Packs/ThreatConnect/Integrations/ThreatConnectV3/ThreatConnectV3_test.py b/Packs/ThreatConnect/Integrations/ThreatConnectV3/ThreatConnectV3_test.py index 9390f9f5784c..d6f8c05f3bb7 100644 --- a/Packs/ThreatConnect/Integrations/ThreatConnectV3/ThreatConnectV3_test.py +++ b/Packs/ThreatConnect/Integrations/ThreatConnectV3/ThreatConnectV3_test.py @@ -1,5 +1,8 @@ -from ThreatConnectV3 import Client, Method, create_or_query, create_context, get_last_run_time, list_groups +import dateparser +from ThreatConnectV3 import Client, Method, create_or_query, create_context, get_last_run_time, list_groups, fetch_incidents from freezegun import freeze_time +import pytest +import demistomock as demisto client = Client('test', 'test', 'test', False) @@ -17,11 +20,60 @@ def test_create_or_query(): assert create_or_query('1,2,3,4,5', 'test', '') == 'test=1 OR test=2 OR test=3 OR test=4 OR test=5 ' -def test_get_last_run_time(): - groups = [{'dateAdded': '2022-08-04T12:35:33Z'}, {'dateAdded': '2022-09-06T12:35:33Z'}, - {'dateAdded': '2022-03-06T12:35:33Z'}, {'dateAdded': '2022-09-06T12:36:33Z'}, - {'dateAdded': '2022-08-06T11:35:33Z'}, ] - assert get_last_run_time(groups) == '2022-09-06T12:36:33' +@pytest.fixture +def groups_fixture() -> list: + return [{'dateAdded': '2022-08-04T12:35:33Z'}, {'dateAdded': '2022-09-06T12:35:33Z'}, + {'dateAdded': '2022-03-06T12:35:33Z'}, {'dateAdded': '2022-09-06T12:36:33Z'}, + {'dateAdded': '2022-08-06T11:35:33Z'}] + + +@pytest.mark.parametrize('last_run, expected_result', [('2022-07-04T12:35:33', '2022-09-06T12:36:33'), + ('2023-07-04T12:35:33', '2023-07-04T12:35:33')]) +def test_get_last_run_time(last_run, expected_result, groups_fixture): + """ + Given: + - a response containing groups with last_run time and the previos last run_time. + When: + - Checking for the next last_run. + Then: + - Validate that the correct last run is set. + """ + assert get_last_run_time(groups_fixture, last_run) == expected_result + + +def test_get_last_run_no_groups(): + """ + Given: + - no grops were found. + When: + - checking for the next last_run. + Then: + - validate that the last run remains as it was before in the previos round. + """ + assert get_last_run_time([], '2022-07-04T12:35:33') == '2022-07-04T12:35:33' + + +def test_fetch_incidents_first_run(mocker): + """ + Given: + - getLastRun is empty (first run) + When: + - calling fetch_events + Then: + - Validate that the last run is set properly + """ + import ThreatConnectV3 + mocker.patch.object(demisto, 'getLastRun', return_value={}) + mocker.patch.object(dateparser, 'parse', return_value=dateparser.parse('2022-08-04T12:35:33')) + mocker.patch.object(ThreatConnectV3, 'list_groups', return_value=[]) + assert fetch_incidents(client) == '2022-08-04T12:35:33' + + +def test_fetch_incidents_not_first_run(mocker, groups_fixture): + import ThreatConnectV3 + mocker.patch.object(demisto, 'getLastRun', return_value={'last': '2021-08-04T12:35:33'}) + mocker.patch.object(ThreatConnectV3, 'list_groups', return_value=groups_fixture) + assert fetch_incidents(client, {}) == '2022-09-06T12:36:33' def test_create_context(): # type: ignore # noqa diff --git a/Packs/ThreatConnect/ReleaseNotes/3_0_10.md b/Packs/ThreatConnect/ReleaseNotes/3_0_10.md new file mode 100644 index 000000000000..6a6008fe2c43 --- /dev/null +++ b/Packs/ThreatConnect/ReleaseNotes/3_0_10.md @@ -0,0 +1,5 @@ + +#### Integrations + +##### ThreatConnect v3 +- Fixed an issue where the ***fetch-incident*** command didn't correctly update the fetch time. diff --git a/Packs/ThreatConnect/pack_metadata.json b/Packs/ThreatConnect/pack_metadata.json index 4a659d00e637..4599e5801396 100644 --- a/Packs/ThreatConnect/pack_metadata.json +++ b/Packs/ThreatConnect/pack_metadata.json @@ -2,7 +2,7 @@ "name": "ThreatConnect", "description": "Threat intelligence platform.", "support": "xsoar", - "currentVersion": "3.0.9", + "currentVersion": "3.0.10", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "",