import pytest from FireEyeEX import * from freezegun import freeze_time from test_data.result_constants import ( ALLOWEDLIST, BLOCKEDLIST, GET_ALERTS_CONTEXT, GET_ALERTS_DETAILS_CONTEXT, GET_ARTIFACTS_METADATA_CONTEXT, QUARANTINED_EMAILS_CONTEXT, ) def util_load_json(path): with open(path, encoding="utf-8") as f: return json.loads(f.read()) def date_parser_mock(time_str: str): if "10 minutes" in time_str: # We return this constant time since the integration is performing relative time search (10 minutes ago). return dateparser.parse("2021-02-20T17:01:14.000000+00:00") return dateparser.parse(time_str) def test_get_alerts(mocker): """Unit test Given - get_alerts command - command args - command raw response When - mock the Client's token generation. - mock the Client's get_alerts_request response. Then - Validate The entry context """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "get_alerts_request", return_value=util_load_json("test_data/get_alerts.json")) command_results = get_alerts( client=client, args={"limit": "2", "start_time": "2 months", "sender_email": "test@malicious.net"} ) assert command_results.outputs == GET_ALERTS_CONTEXT def test_get_alert_details(mocker): """Unit test Given - get_alert_details command - command args - command raw response When - mock the Client's token generation. - mock the Client's get_alert_details_request response. Then - Validate The entry context """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object( FireEyeClient, "get_alert_details_request", return_value=util_load_json("test_data/get_alert_details.json") ) command_results = get_alert_details(client=client, args={"alert_id": "3"}) assert command_results[0].outputs == GET_ALERTS_DETAILS_CONTEXT def test_get_artifacts_metadata(mocker): """Unit test Given - get_artifacts_metadata_by_uuid command - command args - command raw response When - mock the Client's token generation. - mock the Client's get_artifacts_metadata_by_uuid request response. Then - Validate The entry context """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object( FireEyeClient, "get_artifacts_metadata_by_uuid_request", return_value=util_load_json("test_data/get_artifact_metadata.json"), ) command_results = get_artifacts_metadata_by_uuid(client=client, args={"uuid": "uuid"}) assert command_results[0].outputs == GET_ARTIFACTS_METADATA_CONTEXT def test_get_quarantined_emails(mocker): """Unit test Given - get_quarantined_emails command - command args - command raw response When - mock the Client's token generation. - mock the Client's get_quarantined_emails_request response. Then - Validate The entry context """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object( FireEyeClient, "get_quarantined_emails_request", return_value=util_load_json("test_data/quarantined_emails.json") ) command_results = get_quarantined_emails(client=client, args={"limit": "2"}) assert command_results.outputs == QUARANTINED_EMAILS_CONTEXT def test_get_report_not_found(mocker): """Unit test Given - get_reports command - command args - command raw response When - mock the Client's token generation. - mock the Client's get_reports_request response for a non found report. Then - Validate the human readable """ error_msg = ( "Error in API call [400] - Bad Request " '{"fireeyeapis": {"@version": "v2.0.0", "description": "WSAPI_REPORT_ALERT_NOT_FOUND.' ' code:WSAPI_WITH_ERRORCODE_2016", "httpStatus": 400,' ' "message": "parameters{infection_id=34013; infection_type=malware-callback}"}}' ) def error_400_mock(*kwargs): raise Exception(error_msg) mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch("FireEyeEX.FireEyeClient.get_reports_request", side_effect=error_400_mock) command_results = get_reports( client=client, args={"report_type": "alertDetailsReport", "infection_id": "34013", "infection_type": "mallware-callback"} ) assert command_results.readable_output == "Report alertDetailsReport was not found with the given arguments." def test_release_quarantined_emails(mocker): """Unit test Given - release_quarantined_emails command - command args - command raw response When - mock the Client's token generation. - mock the Client's release_quarantined_emails_request response. Then - Validate that an error is raised from the command """ def mocked_release_quarantined_emails_requests(*args): class MockResponse: def __init__(self, json_data, status_code): self.json_data = json_data self.status_code = status_code def json(self): return self.json_data def text(self): return "1234" return MockResponse({"1234": "Unable to release the email:quarantined email does not exist\\n"}, 200) mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object( FireEyeClient, "release_quarantined_emails_request", side_effect=mocked_release_quarantined_emails_requests ) with pytest.raises(DemistoException): release_quarantined_emails(client=client, args={"queue_ids": "1234"}) def test_delete_quarantined_emails(mocker): """Unit test Given - delete_quarantined_emails command - command args - command raw response When - mock the Client's token generation. - mock the Client's delete_quarantined_emails_request response. Then - Validate that an error is raised from the command """ def mocked_delete_quarantined_emails_requests(*args): class MockResponse: def __init__(self, json_data, status_code): self.json_data = json_data self.status_code = status_code def json(self): return self.json_data def text(self): return "1234" return MockResponse({"1234": "Unable to delete the email:quarantined email does not exist\\n"}, 200) mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.cm.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "delete_quarantined_emails_request", side_effect=mocked_delete_quarantined_emails_requests) with pytest.raises(DemistoException): delete_quarantined_emails(client=client, args={"queue_ids": "1234"}) def test_list_allowedlist(mocker): """Unit test Given - list_allowedlist_request command - command args - command raw response When - mock the Client's token generation. - mock the Client's list_allowedlist_request response. Then - Validate The entry context """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_allowedlist_request", return_value=util_load_json("test_data/list_allowedlist.json")) command_results = list_allowedlist(client=client, args={"type": "url"}) assert command_results.outputs == ALLOWEDLIST def test_create_allowedlist_already_exist(mocker): """Unit test Given - create_allowedlist_request command - an already existing entry_value - command raw response When - mock the Client's token generation. - mock the Client's list_allowedlist_request response. Then - Validate The a proper error is raised """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_allowedlist_request", return_value=util_load_json("test_data/list_allowedlist.json")) err_str = "Cannot create the entry_value www.demisto.com as it is already exist in the Allowedlist of type url." with pytest.raises(DemistoException, match=err_str): create_allowedlist(client=client, args={"type": "url", "entry_value": "www.demisto.com", "matches": "2"}) def test_update_allowedlist_not_exist(mocker): """Unit test Given - update_allowedlist_request command - a non existing entry_value - command raw response When - mock the Client's token generation. - mock the Client's list_allowedlist_request response. Then - Validate The a proper error is raised """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_allowedlist_request", return_value=util_load_json("test_data/list_allowedlist.json")) err_str = "Cannot update the entry_value www.fake.com as it does not exist in the Allowedlist of type url." with pytest.raises(DemistoException, match=err_str): update_allowedlist(client=client, args={"type": "url", "entry_value": "www.fake.com", "matches": "2"}) def test_delete_allowedlist_not_exist(mocker): """Unit test Given - delete_allowedlist_request command - a non existing entry_value - command raw response When - mock the Client's token generation. - mock the Client's list_allowedlist_request response. Then - Validate The a proper error is raised """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_allowedlist_request", return_value=util_load_json("test_data/list_allowedlist.json")) err_str = "Cannot delete the entry_value www.fake.com as it does not exist in the Allowedlist of type url." with pytest.raises(DemistoException, match=err_str): delete_allowedlist(client=client, args={"type": "url", "entry_value": "www.fake.com"}) def test_list_blockedlist(mocker): """Unit test Given - list_blockedlist_request command - command args - command raw response When - mock the Client's token generation. - mock the Client's list_blockedlist_request response. Then - Validate The entry context """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_blockedlist_request", return_value=util_load_json("test_data/list_blockedlist.json")) command_results = list_blockedlist(client=client, args={"type": "url"}) assert command_results.outputs == BLOCKEDLIST def test_list_blockedlist_with_limit(mocker): """Unit test Given - list_blockedlist_request command - command args with a limit - command raw response When - mock the Client's token generation. - mock the Client's list_blockedlist_request response. Then - Validate The entry context is limited """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_blockedlist_request", return_value=util_load_json("test_data/list_blockedlist.json")) command_results = list_blockedlist(client=client, args={"type": "url", "limit": "1"}) assert command_results.outputs == BLOCKEDLIST[:1] def test_list_blockedlist_no_entries(mocker): """Unit test Given - list_blockedlist_request command - command args - command raw response When - mock the Client's token generation. - mock the Client's list_blockedlist_request response. Then - Validate The human readable yields an appropriate message """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_blockedlist_request", return_value={}) command_results = list_blockedlist(client=client, args={"type": "sender_domain"}) assert command_results.readable_output == "No blocked lists with the given type sender_domain were found." def test_create_blockedlist_already_exist(mocker): """Unit test Given - create_blockedlist_request command - an already existing entry_value - command raw response When - mock the Client's token generation. - mock the Client's list_allowedlist_request response. Then - Validate The a proper error is raised """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_blockedlist_request", return_value=util_load_json("test_data/list_blockedlist.json")) err_str = ( "Cannot create the entry_value www.blocksite1.net/path/test.html as it is already exist in the " "Blockedlist of type url." ) with pytest.raises(DemistoException, match=err_str): create_blockedlist( client=client, args={"type": "url", "entry_value": "www.blocksite1.net/path/test.html", "matches": "2"} ) def test_update_blockedlist_not_exist(mocker): """Unit test Given - update_blockedlist_request command - a non existing entry_value - command raw response When - mock the Client's token generation. - mock the Client's list_blockedlist_request response. Then - Validate The a proper error is raised """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_blockedlist_request", return_value=util_load_json("test_data/list_blockedlist.json")) err_str = "Cannot update the entry_value www.fake.com as it does not exist in the Blockedlist of type url." with pytest.raises(DemistoException, match=err_str): update_blockedlist(client=client, args={"type": "url", "entry_value": "www.fake.com", "matches": "2"}) def test_delete_blockedlist_not_exist(mocker): """Unit test Given - delete_blockedlist_request command - an non existing entry_value - command raw response When - mock the Client's token generation. - mock the Client's list_blockedlist_request response. Then - Validate The a proper error is raised """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "list_blockedlist_request", return_value=util_load_json("test_data/list_blockedlist.json")) err_str = "Cannot delete the entry_value www.fake.com as it does not exist in the Blockedlist of type url." with pytest.raises(DemistoException, match=err_str): delete_blockedlist(client=client, args={"type": "url", "entry_value": "www.fake.com"}) def test_fetch_incidents(mocker): """Unit test Given - fetch incidents command - command args - command raw response When - mock the Client's token generation. - mock the Client's get_alerts_request. Then - run the fetch incidents command using the Client Validate The length of the results and the last_run. """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "get_alerts_request", return_value=util_load_json("test_data/alerts.json")) last_run, incidents = fetch_incidents(client=client, last_run={}, first_fetch="1 year", max_fetch=50, info_level="concise") assert len(incidents) == 5 assert last_run.get("time") == "2021-02-14 17:01:14 +0000" # occurred time of the last alert def test_fetch_incidents_with_limit(mocker): """Unit test Given - fetch incidents command - command args with a harsh limit - command raw response When - mock the Client's token generation. - mock the Client's get_alerts_request. Then - run the fetch incidents command using the Client Validate The length of the results and the last_run of the limited incident. """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.ex.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "get_alerts_request", return_value=util_load_json("test_data/alerts.json")) last_run, incidents = fetch_incidents(client=client, last_run={}, first_fetch="1 year", max_fetch=2, info_level="concise") assert len(incidents) == 2 assert last_run.get("time") == "2021-02-14 09:43:55 +0000" # occurred time of the last alert def test_fetch_incidents_last_alerts(mocker): """Unit test Given - Fetch incidents command is called - command args - command raw response When - The alerts returned from teh server are already in (1,2,3,4,5) Then - Validate that no incident will be returned. - Validate that the last_run is pushed in two days from the latest incident fetched - Validate last_alert_ids stays the same """ # mocker.patch.object(dateparser, 'parse', side_effect=date_parser_mock) mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.cm.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "get_alerts_request", return_value=util_load_json("test_data/alerts.json")) last_run_time = "2021-02-14T17:01:14+00:00" next_run_time_to_expect = (dateparser.parse(last_run_time) + timedelta(hours=48)).isoformat() last_alert_ids = '["1", "2", "3", "4", "5"]' last_run = {"time": last_run_time, "last_alert_ids": last_alert_ids} next_run, incidents = fetch_incidents( client=client, last_run=last_run, first_fetch="1 year", max_fetch=50, info_level="concise" ) assert len(incidents) == 0 assert next_run.get("time") == next_run_time_to_expect assert next_run.get("last_alert_ids") == last_alert_ids # We freeze the time since we are using dateparser.parse('now') in the fetch incidents @freeze_time("2021-02-15T17:10:00+00:00") def test_fetch_incidents_no_alerts(mocker): """Unit test Given - Current time is 2021-02-15 17:10:00 +00:00 - Fetch incidents command is called When - No results returned from the search for the start_time = 2021-02-14 17:01:14 +00:00 (no new alerts created until now) Then - Validate that no incident will be returned. - Validate that the last_run is set to the current time minus ten minutes (2021-02-15 17:00:00 +00:00) - Validate last_alert_ids is reset to empty list """ mocker.patch.object(FireEyeClient, "_get_token", return_value="token") client = Client(base_url="https://fireeye.cm.com/", username="user", password="pass", verify=False, proxy=False) mocker.patch.object(FireEyeClient, "get_alerts_request", return_value=util_load_json("test_data/no_alerts.json")) last_run_time = "2021-02-14T17:01:14+00:00" last_alert_ids = '["1", "2", "3", "4", "5"]' last_run = {"time": last_run_time, "last_alert_ids": last_alert_ids} next_run, incidents = fetch_incidents( client=client, last_run=last_run, first_fetch="1 year", max_fetch=50, info_level="concise" ) assert len(incidents) == 0 assert next_run.get("time") == "2021-02-15T17:00:00+00:00" assert next_run.get("last_alert_ids") == [] def test_module_test(mocker): """ Given: - When: - Run the test-module command Then: - Validate the get_alerts_request was called with the start_time argument """ # prepare mocker.patch.object(FireEyeClient, "_get_token", return_value="token") mocker.patch.object(FireEyeClient, "get_alerts_request") client = Client(base_url="https://fireeye.cm.com/", username="user", password="pass", verify=False, proxy=False) # run run_test_module(client=client) # validate # take the date from the whole fe_datetime by split by the T start_time = to_fe_datetime_converter("1 day").split("T")[0] call_args_dict = FireEyeClient.get_alerts_request.call_args[0][0] assert start_time in call_args_dict["start_time"] assert call_args_dict["duration"] == "24_hours" @pytest.mark.parametrize(argnames="status_code", argvalues=OK_CODES) def test_ok_status_codes_in_fe_response(mocker, status_code): """ Given: - ok status codes defined in FireEyeApiModule When: - Run any FireEye request Then: - Validate the response consider ok and return the data """ # prepare mocked_response = requests.Response() mocked_response.status_code = status_code mocked_response._content = json.dumps({"request_status": "success"}).encode("utf-8") mocker.patch.object(FireEyeClient, "_get_token", return_value="token") mocker.patch("requests.sessions.Session.request", return_value=mocked_response) client = Client(base_url="https://fireeye.cm.com/", username="user", password="pass", verify=False, proxy=False) # run res = client.fe_client.get_alerts_request( { "info_level": "concise", "start_time": to_fe_datetime_converter("1 day"), "duration": "24_hours", } ) # validate assert res["request_status"] == "success" def test_wrong_status_codes_in_fe_response(mocker): """ Given: - wrong status codes not defined as ok_codes in FireEyeApiModule When: - Run any FireEye request Then: - Validate the request was failed """ # prepare mocked_response = requests.Response() mocked_response.status_code = 300 mocked_response._content = json.dumps({"request_status": "failed"}).encode("utf-8") mocker.patch.object(FireEyeClient, "_get_token", return_value="token") mocker.patch("requests.sessions.Session.request", return_value=mocked_response) client = Client(base_url="https://fireeye.cm.com/", username="user", password="pass", verify=False, proxy=False) # run with pytest.raises(DemistoException, match="Error in API call"): client.fe_client.get_alerts_request( { "info_level": "concise", "start_time": to_fe_datetime_converter("1 day"), "duration": "24_hours", } )