Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ciac 8941/enhancement/cortex xdr flexible close reason mappings mirroring #33140

Merged
Show file tree
Hide file tree
Changes from 67 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
f767be4
Enhancing Cortex XDR IR integration with custom close-reason mapping …
barryyosi-panw Feb 22, 2024
4451db6
XSOAR->XDR custom close-reason mapping support
barryyosi-panw Feb 26, 2024
9949f31
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Feb 26, 2024
73d5057
lint
barryyosi-panw Feb 26, 2024
c7ef2d3
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Feb 26, 2024
77282cc
update RN
michal-dagan Feb 26, 2024
712a6dd
update RN
michal-dagan Feb 26, 2024
9a6b821
Updated release notes
barryyosi-panw Feb 26, 2024
2f1b421
Merge
barryyosi-panw Feb 26, 2024
56c546f
Fixes
barryyosi-panw Feb 28, 2024
59817f0
Merge master
barryyosi-panw Feb 29, 2024
3fcb374
Unittests
barryyosi-panw Feb 29, 2024
e951714
Documentation
barryyosi-panw Feb 29, 2024
cbbeb31
pre-commit fixes
barryyosi-panw Feb 29, 2024
7336431
unittests labeling
barryyosi-panw Feb 29, 2024
e856cca
updated RN
barryyosi-panw Feb 29, 2024
d12e4f9
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Feb 29, 2024
5a16b8f
autopep8
barryyosi-panw Feb 29, 2024
c47ee9c
Merge remote-tracking branch 'origin/CIAC-8941/Enhancement/Cortex-XDR…
barryyosi-panw Feb 29, 2024
61af589
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Feb 29, 2024
8246187
autopep8
barryyosi-panw Feb 29, 2024
f0463ea
Merge remote-tracking branch 'origin/CIAC-8941/Enhancement/Cortex-XDR…
barryyosi-panw Feb 29, 2024
a30a49f
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Feb 29, 2024
7f44879
Describing `comma_separated_mapping_to_dict()`
barryyosi-panw Feb 29, 2024
dbb33f9
Merge remote-tracking branch 'origin/CIAC-8941/Enhancement/Cortex-XDR…
barryyosi-panw Feb 29, 2024
9a3f7f8
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Feb 29, 2024
618e074
Updating RN
barryyosi-panw Feb 29, 2024
780b0ef
Merge remote-tracking branch 'origin/CIAC-8941/Enhancement/Cortex-XDR…
barryyosi-panw Feb 29, 2024
77485db
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 1, 2024
5418183
mypy
barryyosi-panw Mar 1, 2024
78610e6
Merge remote-tracking branch 'origin/CIAC-8941/Enhancement/Cortex-XDR…
barryyosi-panw Mar 1, 2024
56ba40c
mypy
barryyosi-panw Mar 1, 2024
c1a4e05
autopep8
barryyosi-panw Mar 1, 2024
7acd01a
merge master
barryyosi-panw Mar 3, 2024
ba70e89
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 3, 2024
020b003
Update RN
barryyosi-panw Mar 3, 2024
6b3520b
Merge remote-tracking branch 'origin/CIAC-8941/Enhancement/Cortex-XDR…
barryyosi-panw Mar 3, 2024
f668921
yaml update
barryyosi-panw Mar 3, 2024
43dad8a
Merged master into current branch.
Mar 3, 2024
1d42de7
Bump pack from version Base to 1.33.38.
Mar 3, 2024
dd628d5
Update Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.yml
barryyosi-panw Mar 3, 2024
70dd0e3
Update Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.yml
barryyosi-panw Mar 3, 2024
42f87d3
Update Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.yml
barryyosi-panw Mar 3, 2024
3578650
Update Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.yml
barryyosi-panw Mar 3, 2024
d776479
Update Packs/CortexXDR/Integrations/CortexXDRIR/README.md
barryyosi-panw Mar 3, 2024
d78eb7b
Update Packs/ctf01/ReleaseNotes/1_0_10.md
barryyosi-panw Mar 3, 2024
582b4b9
Update Packs/CortexXDR/ReleaseNotes/6_1_18.md
barryyosi-panw Mar 3, 2024
0a94811
Update Packs/CortexXDR/Integrations/CortexXDRIR/README.md
barryyosi-panw Mar 3, 2024
4d168de
Update Packs/CortexXDR/Integrations/CortexXDRIR/README.md
barryyosi-panw Mar 3, 2024
60d2c54
Merged master into current branch.
Mar 3, 2024
d8ee592
Bump pack from version Core to 3.0.22.
Mar 3, 2024
6c944c9
Bump pack from version CortexXDR to 6.1.19.
Mar 3, 2024
4ba41d5
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 3, 2024
e2570eb
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 3, 2024
1820cae
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 3, 2024
180a772
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 3, 2024
112a6bf
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 4, 2024
fb9dc18
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 4, 2024
743dbf9
PR & demo fixes
barryyosi-panw Mar 4, 2024
8ccbacf
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 4, 2024
470be0d
PR fixes
barryyosi-panw Mar 4, 2024
b076978
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 4, 2024
7e96659
Testing test module
barryyosi-panw Mar 5, 2024
5296bba
Merge remote-tracking branch 'origin/CIAC-8941/Enhancement/Cortex-XDR…
barryyosi-panw Mar 5, 2024
f992023
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 5, 2024
310f990
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 6, 2024
6bda322
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 6, 2024
e5b6c52
Merged master into current branch.
Mar 6, 2024
baa4eea
Bump pack from version CortexXDR to 6.1.20.
Mar 6, 2024
9f5ce74
Merge branch 'master' into CIAC-8941/Enhancement/Cortex-XDR-Flexible-…
barryyosi-panw Mar 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
74 changes: 51 additions & 23 deletions Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule.py
Expand Up @@ -13,18 +13,18 @@

XSOAR_RESOLVED_STATUS_TO_XDR = {
'Other': 'resolved_other',
'Duplicate': 'resolved_duplicate',
'Duplicate': 'resolved_duplicate_incident',
'False Positive': 'resolved_false_positive',
'Resolved': 'resolved_true_positive',
'Resolved - Security Testing': 'resolved_security_testing',
'Security Testing': 'resolved_security_testing',
}

XDR_RESOLVED_STATUS_TO_XSOAR = {
'resolved_known_issue': 'Other',
'resolved_duplicate': 'Duplicate',
'resolved_duplicate_incident': 'Duplicate',
'resolved_false_positive': 'False Positive',
'resolved_true_positive': 'Resolved',
'resolved_security_testing': 'Resolved - Security Testing',
'resolved_security_testing': 'Security Testing',
'resolved_other': 'Other',
'resolved_auto': 'Resolved'
}
Expand Down Expand Up @@ -346,7 +346,7 @@ def get_endpoints(self,
endpoints = reply.get('reply').get('endpoints', [])
return endpoints

def set_endpoints_alias(self, filters: list[dict[str, str]], new_alias_name: str | None) -> dict: # pragma: no cover
def set_endpoints_alias(self, filters: list[dict[str, str]], new_alias_name: str | None) -> dict: # pragma: no cover
"""
This func is used to set the alias name of an endpoint.

Expand Down Expand Up @@ -934,8 +934,7 @@ def get_endpoint_device_control_violations(self, endpoint_ids: list, type_of_vio
ip_list: list, vendor: list, vendor_id: list, product: list,
product_id: list,
serial: list,
hostname: list, violation_ids: list, username: list) \
-> Dict[str, Any]:
hostname: list, violation_ids: list, username: list) -> Dict[str, Any]:
arg_list = {'type': type_of_violation,
'endpoint_id_list': endpoint_ids,
'ip_list': ip_list,
Expand Down Expand Up @@ -1709,8 +1708,8 @@ def validate_args_scan_commands(args):
'and without any other filters. This may cause performance issues.\n' \
'To scan/abort scan some of the endpoints, please use the filter arguments.'
if all_:
if endpoint_id_list or dist_name or gte_first_seen or gte_last_seen or lte_first_seen or lte_last_seen \
or ip_list or group_name or platform or alias or hostname:
if (endpoint_id_list or dist_name or gte_first_seen or gte_last_seen or lte_first_seen or lte_last_seen
or ip_list or group_name or platform or alias or hostname):
raise Exception(err_msg)
elif not endpoint_id_list and not dist_name and not gte_first_seen and not gte_last_seen \
and not lte_first_seen and not lte_last_seen and not ip_list and not group_name and not platform \
Expand Down Expand Up @@ -2849,13 +2848,44 @@ def handle_outgoing_incident_owner_sync(update_args):

def handle_user_unassignment(update_args):
if ('assigned_user_mail' in update_args and update_args.get('assigned_user_mail') in ['None', 'null', '', None]) \
or ('assigned_user_pretty_name' in update_args
and update_args.get('assigned_user_pretty_name') in ['None', 'null', '', None]):
or ('assigned_user_pretty_name' in update_args
and update_args.get('assigned_user_pretty_name') in ['None', 'null', '', None]):
update_args['unassign_user'] = 'true'
update_args['assigned_user_mail'] = None
update_args['assigned_user_pretty_name'] = None


def resolve_xdr_close_reason(xsoar_close_reason: str) -> str:
"""
Resolving XDR close reason from possible custom XSOAR->XDR close-reason mapping or default mapping.
:param xsoar_close_reason: XSOAR raw status/close reason e.g. 'False Positive'.
:return: XDR close-reason in snake_case format e.g. 'resolved_false_positive'.
"""
# Initially setting the close reason according to the default mapping.
xdr_close_reason = XSOAR_RESOLVED_STATUS_TO_XDR.get(xsoar_close_reason, 'Other')
# Reading custom XSOAR->XDR close-reason mapping.
custom_xsoar_to_xdr_close_reason_mapping = comma_separated_mapping_to_dict(
demisto.params().get("custom_xsoar_to_xdr_close_reason_mapping")
)

# Overriding default close-reason mapping if there exists a custom one.
if xsoar_close_reason in custom_xsoar_to_xdr_close_reason_mapping:
xdr_close_reason_candidate = custom_xsoar_to_xdr_close_reason_mapping[xsoar_close_reason]
# Transforming resolved close-reason into snake_case format with known prefix to match XDR status format.
demisto.debug(
f"resolve_xdr_close_reason XSOAR->XDR custom close-reason exists, using {xsoar_close_reason}={xdr_close_reason}")
xdr_close_reason_candidate = "resolved_" + "_".join(xdr_close_reason_candidate.lower().split(" "))

if xdr_close_reason_candidate not in XDR_RESOLVED_STATUS_TO_XSOAR:
demisto.debug("Warning: Provided XDR close-reason does not exist. Using default XDR close-reason mapping. ")
else:
xdr_close_reason = xdr_close_reason_candidate
else:
demisto.debug(f"resolve_xdr_close_reason using default mapping {xsoar_close_reason}={xdr_close_reason}")

return xdr_close_reason


def handle_outgoing_issue_closure(remote_args):
incident_id = remote_args.remote_incident_id
demisto.debug(f"handle_outgoing_issue_closure {incident_id=}")
Expand All @@ -2866,13 +2896,13 @@ def handle_outgoing_issue_closure(remote_args):
# force closing remote incident only if:
# The XSOAR incident is closed
# and the remote incident isn't already closed
if remote_args.inc_status == 2 and \
current_remote_status not in XDR_RESOLVED_STATUS_TO_XSOAR and close_reason:

if remote_args.inc_status == 2 and current_remote_status not in XDR_RESOLVED_STATUS_TO_XSOAR and close_reason:
if close_notes := update_args.get('closeNotes'):
demisto.debug(f"handle_outgoing_issue_closure {incident_id=} {close_notes=}")
update_args['resolve_comment'] = close_notes
update_args['status'] = XSOAR_RESOLVED_STATUS_TO_XDR.get(close_reason, 'Other')

xdr_close_reason = resolve_xdr_close_reason(close_reason)
update_args['status'] = xdr_close_reason
demisto.debug(f"handle_outgoing_issue_closure Closing Remote incident {incident_id=} with status {update_args['status']}")


Expand Down Expand Up @@ -3148,7 +3178,6 @@ def get_script_code_command(client: CoreClient, args: Dict[str, str]) -> Tuple[s
requires_polling_arg=False # means it will always be default to poll, poll=true
)
def script_run_polling_command(args: dict, client: CoreClient) -> PollResult:

if action_id := args.get('action_id'):
response = client.get_script_execution_status(action_id)
general_status = response.get('reply', {}).get('general_status') or ''
Expand Down Expand Up @@ -3740,7 +3769,6 @@ def create_request_filters(


def args_to_request_filters(args):

if set(args.keys()) & { # check if any filter argument was provided
'endpoint_id_list', 'dist_name', 'ip_list', 'group_name', 'platform', 'alias_name',
'isolate', 'hostname', 'status', 'first_seen_gte', 'first_seen_lte', 'last_seen_gte', 'last_seen_lte'
Expand Down Expand Up @@ -3814,7 +3842,6 @@ def parse_risky_users_or_hosts(user_or_host_data: dict[str, Any],
score_header: str,
description_header: str
) -> dict[str, Any]:

reasons = user_or_host_data.get('reasons', [])
return {
id_header: user_or_host_data.get('id'),
Expand Down Expand Up @@ -4046,13 +4073,14 @@ def list_risky_users_or_host_command(client: CoreClient, command: str, args: dic
ValueError: If the API connection fails.

"""

def _warn_if_module_is_disabled(e: DemistoException) -> None:
if (
e is not None
and e.res is not None
and e.res.status_code == 500
and 'No identity threat' in str(e)
and "An error occurred while processing XDR public API" in e.message
e is not None
and e.res is not None
and e.res.status_code == 500
and 'No identity threat' in str(e)
and "An error occurred while processing XDR public API" in e.message
):
return_warning(f'Please confirm the XDR Identity Threat Module is enabled.\nFull error message: {e}', exit=True)

Expand Down
Expand Up @@ -9,7 +9,7 @@

import demistomock as demisto
from CommonServerPython import Common, tableToMarkdown, pascalToSpace, DemistoException
from CoreIRApiModule import CoreClient, handle_outgoing_issue_closure
from CoreIRApiModule import CoreClient, handle_outgoing_issue_closure, XSOAR_RESOLVED_STATUS_TO_XDR
from CoreIRApiModule import add_tag_to_endpoints_command, remove_tag_from_endpoints_command, quarantine_files_command, \
isolate_endpoint_command, list_user_groups_command, parse_user_groups, list_users_command, list_roles_command, \
change_user_role_command, list_risky_users_or_host_command, enrich_error_message_id_group_role, get_incidents_command
Expand All @@ -18,7 +18,6 @@
base_url='https://test_api.com/public_api/v1', headers={}
)


Core_URL = 'https://api.xdrurl.com'

''' HELPER FUNCTIONS '''
Expand Down Expand Up @@ -544,7 +543,7 @@ def test_allowlist_files_command_with_more_than_one_file(requests_mock):
test_data = load_test_data('test_data/blocklist_allowlist_files_success.json')
expected_command_result = {
'CoreApiModule.allowlist.added_hashes.fileHash(val.fileHash == obj.fileHash)':
test_data['multi_command_args']['hash_list']
test_data['multi_command_args']['hash_list']
}
requests_mock.post(f'{Core_URL}/public_api/v1/hash_exceptions/allowlist/', json=test_data['api_response'])

Expand Down Expand Up @@ -859,13 +858,14 @@ def test_handle_outgoing_issue_closure_close_reason(mocker):
"""
from CoreIRApiModule import handle_outgoing_issue_closure
from CommonServerPython import UpdateRemoteSystemArgs
remote_args = UpdateRemoteSystemArgs({'delta': {'assigned_user_mail': 'None', 'closeReason': 'Resolved - Security Testing'},
remote_args = UpdateRemoteSystemArgs({'delta': {'assigned_user_mail': 'None', 'closeReason': 'Security Testing'},
'status': 2, 'inc_status': 2, 'data': {'status': 'other'}})
request_data_log = mocker.patch.object(demisto, 'debug')
handle_outgoing_issue_closure(remote_args)

assert "handle_outgoing_issue_closure Closing Remote incident incident_id=None with status resolved_security_testing" in request_data_log.call_args[ # noqa: E501
0][0]
assert "handle_outgoing_issue_closure Closing Remote incident incident_id=None with status resolved_security_testing" in \
request_data_log.call_args[ # noqa: E501
0][0]


def test_get_update_args_close_incident():
Expand Down Expand Up @@ -3168,8 +3168,8 @@ def test_endpoint_alias_change_command__no_filters(mocker):
},
{
"err_msg": "An error occurred while processing XDR public API - No endpoint "
"was found "
"for creating the requested action",
"was found "
"for creating the requested action",
"status_code": 500,
},
False,
Expand Down Expand Up @@ -3444,7 +3444,7 @@ def test_parse_user_groups(data: dict[str, Any], expected_results: list[dict[str
[
({"group_names": "test"}, "Error: Group test was not found. Full error message: Group 'test' was not found"),
({"group_names": "test, test2"}, "Error: Group test was not found. Note: If you sent more than one group name, "
"they may not exist either. Full error message: Group 'test' was not found")
"they may not exist either. Full error message: Group 'test' was not found")
]
)
def test_list_user_groups_command_raise_exception(mocker, test_data: dict[str, str], excepted_error: str):
Expand Down Expand Up @@ -3844,3 +3844,67 @@ def test_handle_outgoing_issue_closure(args, expected_delta):
remote_args = UpdateRemoteSystemArgs(args)
handle_outgoing_issue_closure(remote_args)
assert remote_args.delta == expected_delta


@pytest.mark.parametrize('custom_mapping, expected_resolved_status',
[
("Other=Other,Duplicate=Other,False Positive=False Positive,Resolved=True Positive",
["resolved_other", "resolved_other", "resolved_false_positive", "resolved_true_positive",
"resolved_security_testing"]),

("Other=True Positive,Duplicate=Other,False Positive=False Positive,Resolved=True Positive",
["resolved_true_positive", "resolved_other", "resolved_false_positive",
"resolved_true_positive", "resolved_security_testing"]),

("Duplicate=Other", ["resolved_other", "resolved_other", "resolved_false_positive",
"resolved_true_positive", "resolved_security_testing"]),

# Expecting default mapping to be used when no mapping provided.
("", list(XSOAR_RESOLVED_STATUS_TO_XDR.values())),

# Expecting default mapping to be used when improper mapping is provided.
("Duplicate=RANDOM1, Other=Random2", list(XSOAR_RESOLVED_STATUS_TO_XDR.values())),

("Random1=Duplicate Incident", list(XSOAR_RESOLVED_STATUS_TO_XDR.values())),

# Expecting default mapping to be used when improper mapping *format* is provided.
("Duplicate=Other False Positive=Other", list(XSOAR_RESOLVED_STATUS_TO_XDR.values())),

# Expecting default mapping to be used for when improper key-value pair *format* is provided.
("Duplicate=Other, False Positive=Other True Positive=Other, Other=True Positive",
["resolved_true_positive", "resolved_other", "resolved_false_positive",
"resolved_true_positive", "resolved_security_testing"]),

],
ids=["case-1", "case-2", "case-3", "empty-case", "improper-input-case-1", "improper-input-case-2",
"improper-input-case-3", "improper-input-case-4"]
)
def test_xsoar_to_xdr_flexible_close_reason_mapping(capfd, mocker, custom_mapping, expected_resolved_status):
"""
Given:
- A custom XSOAR->XDR close-reason mapping
- Expected resolved XDR status according to the custom mapping.
When
- Handling outgoing issue closure (handle_outgoing_issue_closure(...) executed).
Then
- The resolved XDR statuses match the expected statuses for all possible XSOAR close-reasons.
"""
from CoreIRApiModule import handle_outgoing_issue_closure
from CommonServerPython import UpdateRemoteSystemArgs

mocker.patch.object(demisto, 'params', return_value={"mirror_direction": "Both",
"custom_xsoar_to_xdr_close_reason_mapping": custom_mapping})

all_xsoar_close_reasons = XSOAR_RESOLVED_STATUS_TO_XDR.keys()
for i, close_reason in enumerate(all_xsoar_close_reasons):
remote_args = UpdateRemoteSystemArgs({'delta': {'closeReason': close_reason},
'status': 2,
'inc_status': 2,
'data': {'status': 'other'}
})
# Overcoming expected non-empty stderr test failures (Errors are submitted to stderr when improper mapping is provided).
with capfd.disabled():
handle_outgoing_issue_closure(remote_args)

assert remote_args.delta.get('status')
assert remote_args.delta['status'] == expected_resolved_status[i]
6 changes: 6 additions & 0 deletions Packs/Base/ReleaseNotes/1_33_38.md
@@ -0,0 +1,6 @@

#### Scripts

##### CommonServerPython

Added a utility function `comma_separated_mapping_to_dict` that gets a comma-separated mapping `key1=value1,key2=value2,...` and transforms it into a dictionary object.
41 changes: 41 additions & 0 deletions Packs/Base/Scripts/CommonServerPython/CommonServerPython.py
Expand Up @@ -11751,6 +11751,47 @@ def data_error_handler(res):
demisto.updateModuleHealth({'{data_type}Pulled'.format(data_type=data_type): data_size})


def comma_separated_mapping_to_dict(raw_text):
"""
Transforming a textual comma-separated mapping into a dictionary object.

:type raw_text: ``str``
:param raw_text: Comma-separated mapping e.g ('key1=value1', 'key2=value2', ...)

:rtype: ``dict``
:return: Validated dictionary of the raw mapping e.g {'key1': 'value1', 'key2': 'value2', ...}
"""
demisto.debug("comma_separated_mapping_to_dict "
">> Resolving comma-separated input mapping: {raw_text}".format(raw_text=raw_text))

mapping_dict = {} # type: Dict[str, str]
# If a proper mapping was not provided, return an empty dict.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment is redundant

if not raw_text:
return mapping_dict

key_value_pairs = raw_text.split(',')

for pair in key_value_pairs:
# Trimming trailing whitespace
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment is redundant

pair = pair.strip()

try:
key, value = pair.split('=')
except ValueError:
demisto.error("Error: Invalid mapping was provided. "
"Expected comma-separated mapping of format `key1=value1, key2=value2, ...`")
key = value = ''

if key in mapping_dict:
demisto.debug(
"comma_separated_mapping_to_dict "
"Warning: duplicate key provided for {key}: using latter value: {value}".format(key=key, value=value)
)
mapping_dict[key] = value
demisto.debug("comma_separated_mapping_to_dict << Resolved mapping: {mapping_dict}".format(mapping_dict=mapping_dict))
return mapping_dict


###########################################
# DO NOT ADD LINES AFTER THIS ONE #
###########################################
Expand Down
2 changes: 1 addition & 1 deletion Packs/Base/pack_metadata.json
Expand Up @@ -2,7 +2,7 @@
"name": "Base",
"description": "The base pack for Cortex XSOAR.",
"support": "xsoar",
"currentVersion": "1.33.37",
"currentVersion": "1.33.38",
"author": "Cortex XSOAR",
"serverMinVersion": "6.0.0",
"url": "https://www.paloaltonetworks.com/cortex",
Expand Down
6 changes: 6 additions & 0 deletions Packs/Core/ReleaseNotes/3_0_22.md
@@ -0,0 +1,6 @@

#### Integrations

##### Investigation & Response

Added support for flexible close-reason mapping in `handle_outgoing_issue_closure` in `CoreIRApiModule`. Does not affect this module.
2 changes: 1 addition & 1 deletion Packs/Core/pack_metadata.json
Expand Up @@ -2,7 +2,7 @@
"name": "Core - Investigation and Response",
"description": "Automates incident response",
"support": "xsoar",
"currentVersion": "3.0.21",
"currentVersion": "3.0.22",
"author": "Cortex XSOAR",
"url": "https://www.paloaltonetworks.com/cortex",
"email": "",
Expand Down