GetCampaignIncidentsInfo
Get the campaign incidents information as a MD table. This automation runs using the default Limited User role, unless you explicitly change the permissions. For more information, see the section about permissions here: - For Cortex XSOAR 6 see https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/6.x/Cortex-XSOAR-Playbook-Design-Guide/Automations - For Cortex XSOAR 8 Cloud see https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/8/Cortex-XSOAR-Cloud-Documentation/Create-a-script - For Cortex XSOAR 8.7 On-prem see https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/8.7/Cortex-XSOAR-On-prem-Documentation/Create-a-script
python · Phishing Campaign
Details
| ID | GetCampaignIncidentsInfo |
|---|---|
| Language | python |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Tags | field-display dynamic-section |
README
Creates a channel in Slack v2 or in Microsoft Teams. If both Slack v2 and Microsoft Teams are available,
it creates the channel in both Slack v2 and Microsoft Teams.
This automation runs using the default Limited User role, unless you explicitly change the permissions.
For more information, see the section about permissions here: For Cortex XSOAR 6, see the https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/6.x/Cortex-XSOAR-Playbook-Design-Guide/Automations for Cortex XSOAR 8 Cloud, see the https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/8/Cortex-XSOAR-Cloud-Documentation/Create-a-script for Cortex XSOAR 8 On-prem, see the https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/8.7/Cortex-XSOAR-On-prem-Documentation/Create-a-script.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Tags | field-display, dynamic-section |
| Cortex XSOAR Version | 5.0.0 |
Inputs
There are no inputs for this script.
Outputs
There are no outputs for this script.
import pytest from CommonServerPython import * from GetCampaignIncidentsInfo import * REQUIRED_KEYS = ["id", "name", "emailfrom", "recipients", "severity", "status", "created"] STR_VAL_KEYS = ["name", "emailfrom", "recipients", "created"] NUM_OF_INCIDENTS = 5 MOCKED_INCIDENTS = [ {key.replace("_", ""): f"test_{key}_{i}" if key in STR_VAL_KEYS else i for key in REQUIRED_KEYS} for i in range(NUM_OF_INCIDENTS) ] UPDATED_MOCKED_INCIDENTS = [ {key.replace("_", ""): 3 if key in KEYS_FETCHED_BY_QUERY else i for key in REQUIRED_KEYS} for i in range(NUM_OF_INCIDENTS) ] SOME_ERROR = "Raised by mock of demisto.context" def raise_exception(): raise Exception(SOME_ERROR) def test_incidents_info_md_happy_path(mocker): """ Given: - Mocked incidents When: - Get the campaign incidents info Then: - Validate all required key and val are in the MD result """ # prepare mocker.patch("GetCampaignIncidentsInfo.update_incident_with_required_keys", return_value=MOCKED_INCIDENTS) mocker.patch("GetCampaignIncidentsInfo.get_campaign_incidents_from_context", return_value=MOCKED_INCIDENTS) mocker.patch.object(demisto, "results") mocker.patch.object(demisto, "incidents", return_value=MOCKED_INCIDENTS) mocker.patch.object(demisto, "executeCommand") mocker.patch.object(demisto, "context", return_value={"EmailCampaign": {"fieldsToDisplay": REQUIRED_KEYS}}) # run main() hr = demisto.results.call_args[0][0]["HumanReadable"] # validate required keys are header in the MD and the expected values are the table assert all(string_to_table_header(key) in hr for key in REQUIRED_KEYS) assert all(f"test_{key}_" in hr for key in STR_VAL_KEYS) assert all(status in hr for status in STATUS_DICT.values()) assert all(f"[{i}](#/Details/{i})" in hr for i in range(NUM_OF_INCIDENTS)) # linkable incident id # validate the call to update empty fields args = demisto.executeCommand.call_args[0][1] assert args["customFields"] == DEFAULT_CUSTOM_FIELDS def test_incidents_info_md_for_empty_context(mocker): """ Given: - There is no campaign incidents in context When: - Get the campaign incidents info Then: - Validate return message """ # prepare mocker.patch.object(demisto, "results") mocker.patch("GetCampaignIncidentsInfo.get_campaign_incidents_from_context", return_value=[]) # run main() # validate assert demisto.results.call_args[0][0]["HumanReadable"] == NO_CAMPAIGN_INCIDENTS_MSG def test_incidents_info_md_with_invalid_keys(mocker): """ Given: - Incidents in campaign context contains some invalid keys (e.g. status), When: - Get value from incident (GetCampaignIncidentsInfo.get_incident_val) Then: - Validate invalid key not in the human readable """ # prepare incident_with_invalid_status = MOCKED_INCIDENTS[4] incident_without_status = MOCKED_INCIDENTS[0].copy() incident_without_status.pop("status") incidents = [incident_with_invalid_status, incident_without_status] mocker.patch.object(demisto, "results") mocker.patch("GetCampaignIncidentsInfo.get_campaign_incidents_from_context", return_value=incidents) mocker.patch("GetCampaignIncidentsInfo.update_incident_with_required_keys", return_value=incidents) # run main() hr = demisto.results.call_args[0][0]["HumanReadable"] # validate assert "Status" not in hr assert all(status not in hr for status in STATUS_DICT.values()) def test_some_error(mocker): """ Given: - Dynamic section try to populate the MD from script When: - Get incident info Then: - Raise exception and validate the return_error is called """ mocker.patch.object(demisto, "results") mocker.patch.object(demisto, "context", side_effect=raise_exception) mocker.patch("GetCampaignIncidentsInfo.update_incident_with_required_keys") # run try: main() pytest.fail(msg="SystemExit should occurred") except SystemExit: assert demisto.results.call_args[0][0]["Contents"] == SOME_ERROR def test_updated_status_and_severity(mocker): """ Given - Status or severity of incidents in campaign was changed When - Get the incidents info Then - Validate the updated values is returned """ # prepare mocker.patch.object(demisto, "results") mocker.patch("GetCampaignIncidentsInfo.get_campaign_incidents_from_context", return_value=MOCKED_INCIDENTS) mocker.patch.object( demisto, "executeCommand", return_value=[{"Contents": json.dumps(UPDATED_MOCKED_INCIDENTS), "Type": "str"}] ) # run main() # validate hr = demisto.results.call_args[0][0]["HumanReadable"] hr.count("| Archive |") == NUM_OF_INCIDENTS # noqa: B015 # all incidents should have the 'Archive' status hr.count("| 3 |") == NUM_OF_INCIDENTS # noqa: B015 # all incidents should have severity 3 def test_update_incident_with_required_keys(mocker): """ Given - Two Phishing Campaign incidents (the first one exists, the second one is deleted) - The required keys When - Execute update_incident_with_required_keys function Then - Ensure the function returns just the exists incident and does not fail """ incident_1 = { "emailfrom": "", "emailfromdomain": "", "id": "1", "name": "Campaign Test", "occurred": "2023-06-21T13:18:38.056972974Z", "recipients": [], "recipientsdomain": [], "severity": 0, "similarity": 1, "status": 1, } incident_2 = { "emailfrom": "", "emailfromdomain": "", "id": "2", "name": "Campaign Test", "occurred": "2023-06-21T13:18:38.056972974Z", "recipients": [], "recipientsdomain": [], "severity": 0, "similarity": 1, "status": 1, } incident_1_correct_format = ( '[{"emailfrom": "","emailfromdomain": "","id": "1", "name": "Campaign Test",' ' "occurred": "2023-06-21T13:18:38.056972974Z","recipients": [], "recipientsdomain": [],' ' "severity": 0, "similarity": 1, "status": 1}]' ) incidents = [incident_1, incident_2] mocker.patch( "demistomock.executeCommand", side_effect=([{"Contents": "[Test]"}], [{"Contents": "[]"}], [{"Type": "Test", "Contents": incident_1_correct_format}]), ) incidents = update_incident_with_required_keys(incidents, KEYS_FETCHED_BY_QUERY) assert len(incidents) == 1 assert incidents[0].get("id") == "1"