XDRSyncScript Deprecated

Deprecated. No available replacement. Syncs a single incident between Demisto and XDR. This script always uses the xdr-get-incident-extra-data command and outputs to the context the entire incident JSON. When the incident is updated in XDR, the Demisto incident will be updated accordingly and the default playbook will rerun. When an incident is updated in Demisto, the script will execute the xdr-update-incident command and update the incident in XDR.

python · Cortex XDR by Palo Alto Networks

Details

IDXDRSyncScript
Languagepython
From Version6.0.0
Docker Imagedemisto/python3:3.9.7.24076
Tagsxdr
from CommonServerPython import *
import copy
import json
import XDRSyncScript as xdr_script
from XDRSyncScript import ASSIGNED_USER_MAIL_XDR_FIELD, MODIFICATION_TIME_XDR_FIELD, MANUAL_SEVERITY_XDR_FIELD, \
    SEVERITY_XDR_FIELD


INCIDENT_IN_DEMISTO = {
    "sourceInstance": "Palo Alto Networks Cortext XDR IR_instance_1",
    "occurred": "2019-05-30T14:32:22.398+03:00",
    "closeReason": "",
    "modified": "2019-06-02T11:15:09.323251+03:00",
    "CustomFields": {
        "xdrincidentid": "697567",
        "xdrurl": "http://example.com/incident-view/697567",
        "xdrdescription": "WildFire Malware detected on host HostNameFFM8VIP9",
        "xdralertcount": 1,
        "xdrstatus": "new",
        "xdrassignedusermail": "",
        "xdrassigneduserprettyname": "",
        "xdrmodificationtime": "2019-06-02T11:15:09.323251+03:00",
        "xdralerts": [
            {
                "category": "WildFirePostDetection",
                "action_pretty": "Detected (Reported)",
                "description": "Suspicious executable detected",
                "severity": "high",
                "host_ip": "8.8.8.8",
                "source": "Traps",
                "alert_id": "50820",
                "host_name": "HostNameFFM8VIP9",
                "detection_timestamp": 1559215835437,
                "action": "REPORTED",
                "user_name": "N/A",
                "name": "WildFire Malware"
            }
        ],
        "xdrfileartifacts": [
            {
                "file_signature_status": "SIGNATURE_UNAVAILABLE",
                "is_process": None,
                "file_name": "LCTGSK7IML.docx",
                "file_wildfire_verdict": "UNKNOWN",
                "alert_count": 1,
                "is_malicious": None,
                "is_manual": None,
                "file_signature_vendor_name": None,
                "type": "HASH",
                "file_sha256": "384654fa409c7a500a4a843d33a005c9d670d4845d3a9e096efc8b00ad05a621"
            }
        ],
        "xdrnetworkartifacts": []
    },
    "severity": 1,
    "name": "#697567 - WildFire Malware detected on host HostNameFFM8VIP9",
    "created": "2019-06-02T11:13:54.674006+03:00",
    "sourceBrand": "Palo Alto Networks Cortext XDR IR",
}

OLD_INCIDENT_IN_DEMISTO = {
    "sourceInstance": "Palo Alto Networks Cortext XDR IR_instance_1",
    "occurred": "2019-05-30T14:32:22.398+03:00",
    "closeReason": "",
    "modified": "2019-06-02T11:15:09.323251+03:00",
    "CustomFields": {
        "xdrincidentid": "697567",
        "xdrurl": "http://example.com/incident-view/697567",
        "xdrdescription": "WildFire Malware detected on host HostNameFFM8VIP9",
        "xdralertcount": 1,
        "xdrstatus": "new",
        "xdrassignedusermail": "",
        "xdrassigneduserprettyname": "",
        "xdralerts": [
            {
                "category": "WildFirePostDetection",
                "action_pretty": "Detected (Reported)",
                "description": "Suspicious executable detected",
                "severity": "high",
                "host_ip": "8.8.8.8",
                "source": "Traps",
                "alert_id": "50820",
                "host_name": "HostNameFFM8VIP9",
                "detection_timestamp": 1559215835437,
                "action": "REPORTED",
                "user_name": "N/A",
                "name": "WildFire Malware"
            }
        ],
        "xdrfileartifacts": [
            {
                "file_signature_status": "SIGNATURE_UNAVAILABLE",
                "is_process": None,
                "file_name": "LCTGSK7IML.docx",
                "file_wildfire_verdict": "UNKNOWN",
                "alert_count": 1,
                "is_malicious": None,
                "is_manual": None,
                "file_signature_vendor_name": None,
                "type": "HASH",
                "file_sha256": "384654fa409c7a500a4a843d33a005c9d670d4845d3a9e096efc8b00ad05a621"
            }
        ],
        "xdrnetworkartifacts": []
    },
    "labels": [
        {
            "type": "modification_time",
            "value": 1559463309323,
        }
    ],
    "severity": 1,
    "name": "#697567 - WildFire Malware detected on host HostNameFFM8VIP9",
    "created": "2019-06-02T11:13:54.674006+03:00",
    "sourceBrand": "Palo Alto Networks Cortext XDR IR",
}

INCIDENT_FROM_XDR = {
    "host_count": 1,
    "manual_severity": None,
    "xdr_url": "http://example.com/incident-view/697567",
    "assigned_user_pretty_name": None,
    "alert_count": 1,
    "med_severity_alert_count": 0,
    "detection_time": None,
    "user_count": 1,
    "severity": "low",
    "alerts": [
        {
            "category": "WildFirePostDetection",
            "action_pretty": "Detected (Reported)",
            "description": "Suspicious executable detected",
            "severity": "high",
            "host_ip": "8.8.8.8",
            "source": "Traps",
            "alert_id": "50820",
            "host_name": "HostNameFFM8VIP9",
            "detection_timestamp": 1559215835437,
            "action": "REPORTED",
            "user_name": "N/A",
            "name": "WildFire Malware"
        }
    ],
    "low_severity_alert_count": 0,
    "status": "new",
    "description": "WildFire Malware detected on host HostNameFFM8VIP9",
    "resolve_comment": None,
    "creation_time": 1559215942398,
    "modification_time": 1559215942398,
    "network_artifacts": [],
    "file_artifacts": [
        {
            "file_signature_status": "SIGNATURE_UNAVAILABLE",
            "is_process": None,
            "file_name": "LCTGSK7IML.docx",
            "file_wildfire_verdict": "UNKNOWN",
            "alert_count": 1,
            "is_malicious": None,
            "is_manual": None,
            "file_signature_vendor_name": None,
            "type": "HASH",
            "file_sha256": "384654fa409c7a500a4a843d33a005c9d670d4845d3a9e096efc8b00ad05a621"
        }
    ],
    "manual_description": None,
    "incident_id": "697567",
    "notes": None,
    "assigned_user_mail": None,
    "high_severity_alert_count": 1
}

INCIDENT_FROM_XDR_RAW_RESPONSE = {
    'incident': INCIDENT_FROM_XDR
}


def test_compare_incident_in_demisto_vs_xdr_context___incident_not_modified():
    """
    Given
    - incident in xdr which already in context
    - incident in demisto

    When
    - nothing has changed

    Then
    - compare function returns
        is_modified=False
    """

    incident_id = "100"
    fields_mapping = {
        "status": "xdrstatus",
        "severity": "severity"
    }

    incident_in_demisto = copy.deepcopy(INCIDENT_IN_DEMISTO)
    xdr_incident_in_context = copy.deepcopy(INCIDENT_FROM_XDR)
    xdr_incident_in_context['severity'] = 1
    is_modified, update_args = xdr_script.compare_incident_in_demisto_vs_xdr_context(incident_in_demisto,
                                                                                     xdr_incident_in_context,
                                                                                     incident_id,
                                                                                     fields_mapping)
    assert not is_modified


def test_compare_incident_in_demisto_vs_xdr_context___status_was_modified():
    """
    Given
    - incident in xdr which already in context
    - incident in demisto

    When
    - xdrstatus field in demisto changed to closed

    Then
    - compare function returns
        is_modified=True
        update_args contains status
    """

    incident_id = "100"
    fields_mapping = {
        "status": "xdrstatus",
        "severity": "severity"
    }

    incident_in_demisto = copy.deepcopy(INCIDENT_IN_DEMISTO)
    incident_in_demisto["CustomFields"]["xdrstatus"] = "closed"

    xdr_incident_in_context = copy.deepcopy(INCIDENT_FROM_XDR)
    xdr_incident_in_context['severity'] = 1

    is_modified, update_args = xdr_script.compare_incident_in_demisto_vs_xdr_context(incident_in_demisto,
                                                                                     xdr_incident_in_context,
                                                                                     incident_id,
                                                                                     fields_mapping)

    assert is_modified
    assert {
        "incident_id": "100",
        "status": "closed"
    } == update_args


def test_compare_incident_in_demisto_vs_xdr_context___severity_was_modified():
    """
    Given
    - incident in xdr which already in context
    - incident in demisto

    When
    - severity field in demisto changed to 3 (high)

    Then
    - compare function returns
        is_modified=True
        update_args contains manual_severity
    """

    incident_id = "100"
    fields_mapping = {
        "status": "xdrstatus",
        "severity": "severity"
    }

    incident_in_demisto = copy.deepcopy(INCIDENT_IN_DEMISTO)
    incident_in_demisto["severity"] = 3

    xdr_incident_in_context = copy.deepcopy(INCIDENT_FROM_XDR)

    is_modified, update_args = xdr_script.compare_incident_in_demisto_vs_xdr_context(incident_in_demisto,
                                                                                     xdr_incident_in_context,
                                                                                     incident_id,
                                                                                     fields_mapping)

    assert is_modified
    assert {
        "incident_id": "100",
        "manual_severity": "high"
    } == update_args


def test_compare_incident_in_demisto_vs_xdr_context___status_and_severity_was_modified():
    """
    Given
    - incident in xdr which already in context
    - incident in demisto

    When
    - severity field in demisto changed
    - xdrstatus field in demisto changed

    Then
    - compare function returns
        is_modified=True
        update_args contains manual_severity and status
    """

    incident_id = "100"
    fields_mapping = {
        "status": "xdrstatus",
        "severity": "severity"
    }

    incident_in_demisto = copy.deepcopy(INCIDENT_IN_DEMISTO)
    incident_in_demisto["severity"] = 3
    incident_in_demisto["CustomFields"]["xdrstatus"] = "closed"

    xdr_incident_in_context = copy.deepcopy(INCIDENT_FROM_XDR)

    is_modified, update_args = xdr_script.compare_incident_in_demisto_vs_xdr_context(incident_in_demisto,
                                                                                     xdr_incident_in_context,
                                                                                     incident_id,
                                                                                     fields_mapping)

    assert is_modified
    assert {
        "incident_id": "100",
        "manual_severity": "high",
        "status": "closed"
    } == update_args


def test_compare_incident_latest_xdr_incident_with_older_xdr_in_context____when_nothing_changed():
    """
    Given
    - incident from xdr - latest
    - incident from xdr - older
    - fields_mapping:
        status: xdrstatus,
        severity: xdrseverity,
        manual_severity: severity

    When
    - nothing changed

    Then
    - ensure compare returns is_modified=False

    """
    fields_mapping = {
        "status": "xdrstatus",
        "severity": "severity"
    }

    incident_in_xdr_latest = copy.deepcopy(INCIDENT_FROM_XDR)
    incident_from_xdr_in_context = copy.deepcopy(INCIDENT_FROM_XDR)
    incident_from_xdr_in_context['severity'] = 1

    is_modified, update_args = xdr_script.compare_incident_in_xdr_vs_previous_xdr_in_context(
        incident_in_xdr_latest,
        incident_from_xdr_in_context,
        fields_mapping)

    assert not is_modified


def test_compare_incident_latest_xdr_incident_with_older_xdr_in_context____when_status_changed():
    """
    Given
    - incident from xdr - latest
    - incident from xdr - older
    - fields_mapping:
        status: xdrstatus,
        severity: xdrseverity,
        manual_severity: severity

    When
    - status changed from new to under_investigation

    Then
    - ensure compare returns is_modified=True
    - ensure compare returns update_args contains xdrstatus=under_investigation

    """
    fields_mapping = {
        "status": "xdrstatus",
        "severity": "severity",
    }

    incident_in_xdr_latest = copy.deepcopy(INCIDENT_FROM_XDR)
    incident_in_xdr_latest["status"] = "under_investigation"
    incident_in_xdr_latest["modification_time"] += 100

    incident_from_xdr_in_context = copy.deepcopy(INCIDENT_FROM_XDR)
    incident_from_xdr_in_context['severity'] = 1

    is_modified, update_args = xdr_script.compare_incident_in_xdr_vs_previous_xdr_in_context(
        incident_in_xdr_latest,
        incident_from_xdr_in_context,
        fields_mapping)

    assert is_modified
    assert {
        "xdrstatus": "under_investigation",
    } == update_args


def test_compare_incident_latest_xdr_incident_with_older_xdr_in_context____when_manual_severity_changed():
    """
    Given
    - incident from xdr - latest
    - incident from xdr - older
    - fields_mapping:
        status: xdrstatus,
        severity: xdrseverity,
        manual_severity: severity

    When
    - manual_severity changed from None to medium

    Then
    - ensure compare returns is_modified=True
    - ensure compare returns update_args contains severity=medium

    """
    fields_mapping = {
        "status": "xdrstatus",
        "manual_severity": "severity"
    }

    incident_in_xdr_latest = copy.deepcopy(INCIDENT_FROM_XDR)
    incident_in_xdr_latest["manual_severity"] = "medium"
    incident_in_xdr_latest["modification_time"] += 100

    incident_from_xdr_in_context = copy.deepcopy(INCIDENT_FROM_XDR)
    incident_from_xdr_in_context['severity'] = 1

    is_modified, update_args = xdr_script.compare_incident_in_xdr_vs_previous_xdr_in_context(
        incident_in_xdr_latest,
        incident_from_xdr_in_context,
        fields_mapping)

    assert is_modified
    assert {
        "severity": "medium",
    } == update_args


def test_compare_incident_latest_xdr_incident_with_older_xdr_in_context____when_status_and_severity_changed():
    """
    Given
    - incident from xdr - latest
    - incident from xdr - older
    - fields_mapping:
        status: xdrstatus,
        severity: xdrseverity,
        manual_severity: severity

    When
    - manual_severity changed from None to medium
    - status changed from new to under_investigation
    -

    Then
    - ensure compare returns is_modified=True
    - ensure compare returns update_args contains severity=medium

    """
    fields_mapping = {
        "status": "xdrstatus",
        "severity": "xdrseverity",
        "manual_severity": "severity"
    }

    incident_in_xdr_latest = copy.deepcopy(INCIDENT_FROM_XDR)
    incident_in_xdr_latest["manual_severity"] = "medium"
    incident_in_xdr_latest["status"] = "under_investigation"
    incident_in_xdr_latest["modification_time"] += 100

    incident_from_xdr_in_context = copy.deepcopy(INCIDENT_FROM_XDR)
    incident_from_xdr_in_context['severity'] = 1

    is_modified, update_args = xdr_script.compare_incident_in_xdr_vs_previous_xdr_in_context(
        incident_in_xdr_latest,
        incident_from_xdr_in_context,
        fields_mapping)

    assert is_modified
    assert {
        "severity": "medium",
        "xdrstatus": "under_investigation"
    } == update_args


def test_args_to_str_1():
    xdr_incident = copy.deepcopy(INCIDENT_FROM_XDR)
    args = {
        "incident_id": "11",
        "assigned_user_mail": "xdrassigneduser",
        "status": "xdrstatus",
        "severity": "xdrseverity",
        "playbook_to_run": "XDR Demo",
        "first": "true"
    }

    actual = xdr_script.args_to_str(args, xdr_incident)

    expected = 'incident_id=`11` assigned_user_mail=`xdrassigneduser` status=`xdrstatus` severity=`xdrseverity` ' \
               'playbook_to_run=`XDR Demo` first=`false` xdr_incident_from_previous_run=`{}` '\
        .format(json.dumps(xdr_incident))

    assert expected == actual


def test_args_to_str_2():
    xdr_incident = copy.deepcopy(INCIDENT_FROM_XDR)
    args = {
        "incident_id": "11",
        "assigned_user_mail": "xdrassigneduser",
        "status": "xdrstatus",
        "severity": "xdrseverity",
        "playbook_to_run": "XDR Demo",
        "first": "false",
        "xdr_incident_from_previous_run": "some previous value"
    }

    actual = xdr_script.args_to_str(args, xdr_incident)

    expected = 'incident_id=`11` assigned_user_mail=`xdrassigneduser` status=`xdrstatus` severity=`xdrseverity` ' \
               'playbook_to_run=`XDR Demo` first=`false` xdr_incident_from_previous_run=`{}` '\
        .format(json.dumps(xdr_incident))

    assert expected == actual


def test_compare_incident_in_demisto_when_the_severity_is_unknown():
    """
    Given
    - incident in demisto
    - incident from xdr - older
    - fields_mapping:
        severity: severity

    When
    - severity in demisto is unknown

    Then
    - ensure severity is not updated in XDR

    """
    incident_id = "100"
    fields_mapping = {
        "severity": "severity"
    }

    incident_in_demisto = copy.deepcopy(INCIDENT_IN_DEMISTO)
    incident_in_demisto["severity"] = 0

    xdr_incident_in_context = copy.deepcopy(INCIDENT_FROM_XDR)

    is_modified, update_args = xdr_script.compare_incident_in_demisto_vs_xdr_context(incident_in_demisto,
                                                                                     xdr_incident_in_context,
                                                                                     incident_id,
                                                                                     fields_mapping)

    assert is_modified is False
    assert {} == update_args


def test_fix_bug_19669(mocker, capfd):
    """
    bug fix https://github.com/demisto/etc/issues/19669

    The script was throwing `local variable 'latest_incident_in_xdr' referenced before assignment`

    Given
    - xdr script

    When
    - script executed and xdr_incident_sync raised an exception

    Then
    - the xdr_script should not fail on syntax error: `local variable 'latest_incident_in_xdr'
    referenced before assignment`
    - the script should return error entry with message `Raised exception`
    """
    import XDRSyncScript as xdr_script
    import demistomock as demisto
    import sys

    mocker.patch.object(xdr_script, 'xdr_incident_sync', side_effect=Exception('Raised exception'))
    mocker.patch.object(demisto, 'results')

    # mocking exit we make sure that return_error don't stop the test - bad practice but have no choise for now
    mocker.patch.object(sys, 'exit')
    mocker.patch.object(demisto, 'executeCommand', return_value=[{
        'Contents': {
            'id': '1000'
        },
        'Type': entryTypes['note'],
        'Format': formats['json']
    }])
    args = {
        'interval': '1'
    }
    with capfd.disabled():  # this line should prevent the test failing on writing to demisto.error => print => stdout
        xdr_script.main(args)

    assert demisto.results.call_count == 1
    # call_args is tuple (args list, kwargs). we only need the first one
    results = demisto.results.call_args[0]
    assert len(results) == 1
    assert results[0]['Type'] == entryTypes['error']
    assert results[0]['Contents'] == 'Raised exception'


def create_test_incident(no_assignee=False, severity=None):
    xdr_incident = copy.deepcopy(INCIDENT_FROM_XDR)
    demisto_incident = copy.deepcopy(INCIDENT_IN_DEMISTO)

    if no_assignee:
        xdr_incident['assigned_user_pretty_name'] = None
        xdr_incident[ASSIGNED_USER_MAIL_XDR_FIELD] = None

        demisto_incident['xdrassignedusermail'] = ''
        demisto_incident['xdrassigneduserprettyname'] = ''

    if severity:
        xdr_incident[SEVERITY_XDR_FIELD] = severity

        # 3=high, 2=medium, 1=low
        demisto_incident['severity'] = {
            'high': 3,
            'medium': 2,
            'low': 1
        }[severity]

    xdr_incident_from_previous_run = copy.deepcopy(xdr_incident)

    if 'alerts' in xdr_incident_from_previous_run:
        del xdr_incident_from_previous_run['alerts']
    if 'file_artifacts' in xdr_incident_from_previous_run:
        del xdr_incident_from_previous_run['file_artifacts']
    if 'network_artifacts' in xdr_incident_from_previous_run:
        del xdr_incident_from_previous_run['network_artifacts']

    return demisto_incident, xdr_incident_from_previous_run, xdr_incident


def get_execute_command_call(mocked_execute_command, script_name):
    """

    Returns:
        is_called - True means script was called via demisto.executeCommand
        script_args - The arguments that demisto.executeCommand was called with

    """
    if mocked_execute_command.call_count == 0:
        return False, None

    for call_args in mocked_execute_command.call_args_list:
        if call_args[0][0] == script_name:
            return True, call_args[0][1]

    return False, None


def test_incident_was_modified_in_xdr(mocker):
    """
    - incident in demisto
    - incident in xdr

    - incident assignee in xdr is updated by the user to be foo@test.com

    - XDRSyncScript executed

    - ensure incident assignee in demisto is updated to be foo@test.com
    - ensure current playbook was re-executed
    - ensure XDRSyncScript is scheduled to be executed in the next internal with
        xdr_incident_from_previous_run has assignee foo@test.com
    """
    import XDRSyncScript as xdr_script
    import demistomock as demisto

    # - incident in demisto
    # - incident in xdr
    demisto_incident, xdr_incident_from_previous_run, xdr_incident_latest = create_test_incident(no_assignee=True)

    # - incident assignee in xdr is updated by the user to be foo@test.com
    xdr_incident_latest[ASSIGNED_USER_MAIL_XDR_FIELD] = 'foo@test.com'
    xdr_incident_latest[MODIFICATION_TIME_XDR_FIELD] = xdr_incident_from_previous_run[MODIFICATION_TIME_XDR_FIELD] + 100

    mocker.patch.object(demisto, 'incidents', return_value=[demisto_incident])
    mocker.patch.object(demisto, 'results')
    mocker.patch.object(demisto, 'executeCommand', return_value=[{
        'Contents': {
            'incident': xdr_incident_latest,
            'alerts': {
                'data': xdr_incident_latest['alerts']
            },
            'file_artifacts': {
                'data': xdr_incident_latest['file_artifacts']
            },
            'network_artifacts': {
                'data': xdr_incident_latest['network_artifacts']
            }
        },
        'HumanReadable': 'nla',
        'Type': entryTypes['note'],
        'Format': formats['json']
    }])
    args = {
        'interval': '1',
        'verbose': 'true',
        'first': 'false',
        ASSIGNED_USER_MAIL_XDR_FIELD: 'xdrassignedusermail',
        'xdr_alerts': 'xdralerts',
        'xdr_file_artifacts': 'xdrfileartifacts',
        'xdr_network_artifacts': 'xdrnetworkartifacts',
        'xdr_incident_from_previous_run': json.dumps(xdr_incident_from_previous_run)
    }
    xdr_script.main(args)

    # - ensure incident assignee in demisto is updated to be foo@test.com
    is_called, set_incident_args = get_execute_command_call(demisto.executeCommand, 'setIncident')
    assert is_called is True
    assert set_incident_args['xdrassignedusermail'] == 'foo@test.com'

    # - ensure current playbook was re-executed
    is_playbook_executed, _ = get_execute_command_call(demisto.executeCommand, 'setPlaybook')
    assert is_playbook_executed is True

    # - ensure XDRSyncScript is scheduled to be executed in the next internal with
    # xdr_incident_from_previous_run has assignee foo@test.com
    is_called, scheduled_command_args = get_execute_command_call(demisto.executeCommand, 'ScheduleCommand')
    assert is_called is True

    scheduled_command = scheduled_command_args['command']
    assert '"assigned_user_mail": "foo@test.com"' in scheduled_command


def test_incident_was_modified_in_demisto(mocker):
    """
    - incident in demisto and in XDR with low severity

    - incident severity in Demisto is updated by the user to be "high"

    - XDRSyncScript executed

    - ensure incident severity in XDR is updated to be high
    - ensure playbook is NOT executed
    - ensure XDRSyncScript is scheduled to be executed in the next internal with
        xdr_incident_from_previous_run has severity=high
    """
    import XDRSyncScript as xdr_script
    import demistomock as demisto

    # - incident in demisto
    # - incident in xdr
    demisto_incident, xdr_incident_from_previous_run, xdr_incident_latest = create_test_incident(severity='low')

    # - incident severity in Demisto is updated by the user to be "high"
    demisto_incident['severity'] = 3

    # - XDRSyncScript executed
    mocker.patch.object(demisto, 'incidents', return_value=[demisto_incident])
    mocker.patch.object(demisto, 'results')
    mocker.patch.object(demisto, 'executeCommand', return_value=[{
        'Contents': {
            'incident': xdr_incident_latest,
            'alerts': {
                'data': xdr_incident_latest['alerts']
            },
            'file_artifacts': {
                'data': xdr_incident_latest['file_artifacts']
            },
            'network_artifacts': {
                'data': xdr_incident_latest['network_artifacts']
            }
        },
        'HumanReadable': 'nla',
        'Type': entryTypes['note'],
        'Format': formats['json']
    }])
    args = {
        'interval': '1',
        'verbose': 'true',
        'first': 'false',
        SEVERITY_XDR_FIELD: 'severity',
        'xdr_alerts': 'xdralerts',
        'xdr_file_artifacts': 'xdrfileartifacts',
        'xdr_network_artifacts': 'xdrnetworkartifacts',
        'xdr_incident_from_previous_run': json.dumps(xdr_incident_from_previous_run)
    }
    xdr_script.main(args)

    # - ensure incident severity in XDR is updated to be high
    is_called, xdr_update_args = get_execute_command_call(demisto.executeCommand, 'xdr-update-incident')
    assert is_called is True
    assert xdr_update_args[MANUAL_SEVERITY_XDR_FIELD] == 'high'

    # - ensure playbook is NOT executed
    is_playbook_executed, _ = get_execute_command_call(demisto.executeCommand, 'setPlaybook')
    assert not is_playbook_executed

    # - ensure XDRSyncScript is scheduled to be executed in the next internal with
    #     xdr_incident_from_previous_run has severity=high
    is_called, scheduled_command_args = get_execute_command_call(demisto.executeCommand, 'ScheduleCommand')
    assert is_called is True


EXPECTED_INCIDENT = {
    'incident_id': '697567',
    'manual_severity': None,
    'assigned_user_mail': None,
    'high_severity_alert_count': None,
    'host_count': None,
    'xdr_url': 'http://example.com/incident-view/697567',
    'assigned_user_pretty_name': '',
    'alert_count': 1,
    'med_severity_alert_count': None,
    'user_count': None, 'severity': 1,
    'low_severity_alert_count': None,
    'status': 'new',
    'description': 'WildFire Malware detected on host HostNameFFM8VIP9',
    'resolve_comment': None,
    'notes': None,
    'modification_time': 1559463309323
}


def test_create_incident_from_saved_data_without_extra_data():
    """
    Given
    - incident in demisto
    - fields_mapping:
        status: xdrstatus,
        severity: xdrseverity,
        manual_severity: severity
    - include_extra_data = False

    When
    - creating an incident object from the context incident

    Then
    - ensure date fields are parsed correctly
    - ensure all relevant fields are present

    """
    fields_mapping = {
        "alert_count": "xdralertcount",
        "assigned_user_mail": "xdrassigneduseremail",
        "assigned_user_pretty_name": "xdrassigneduserprettyname",
        "description": "xdrdescription",
        "high_severity_alert_count": "xdrhighseverityalertcount",
        "host_count": "xdrhostcount",
        "incident_id": "10",
        "low_severity_alert_count": "xdrlowseverityalertcount",
        "manual_severity": "xdrmanualseverity",
        "med_severity_alert_count": "xdrmediumseverityalertcount",
        "modification_time": "xdrmodificationtime",
        "notes": "xdrnotes",
        "resolve_comment": "xdrresolvecomment",
        "severity": "severity",
        "status": "xdrstatus",
        "user_count": "xdrusercount",
        "xdr_url": "xdrurl"
    }

    incident_from_context = copy.deepcopy(INCIDENT_IN_DEMISTO)

    created_incident = xdr_script.create_incident_from_saved_data(incident_from_context, fields_mapping)

    assert created_incident == EXPECTED_INCIDENT


EXPECTED_INCIDENT_EXTRA_DATA = {
    "xdralerts": [
        {
            "category": "WildFirePostDetection",
            "action_pretty": "Detected (Reported)",
            "description": "Suspicious executable detected",
            "severity": "high",
            "host_ip": "8.8.8.8",
            "source": "Traps",
            "alert_id": "50820",
            "host_name": "HostNameFFM8VIP9",
            "detection_timestamp": 1559215835437,
            "action": "REPORTED",
            "user_name": "N/A",
            "name": "WildFire Malware"
        }
    ],
    "xdrfileartifacts": [
        {
            "file_signature_status": "SIGNATURE_UNAVAILABLE",
            "is_process": None,
            "file_name": "LCTGSK7IML.docx",
            "file_wildfire_verdict": "UNKNOWN",
            "alert_count": 1,
            "is_malicious": None,
            "is_manual": None,
            "file_signature_vendor_name": None,
            "type": "HASH",
            "file_sha256": "384654fa409c7a500a4a843d33a005c9d670d4845d3a9e096efc8b00ad05a621"
        }
    ],
    "xdrnetworkartifacts": []
}


def test_create_incident_from_saved_data_with_extra_data():
    """
    Given
    - incident in demisto
    - fields_mapping:
        status: xdrstatus,
        severity: xdrseverity,
        manual_severity: severity
    - include_extra_data = True

    When
    - creating an incident object from the context incident

    Then
    - ensure date fields are parsed correctly
    - ensure all relevant fields are present

    """
    fields_mapping = {
        "status": "xdrstatus",
        "severity": "severity"
    }

    incident_from_context = copy.deepcopy(INCIDENT_IN_DEMISTO)

    created_incident = xdr_script.create_incident_from_saved_data(incident_from_context, fields_mapping, True)

    assert created_incident == EXPECTED_INCIDENT_EXTRA_DATA


def test_create_incident_from_saved_data_without_extra_data_old_incident():
    """
    Given
    - an old incident in demisto (which means that 'xdrmodificationtime' is not mapped  but present in 'labels')
    - fields_mapping:
        {
        "alert_count": "xdralertcount",
        "assigned_user_mail": "xdrassigneduseremail",
        "assigned_user_pretty_name": "xdrassigneduserprettyname",
        "description": "xdrdescription",
        "high_severity_alert_count": "xdrhighseverityalertcount",
        "host_count": "xdrhostcount",
        "incident_id": "10",
        "low_severity_alert_count": "xdrlowseverityalertcount",
        "manual_severity": "xdrmanualseverity",
        "med_severity_alert_count": "xdrmediumseverityalertcount",
        "modification_time": "xdrmodificationtime",
        "notes": "xdrnotes",
        "resolve_comment": "xdrresolvecomment",
        "severity": "severity",
        "status": "xdrstatus",
        "user_count": "xdrusercount",
        "xdr_url": "xdrurl"
    }
    - include_extra_data = False

    When
    - creating an incident object from the context incident

    Then
    - ensure date fields are parsed correctly
    - ensure all relevant fields are present

    """
    fields_mapping = {
        "alert_count": "xdralertcount",
        "assigned_user_mail": "xdrassigneduseremail",
        "assigned_user_pretty_name": "xdrassigneduserprettyname",
        "description": "xdrdescription",
        "high_severity_alert_count": "xdrhighseverityalertcount",
        "host_count": "xdrhostcount",
        "incident_id": "10",
        "low_severity_alert_count": "xdrlowseverityalertcount",
        "manual_severity": "xdrmanualseverity",
        "med_severity_alert_count": "xdrmediumseverityalertcount",
        "modification_time": "xdrmodificationtime",
        "notes": "xdrnotes",
        "resolve_comment": "xdrresolvecomment",
        "severity": "severity",
        "status": "xdrstatus",
        "user_count": "xdrusercount",
        "xdr_url": "xdrurl"
    }

    incident_from_context = copy.deepcopy(OLD_INCIDENT_IN_DEMISTO)

    created_incident = xdr_script.create_incident_from_saved_data(incident_from_context, fields_mapping)

    assert created_incident == EXPECTED_INCIDENT


def test_create_incident_from_saved_data_old_incident_no_modification_time():
    """
    Given
    - an old incident in demisto (which means that 'xdrmodificationtime' is not mapped and not in 'labels')
    - fields_mapping:
        {
        "alert_count": "xdralertcount",
        "assigned_user_mail": "xdrassigneduseremail",
        "assigned_user_pretty_name": "xdrassigneduserprettyname",
        "description": "xdrdescription",
        "high_severity_alert_count": "xdrhighseverityalertcount",
        "host_count": "xdrhostcount",
        "incident_id": "10",
        "low_severity_alert_count": "xdrlowseverityalertcount",
        "manual_severity": "xdrmanualseverity",
        "med_severity_alert_count": "xdrmediumseverityalertcount",
        "modification_time": "xdrmodificationtime",
        "notes": "xdrnotes",
        "resolve_comment": "xdrresolvecomment",
        "severity": "severity",
        "status": "xdrstatus",
        "user_count": "xdrusercount",
        "xdr_url": "xdrurl"
    }
    - include_extra_data = False

    When
    - creating an incident object from the context incident

    Then
    - ensure date fields are parsed correctly
    - ensure all relevant fields are present

    """
    fields_mapping = {
        "alert_count": "xdralertcount",
        "assigned_user_mail": "xdrassigneduseremail",
        "assigned_user_pretty_name": "xdrassigneduserprettyname",
        "description": "xdrdescription",
        "high_severity_alert_count": "xdrhighseverityalertcount",
        "host_count": "xdrhostcount",
        "incident_id": "10",
        "low_severity_alert_count": "xdrlowseverityalertcount",
        "manual_severity": "xdrmanualseverity",
        "med_severity_alert_count": "xdrmediumseverityalertcount",
        "modification_time": "xdrmodificationtime",
        "notes": "xdrnotes",
        "resolve_comment": "xdrresolvecomment",
        "severity": "severity",
        "status": "xdrstatus",
        "user_count": "xdrusercount",
        "xdr_url": "xdrurl"
    }

    EXPECTED_INCIDENT['modification_time'] = 0

    incident_from_context = copy.deepcopy(OLD_INCIDENT_IN_DEMISTO)
    incident_from_context["labels"] = []

    created_incident = xdr_script.create_incident_from_saved_data(incident_from_context, fields_mapping)

    assert created_incident['modification_time'] == 0
    assert created_incident == EXPECTED_INCIDENT