diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/README.md b/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/README.md index e69de29bb2d1..32b9c13fe54b 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/README.md +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/README.md @@ -0,0 +1,25 @@ +Script to add a comment to an alert in Sekoia, including the name of the person who made the comment. + +## Script Data + +--- + +| **Name** | **Description** | +| --- | --- | +| Script Type | python3 | +| Tags | incident-action-button | +| Cortex XSOAR Version | 6.10.0 | + +## Inputs + +--- + +| **Argument Name** | **Description** | +| --- | --- | +| short_id | The short ID of the alert. | +| comment | The comment you want to send to an alert. | + +## Outputs + +--- +There are no outputs for this script. diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/SekoiaXDRAddComment.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/SekoiaXDRAddComment.py index f9fa9ea9f511..db43bb5c73c4 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/SekoiaXDRAddComment.py +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/SekoiaXDRAddComment.py @@ -2,25 +2,34 @@ from CommonServerPython import * # noqa: F401 -def main(): +def get_username(): + get_users = execute_command("getUsers", {"current": "true"}) + username = get_users[0]["name"] # type: ignore + return username - alert_short_id = demisto.args().get("short_id") - comment = demisto.args().get("comment") - user = execute_command("getUsers", {"current": "true"})[0]["name"] # type: ignore - execute_command( - "sekoia-xdr-post-comment-alert", - {"id": alert_short_id, "comment": comment, "author": user}, - ) +def post_comment(alert_short_id: str, comment: Optional[str], author: str): + try: + execute_command( + "sekoia-xdr-post-comment-alert", + {"id": alert_short_id, "comment": comment, "author": author}, + ) + except Exception as e: + return_error( + f"Failed to post comment for alert with id {alert_short_id} : {str(e)}" + ) + +def main(): + alert_short_id = demisto.args()["short_id"] + comment = demisto.args().get("comment") + + user = get_username() + post_comment(alert_short_id, comment, user) readable_output = f"### Comment added by {user}:\n {comment}" - demisto.results( - { - "ContentsFormat": formats["markdown"], - "Type": entryTypes["note"], - "Contents": readable_output, - } - ) + + command_results = CommandResults(readable_output=readable_output) + return_results(command_results) if __name__ in ["__main__", "builtin", "builtins"]: diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/SekoiaXDRAddComment_test.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/SekoiaXDRAddComment_test.py new file mode 100644 index 000000000000..327a772687dd --- /dev/null +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRAddComment/SekoiaXDRAddComment_test.py @@ -0,0 +1,18 @@ +import demistomock as demisto +from SekoiaXDRAddComment import get_username, post_comment # type: ignore + + +def test_get_username(mocker): + output_data = [ + {"Type": 3, "Contents": [{"name": "admin", "PrettyRoles": "Administrator"}]} + ] + mocker.patch.object(demisto, "executeCommand", return_value=output_data) + assert get_username() == "admin" + + +def test_post_comment(mocker): + output_data = [ + {"Type": 3, "Contents": [{"id": "1", "comment": "test", "author": "admin"}]} + ] + mocker.patch.object(demisto, "executeCommand", return_value=output_data) + assert not post_comment("1", "test", "admin") diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/README.md b/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/README.md index e69de29bb2d1..4a96141d969f 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/README.md +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/README.md @@ -0,0 +1,26 @@ +This script changes the status of the Sekoia alert. + +## Script Data + +--- + +| **Name** | **Description** | +| --- | --- | +| Script Type | python3 | +| Tags | incident-action-button | +| Cortex XSOAR Version | 6.10.0 | + +## Inputs + +--- + +| **Argument Name** | **Description** | +| --- | --- | +| short_id | The short ID of the alert. | +| status | Status to change on the Sekoia alert. | +| comment | The comment to add to the alert on the status change. | + +## Outputs + +--- +There are no outputs for this script. diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/SekoiaXDRChangeStatus.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/SekoiaXDRChangeStatus.py index 7882a80b2087..7f5f3baff6b3 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/SekoiaXDRChangeStatus.py +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/SekoiaXDRChangeStatus.py @@ -2,35 +2,53 @@ from CommonServerPython import * # noqa: F401 +def get_username(): + get_users = execute_command("getUsers", {"current": "true"}) + username = get_users[0]["name"] # type: ignore + return username + + +def post_comment(alert_short_id: str, comment: Optional[str], author: str): + try: + execute_command( + "sekoia-xdr-post-comment-alert", + {"id": alert_short_id, "comment": comment, "author": author}, + ) + except Exception as e: + return_error( + f"Failed to post comment for alert with id {alert_short_id} : {str(e)}" + ) + + +def update_status(MirrorEnable: str, alert_short_id: str, new_status: str): + if MirrorEnable in ["Out", "Both"]: + execute_command("setIncident", {"sekoiaalertstatus": new_status}) + elif MirrorEnable == "In": + execute_command( + "sekoia-xdr-update-status-alert", + {"id": alert_short_id, "status": new_status}, + ) + else: + execute_command( + "sekoia-xdr-update-status-alert", + {"id": alert_short_id, "status": new_status}, + ) + execute_command("setIncident", {"sekoiaalertstatus": new_status}) + + def main(): incident = demisto.incidents()[0] # type: ignore isMirrorEnable = incident.get("dbotMirrorDirection") - alert_short_id = demisto.args().get("short_id") - new_status = demisto.args().get("status") + alert_short_id = demisto.args()["short_id"] + new_status = demisto.args()["status"] comment = demisto.args().get("comment") if new_status in ["Ongoing", "Acknowledged"]: if comment: - user = execute_command("getUsers", {"current": "true"})[0]["name"] # type: ignore - execute_command( - "sekoia-xdr-post-comment-alert", - {"id": alert_short_id, "comment": comment, "author": user}, - ) - if isMirrorEnable in ["Out", "Both"]: - execute_command("setIncident", {"sekoiaalertstatus": new_status}) - elif isMirrorEnable == "In": - execute_command( - "sekoia-xdr-update-status-alert", - {"id": alert_short_id, "status": new_status}, - ) - else: - execute_command( - "sekoia-xdr-update-status-alert", - {"id": alert_short_id, "status": new_status}, - ) - execute_command("setIncident", {"sekoiaalertstatus": new_status}) + post_comment(alert_short_id, comment, get_username()) + update_status(isMirrorEnable, alert_short_id, new_status) readable_output = f"### Status of the alert changed to:\n {new_status}" - demisto.results( + return_results( { "ContentsFormat": formats["markdown"], "Type": entryTypes["note"], @@ -39,9 +57,8 @@ def main(): ) else: raise Exception( - "Sorry, the alert was not possible to be changed to that status.\n \ - If you want to reject or close the Sekoia Alert please do it \ - by closing the XSOAR incident with the XSOAR close incident button." + f"Alert {alert_short_id} could not be changed to that status. \ + Please reject or close the Sekoia Alert by closing the XSOAR incident using the XSOAR close incident button." ) diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/SekoiaXDRChangeStatus_test.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/SekoiaXDRChangeStatus_test.py new file mode 100644 index 000000000000..432923a4b140 --- /dev/null +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRChangeStatus/SekoiaXDRChangeStatus_test.py @@ -0,0 +1,28 @@ +import demistomock as demisto +from SekoiaXDRChangeStatus import get_username, main # type: ignore + + +def test_get_username(mocker): + output_data = [ + {"Type": 3, "Contents": [{"name": "admin", "PrettyRoles": "Administrator"}]} + ] + mocker.patch.object(demisto, "executeCommand", return_value=output_data) + assert get_username() == "admin" + + +def test_main(mocker): + mocker.patch.object( + demisto, "incidents", return_value=[{"dbotMirrorDirection": "In"}] + ) + mocker.patch.object( + demisto, + "args", + return_value={"short_id": "1", "status": "Ongoing", "comment": "test"}, + ) + mocker.patch.object(demisto, "results") + mocker.patch("SekoiaXDRChangeStatus.get_username", return_value="admin") + main() + assert ( + demisto.results.call_args[0][0]["Contents"] + == "### Status of the alert changed to:\n Ongoing" + ) diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/README.md b/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/README.md index e69de29bb2d1..ba4b33ce616c 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/README.md +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/README.md @@ -0,0 +1,21 @@ +Post-processing script to close Sekoia Alert after the XSOAR incident is closed. + +## Script Data + +--- + +| **Name** | **Description** | +| --- | --- | +| Script Type | python3 | +| Tags | post-processing | +| Cortex XSOAR Version | 6.10.0 | + +## Inputs + +--- +There are no inputs for this script. + +## Outputs + +--- +There are no outputs for this script. diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/SekoiaXDRCloseAlert.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/SekoiaXDRCloseAlert.py index 653b7025b46a..bc068b7818c2 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/SekoiaXDRCloseAlert.py +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/SekoiaXDRCloseAlert.py @@ -1,44 +1,92 @@ import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 -incident = demisto.incidents()[0] # type: ignore -isMirrorEnable = incident.get("dbotMirrorDirection") -alert_short_id = incident.get("CustomFields", {}).get("alertid") -reject = demisto.getArg("sekoiaalertreject") -close_reason = demisto.getArg("closeReason") -close_notes = demisto.getArg("closeNotes") -owner = demisto.getArg("owner") -username = demisto.getArg("closingUserId") - -# Check if the owner is set when closing the incident otherwise raise an error. -if not owner or owner == "Assign owner" or not incident.get("owner"): - raise Exception( - "**** Please select a owner, the incident can't be closed without an owner. ****" - ) -# Check if the Sekoia Alert is closed and if not then make a comment and close it -get_alert = execute_command("sekoia-xdr-get-alert", {"id": alert_short_id}) -alert_status = get_alert["status"]["name"] # type: ignore -if alert_status not in ["Closed", "Rejected"]: - # Check if the mirror Out or Both is enabled in which case the sekoiaalertstatus - # field will be changed and in the period of 1 minute the mirror out will send the changes to Sekoia XDR. - if isMirrorEnable in ["Out", "Both"]: - # IF reject is False then close the sekoia alert and if reject is True then reject the sekoia alert. - if reject == "false": - execute_command("setIncident", {"sekoiaalertstatus": "Closed"}) - if reject == "true": - execute_command("setIncident", {"sekoiaalertstatus": "Rejected"}) - - # Send the close reason and notes as a comment to the Sekoia XDR alert using the name of the person who closed the incident. +def get_status_name(alert_id: str): + get_alert = execute_command("sekoia-xdr-get-alert", {"id": alert_id}) + return get_alert["status"]["name"] # type: ignore + + +def get_username(username: str): user = execute_command("getUserByUsername", {"username": username}) - comment = execute_command( - "sekoia-xdr-post-comment-alert", - { - "id": alert_short_id, - "comment": f"{close_reason}-{close_notes}", - "author": user["name"], # type: ignore - }, + return user["name"] # type: ignore + + +def post_closure_comment( + alert_id: str, + close_reason: Optional[str], + close_notes: Optional[str], + username: str, +): + try: + execute_command( + "sekoia-xdr-post-comment-alert", + { + "id": alert_id, + "comment": ( + f"{close_reason}-{close_notes}" + if close_reason and close_notes + else None + ), + "author": get_username(username), # type: ignore + }, + ) + except Exception as e: + return_error(f"Failed to post comment: {str(e)}") + + +def close_alert( + alert_id: str, + reject: str, + isMirrorEnable: str, + close_reason: Optional[str], + close_notes: Optional[str], + username: str, +): + alert_status = get_status_name(alert_id) + if alert_status not in ["Closed", "Rejected"]: + if isMirrorEnable in ["Out", "Both"]: + if reject == "false": + execute_command("setIncident", {"sekoiaalertstatus": "Closed"}) + readable_output = f"**** The alert {alert_id} has been closed. ****" + if reject == "true": + execute_command("setIncident", {"sekoiaalertstatus": "Rejected"}) + readable_output = f"**** The alert {alert_id} has been rejected. ****" + + post_closure_comment(alert_id, close_reason, close_notes, username) + + return_results( + { + "ContentsFormat": formats["markdown"], + "Type": entryTypes["note"], + "Contents": readable_output, + } + ) + + else: + raise Exception("**** The alert is already closed or rejected. ****") + + +def main(): + incident = demisto.incidents()[0] # type: ignore + isMirrorEnable = incident.get("dbotMirrorDirection") + alert_short_id = incident.get("CustomFields", {}).get("alertid") + reject = demisto.getArg["sekoiaalertreject"] # type: ignore + close_reason = demisto.getArg("closeReason") + close_notes = demisto.getArg("closeNotes") + owner = demisto.getArg("owner") + username = demisto.getArg["closingUserId"] # type: ignore + + # Check if the owner is set when closing the incident otherwise raise an error. + if not owner or owner == "Assign owner" or not incident.get("owner"): + raise Exception( + "**** Please select a owner, the incident can't be closed without an owner. ****" + ) + + close_alert( + alert_short_id, reject, isMirrorEnable, close_reason, close_notes, username ) -else: - # If the alert is already closed or rejected then raise an error. - raise Exception("**** The alert is already closed or rejected. ****") + + +if __name__ in ("__main__", "__builtin__", "builtins"): + main() diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/SekoiaXDRCloseAlert_test.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/SekoiaXDRCloseAlert_test.py new file mode 100644 index 000000000000..30a4696124c3 --- /dev/null +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRCloseAlert/SekoiaXDRCloseAlert_test.py @@ -0,0 +1,47 @@ +import demistomock as demisto +import SekoiaXDRCloseAlert # type: ignore +from SekoiaXDRCloseAlert import get_status_name, get_username, post_closure_comment, close_alert # type: ignore + + +def test_get_status_name(mocker): + output_data = [{"Type": 3, "Contents": {"status": {"name": "Ongoing"}}}] + mocker.patch.object(demisto, "executeCommand", return_value=output_data) + assert get_status_name("1") == "Ongoing" + + +def test_get_username(mocker): + output_data = [{"Type": 3, "Contents": {"name": "admin1"}}] + mocker.patch.object(demisto, "executeCommand", return_value=output_data) + assert get_username("admin") == "admin1" + + +def test_post_closure_comment(mocker): + output_data = [{"Type": 3, "Contents": {"name": "admin1"}}] + mocker.patch.object(demisto, "executeCommand", return_value=output_data) + mocker.patch.object(SekoiaXDRCloseAlert, "get_username", return_value="admin1") + assert post_closure_comment("1", "reason", "notes", "admin") is None + + +def test_close_alert(mocker): + mocker.patch.object(SekoiaXDRCloseAlert, "get_status_name", return_value="Ongoing") + output_data = [{"Type": 3, "Contents": {}}] + mocker.patch.object(demisto, "executeCommand", return_value=output_data) + mocker.patch.object(SekoiaXDRCloseAlert, "post_closure_comment", return_value=None) + mocker.patch.object(demisto, "results") + close_alert("1", "false", "Out", "reason", "notes", "admin") + assert ( + demisto.results.call_args[0][0]["Contents"] + == "**** The alert 1 has been closed. ****" + ) + + close_alert("1", "true", "Out", "reason", "notes", "admin") + assert ( + demisto.results.call_args[0][0]["Contents"] + == "**** The alert 1 has been rejected. ****" + ) + + mocker.patch.object(SekoiaXDRCloseAlert, "get_status_name", return_value="Closed") + try: + close_alert("1", "false", "Out", "reason", "notes", "admin") + except Exception as e: + assert str(e) == "**** The alert is already closed or rejected. ****" diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/README.md b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/README.md index e69de29bb2d1..29bb4d9acaa2 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/README.md +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/README.md @@ -0,0 +1,21 @@ +Print all assets by incident. + +## Script Data + +--- + +| **Name** | **Description** | +| --- | --- | +| Script Type | python3 | +| Tags | dynamic-section | +| Cortex XSOAR Version | 6.10.0 | + +## Inputs + +--- +There are no inputs for this script. + +## Outputs + +--- +There are no outputs for this script. diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/SekoiaXDRPrintAssets.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/SekoiaXDRPrintAssets.py index 57bf9f257ba0..c085d296b194 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/SekoiaXDRPrintAssets.py +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/SekoiaXDRPrintAssets.py @@ -2,36 +2,45 @@ from CommonServerPython import * # noqa: F401 -def main(): - incident = demisto.incident() - alert_uuid = incident.get("CustomFields", {}).get("alertuuid") - readable_output = ( - "### {{color:green}}(There is no case information related to this alert.)" - ) +def get_assets_info(assets_ids: list): + assets_infos = [] + for asset in assets_ids: + asset_infos = execute_command("sekoia-xdr-get-asset", {"asset_uuid": asset}) + asset_dict = { + "name": asset_infos["name"], # type: ignore + "description": asset_infos["description"], # type: ignore + } + assets_infos.append(asset_dict) + return assets_infos + +def get_assets_ids(alert_uuid: str): try: alert_infos = execute_command("sekoia-xdr-get-alert", {"id": alert_uuid}) except Exception as e: return_error(f"Failed to get alert information: {str(e)}") - assets_infos = [] assets_ids = alert_infos.get("assets") # type: ignore if assets_ids: - for asset in assets_ids: - asset_infos = execute_command("sekoia-xdr-get-asset", {"asset_uuid": asset}) - asset_dict = { - "name": asset_infos["name"], # type: ignore - "description": asset_infos["description"], # type: ignore - } - assets_infos.append(asset_dict) - + assets_infos = get_assets_info(assets_ids) headers = ["name", "description"] readable_output = tableToMarkdown( "Impacted assets:", assets_infos, headers=headers ) + else: + readable_output = ( + "### {{color:green}}(There is no case information related to this alert.)" + ) + + return readable_output - command_results = CommandResults(readable_output=readable_output) +def main(): + incident = demisto.incident() + alert_uuid = incident.get("CustomFields", {}).get("alertuuid") + + readable_output = get_assets_ids(alert_uuid) + command_results = CommandResults(readable_output=readable_output) return_results(command_results) diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/SekoiaXDRPrintAssets_test.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/SekoiaXDRPrintAssets_test.py new file mode 100644 index 000000000000..f8ddd8203ac1 --- /dev/null +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintAssets/SekoiaXDRPrintAssets_test.py @@ -0,0 +1,30 @@ +import demistomock as demisto +import SekoiaXDRPrintAssets + + +def test_assets_info(mocker): + assets_ids = ["1", "2"] + asset = { + "name": "asset", + "description": "description", + } + mocker.patch.object( + demisto, "executeCommand", return_value=[{"Type": 3, "Contents": asset}] + ) + assert len(SekoiaXDRPrintAssets.get_assets_info(assets_ids)) == 2 + + +def test_assets_ids(mocker): + alert_infos = {"assets": ["1", "2"]} + assets_infos = [ + {"description": "alVEdEMFNEMcBTNodDPL", "name": "name1"}, + {"description": "alVEdEMFNEazedadazedL", "name": "name2"}, + ] + mocker.patch.object( + demisto, "executeCommand", return_value=[{"Type": 3, "Contents": alert_infos}] + ) + mocker.patch.object( + SekoiaXDRPrintAssets, "get_assets_info", return_value=assets_infos + ) + assert "name1" in SekoiaXDRPrintAssets.get_assets_ids("1234") + assert "name2" in SekoiaXDRPrintAssets.get_assets_ids("1234") diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/README.md b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/README.md index e69de29bb2d1..2287313742eb 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/README.md +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/README.md @@ -0,0 +1,21 @@ +Prints case details from the Sekoia alert. + +## Script Data + +--- + +| **Name** | **Description** | +| --- | --- | +| Script Type | python3 | +| Tags | dynamic-section | +| Cortex XSOAR Version | 6.10.0 | + +## Inputs + +--- +There are no inputs for this script. + +## Outputs + +--- +There are no outputs for this script. diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/SekoiaXDRPrintCase.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/SekoiaXDRPrintCase.py index 8de716c82d64..2d751102abff 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/SekoiaXDRPrintCase.py +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/SekoiaXDRPrintCase.py @@ -2,30 +2,47 @@ from CommonServerPython import * # noqa: F401 -def main(): - incident = demisto.incident() - alert_uuid = incident.get("CustomFields", {}).get("alertuuid") - readable_output = ( - "### {{color:green}}(There is no case information related to this alert.)" - ) - +def create_case_object(cases): + return [ + { + "title": case_item["title"], + "description": case_item["description"], + "status": case_item["status"].capitalize(), + "priority": case_item["priority"].capitalize(), + "related alerts": ", ".join( + [alert["short_id"] for alert in case_item["alerts"]] + ), + } + for case_item in cases + ] + + +def get_case_info(alert_uuid: str): + readable_output = "" try: cases = execute_command("sekoia-xdr-get-cases-alert", {"alert_id": alert_uuid}) except Exception as e: return_error(f"Failed to get case information: {str(e)}") if cases: - for case in cases: - case_title = case["title"] # type: ignore - case_description = case["description"] # type: ignore - case_id = case["short_id"] # type: ignore - case_status = case["status"] # type: ignore - case_priority = case["priority"] # type: ignore - alerts = [alert["short_id"] for alert in case["alerts"]] # type: ignore - - readable_output = f"### Case {case_id}:\n|Case title:|Case description:|Case status:\ - |Case priority:|Related Alerts:|\n|---|---|---|---|---|\n| \ - {case_title} | {case_description} | {case_status.capitalize()} | {case_priority.capitalize()} | {', '.join(alerts)}" + readable_cases = create_case_object(cases) + headers = ["title", "description", "status", "priority", "related alerts"] + readable_output = tableToMarkdown( + "Cases information:", readable_cases, headers=headers + ) + else: + readable_output = ( + "### {{color:green}}(There is no case information related to this alert.)" + ) + + return readable_output + + +def main(): + incident = demisto.incident() + alert_uuid = incident.get("CustomFields", {}).get("alertuuid") + + readable_output = get_case_info(alert_uuid) command_results = CommandResults(readable_output=readable_output) return_results(command_results) diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/SekoiaXDRPrintCase_test.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/SekoiaXDRPrintCase_test.py new file mode 100644 index 000000000000..0d217e821ac5 --- /dev/null +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintCase/SekoiaXDRPrintCase_test.py @@ -0,0 +1,67 @@ +import demistomock as demisto +from SekoiaXDRPrintCase import get_case_info, create_case_object # type: ignore + + +def test_create_case_object(): + cases = [ + { + "title": "title1", + "description": "description1", + "short_id": "11", + "status": "status1", + "priority": "priority1", + "alerts": [{"short_id": "1"}, {"short_id": "2"}, {"short_id": "3"}], + }, + { + "title": "title2", + "description": "description2", + "short_id": "22", + "status": "status2", + "priority": "priority2", + "alerts": [{"short_id": "4"}, {"short_id": "5"}, {"short_id": "6"}], + }, + ] + expected = [ + { + "title": "title1", + "description": "description1", + "status": "Status1", + "priority": "Priority1", + "related alerts": "1, 2, 3", + }, + { + "title": "title2", + "description": "description2", + "status": "Status2", + "priority": "Priority2", + "related alerts": "4, 5, 6", + }, + ] + assert create_case_object(cases) == expected + + +def test_get_case_info(mocker): + cases_output = [ + { + "title": "title1", + "description": "description1", + "short_id": "11", + "status": "status1", + "priority": "priority1", + "alerts": [{"short_id": "1"}, {"short_id": "2"}, {"short_id": "3"}], + }, + { + "title": "title2", + "description": "description2", + "short_id": "22", + "status": "status2", + "priority": "priority2", + "alerts": [{"short_id": "4"}, {"short_id": "5"}, {"short_id": "6"}], + }, + ] + mocker.patch.object( + demisto, "executeCommand", return_value=[{"Type": 3, "Contents": cases_output}] + ) + assert "title1" in get_case_info("1") + assert "title2" in get_case_info("1") + assert "1, 2, 3" in get_case_info("1") diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/README.md b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/README.md index e69de29bb2d1..f2ebbec7a2b4 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/README.md +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/README.md @@ -0,0 +1,21 @@ +Prints the comments fetched from the Sekoia alert in a table format. + +## Script Data + +--- + +| **Name** | **Description** | +| --- | --- | +| Script Type | python3 | +| Tags | dynamic-section | +| Cortex XSOAR Version | 6.10.0 | + +## Inputs + +--- +There are no inputs for this script. + +## Outputs + +--- +There are no outputs for this script. diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/SekoiaXDRPrintComments.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/SekoiaXDRPrintComments.py index fefe87396569..f0e79138750e 100644 --- a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/SekoiaXDRPrintComments.py +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/SekoiaXDRPrintComments.py @@ -2,34 +2,44 @@ from CommonServerPython import * # noqa: F401 -def main(): - - incident = demisto.incident() - alert_short_id = incident.get("CustomFields", {}).get("alertid") - readable_output = ( - "### Comments:\n ### {{color:green}}(There is no comments in this alert.)" - ) - +def create_comment_object(comments): + return [ + { + "date": comment_item["date"], + "comment": comment_item["content"], + "user": comment_item["user"], + } + for comment_item in comments + ] + + +def get_comments(alert_id: str): + readable_output = "" try: - comments = execute_command("sekoia-xdr-get-comments", {"id": alert_short_id}) + comments = execute_command("sekoia-xdr-get-comments", {"id": alert_id}) except Exception as e: return_error(f"Failed to get comments: {str(e)}") if len(comments) > 0: # type: ignore - readable_comment = [] - for comment in comments: # type: ignore - new_item = { - "date": comment["date"], # type: ignore - "comment": comment["content"], # type: ignore - "user": comment["user"], # type: ignore - } - readable_comment.append(new_item) - + readable_comments = create_comment_object(comments) headers = ["date", "comment", "user"] readable_output = tableToMarkdown( - "Comments:", readable_comment, headers=headers + "Comments:", readable_comments, headers=headers + ) + else: + readable_output = ( + "### Comments:\n ### {{color:green}}(There is no comments in this alert.)" ) + return readable_output + + +def main(): + incident = demisto.incident() + alert_short_id = incident.get("CustomFields", {}).get("alertid") + + readable_output = get_comments(alert_short_id) + command_results = CommandResults(readable_output=readable_output) return_results(command_results) diff --git a/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/SekoiaXDRPrintComments_test.py b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/SekoiaXDRPrintComments_test.py new file mode 100644 index 000000000000..3de9a8f67d01 --- /dev/null +++ b/Packs/SekoiaXDR/Scripts/SekoiaXDRPrintComments/SekoiaXDRPrintComments_test.py @@ -0,0 +1,80 @@ +import demistomock as demisto +from SekoiaXDRPrintComments import create_comment_object, get_comments, main # type: ignore + + +def test_create_comment_object(mocker): + comments = [ + { + "date": "2021-07-27T15:00:00Z", + "content": "comment", + "user": "user", + "field_1": "value_1", + "field_2": "value_2", + "field_3": "value_3", + "field_4": "value_4", + }, + { + "date": "2021-07-27T15:00:00Z", + "content": "comment1", + "user": "user1", + "field_1": "value_1", + "field_2": "value_2", + "field_3": "value_3", + "field_4": "value_4", + }, + ] + expected = [ + { + "date": "2021-07-27T15:00:00Z", + "comment": "comment", + "user": "user", + }, + { + "date": "2021-07-27T15:00:00Z", + "comment": "comment1", + "user": "user1", + }, + ] + assert create_comment_object(comments) == expected + + +def test_get_comments(mocker): + comments_output = [ + { + "date": "2021-07-27T15:00:00Z", + "content": "comment", + "user": "user", + "field_1": "value_1", + "field_2": "value_2", + "field_3": "value_3", + "field_4": "value_4", + }, + { + "date": "2021-07-27T15:00:00Z", + "content": "comment1", + "user": "user1", + "field_1": "value_1", + "field_2": "value_2", + "field_3": "value_3", + "field_4": "value_4", + }, + ] + mocker.patch.object( + demisto, + "executeCommand", + return_value=[{"Type": 3, "Contents": comments_output}], + ) + assert "user" in get_comments("alert_id") + assert "user1" in get_comments("alert_id") + assert "comment" in get_comments("alert_id") + assert "comment1" in get_comments("alert_id") + + +def test_get_comments_no_comments(mocker): + comments_output = [] + mocker.patch.object( + demisto, + "executeCommand", + return_value=[{"Type": 3, "Contents": comments_output}], + ) + assert "There is no comments in this alert" in get_comments("alert_id")