Skip to content

Commit

Permalink
new core-script-run command (demisto#36249)
Browse files Browse the repository at this point in the history
* core-script-run

* add tests and rn

* delete print

* rn

* pre-commit

* remove xdr

* ignore

* add to yml

* remove xdr

* rm

* rn

* rn

* Update Packs/Core/ReleaseNotes/3_0_63.md

Co-authored-by: ShirleyDenkberg <[email protected]>

* rn

* Bump pack from version Core to 3.0.64.

* Bump pack from version CortexXDR to 6.1.73.

* Bump pack from version CortexXDR to 6.1.74.

* Bump pack from version Core to 3.0.65.

* Bump pack from version CortexXDR to 6.1.75.

* Bump pack from version Core to 3.0.66.

* core-run-script

* fix rm

* fix rn

---------

Co-authored-by: ShirleyDenkberg <[email protected]>
Co-authored-by: Content Bot <[email protected]>
  • Loading branch information
3 people authored Sep 24, 2024
1 parent f502c0d commit 9a7db26
Show file tree
Hide file tree
Showing 13 changed files with 317 additions and 10 deletions.
5 changes: 4 additions & 1 deletion Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule.py
Original file line number Diff line number Diff line change
Expand Up @@ -3343,7 +3343,10 @@ def script_run_polling_command(args: dict, client: CoreClient) -> PollResult:

return PollResult(
response=get_script_execution_results_command(
client, {'action_id': action_id, 'integration_context_brand': 'PaloAltoNetworksXDR'}
client, {'action_id': action_id,
'integration_context_brand': 'Core'
if argToBoolean(args.get('is_core', False))
else 'PaloAltoNetworksXDR'}
),
continue_to_poll=general_status.upper() in ('PENDING', 'IN_PROGRESS')
)
Expand Down
3 changes: 2 additions & 1 deletion Packs/Core/.secrets-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,5 @@ [email protected]
[email protected]
[email protected]
f3322.net
Clarizen
Clarizen
https://test_api.com
4 changes: 4 additions & 0 deletions Packs/Core/Integrations/CortexCoreIR/CortexCoreIR.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,10 @@ def main(): # pragma: no cover
elif command == 'core-run-script':
return_results(run_script_command(client, args))

elif command == 'core-script-run':
args = args | {'is_core': True}
return_results(script_run_polling_command(args, client))

elif command == 'core-run-snippet-code-script':
return_results(run_polling_command(client=client,
args=args,
Expand Down
73 changes: 72 additions & 1 deletion Packs/Core/Integrations/CortexCoreIR/CortexCoreIR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1470,8 +1470,9 @@ script:
- defaultValue: '600'
description: The timeout in seconds for this execution.
name: timeout
description: Initiates a new endpoint script execution action using a script from the script library.
description: Deprecated. Use core-script-run instead.
name: core-run-script
deprecated: true
outputs:
- contextPath: Core.ScriptRun.action_id
description: ID of the action initiated.
Expand Down Expand Up @@ -2945,6 +2946,76 @@ script:
- contextPath: Core.UserGroup.source
description: Type of user group.
type: String
- arguments:
- description: Allows linking the response action to the incident that triggered it.
name: incident_id
- description: A comma-separated list of endpoint IDs. Can be retrieved by running the core-get-endpoints command.
name: endpoint_ids
required: true
- description: Unique identifier of the script. Can be retrieved by running the core-get-scripts command.
name: script_uid
required: true
- description: Dictionary containing the parameter name as key and its value for this execution as the value. For example, {"param1":"param1_value","param2":"param2_value"}.
name: parameters
- defaultValue: '600'
description: The timeout in seconds for this execution.
name: timeout
- description: Interval in seconds between each poll.
defaultValue: '10'
name: polling_interval_in_seconds
- description: Polling timeout in seconds.
name: polling_timeout_in_seconds
defaultValue: '600'
- description: The action ID for polling use.
name: action_id
hidden: true
- name: hide_polling_output
hidden: true
description: Whether to hide the polling result (automatically filled by polling).
- name: is_core
hidden: true
description: Is the command being called from a core pack.
defaultValue: true
description: Initiates a new endpoint script execution action using a script from the script library and returns the results.
name: core-script-run
polling: true
outputs:
- contextPath: Core.ScriptResult.action_id
description: ID of the action initiated.
type: Number
- contextPath: Core.ScriptResult.results.retrieved_files
description: Number of successfully retrieved files.
type: Number
- contextPath: Core.ScriptResult.results.endpoint_ip_address
description: Endpoint IP address.
type: String
- contextPath: Core.ScriptResult.results.endpoint_name
description: Name of successfully retrieved files.
type: String
- contextPath: Core.ScriptResult.results.failed_files
description: Number of files failed to be retrieved.
type: Number
- contextPath: Core.ScriptResult.results.endpoint_status
description: Endpoint status.
type: String
- contextPath: Core.ScriptResult.results.domain
description: Domain to which the endpoint belongs.
type: String
- contextPath: Core.ScriptResult.results.endpoint_id
description: Endpoint ID.
type: String
- contextPath: Core.ScriptResult.results.execution_status
description: Execution status of this endpoint.
type: String
- contextPath: Core.ScriptResult.results.return_value
description: Value returned by the script in case the type is not a dictionary.
type: String
- contextPath: Core.ScriptResult.results.standard_output
description: The STDOUT and the STDERR logged by the script during the execution.
type: String
- contextPath: Core.ScriptResult.results.retention_date
description: Timestamp in which the retrieved files will be deleted from the server.
type: Date
runonce: false
script: '-'
subtype: python3
Expand Down
118 changes: 118 additions & 0 deletions Packs/Core/Integrations/CortexCoreIR/CortexCoreIR_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import json

import pytest

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


Expand Down Expand Up @@ -133,3 +135,119 @@ def test_allowlist_files_command(self, mocker):

res = allowlist_files_command(mock_client, args)
assert res.readable_output == 'All hashes have already been added to the allow list.'


class TestPollingCommand:
@staticmethod
def create_mocked_responses(status_count):

response_queue = [
{
"reply": {
"action_id": 1,
"status": 1,
"endpoints_count": 1
}
}
]

for i in range(status_count):
if i == status_count - 1:
general_status = 'COMPLETED_SUCCESSFULLY'
elif i < 2:
general_status = 'PENDING'
else:
general_status = 'IN_PROGRESS'

response_queue.append(
{
"reply": { # get script status response
"general_status": general_status,
"endpoints_pending": 1 if i < 2 else 0,
"endpoints_in_progress": 0 if i < 2 else 1,
}
}
)
response_queue.append(
{
"reply": { # get script execution result response
"script_name": "snippet script",
"error_message": "",
"results": [
{
"endpoint_name": "test endpoint",
"endpoint_ip_address": [
"1.1.1.1"
],
"endpoint_status": "STATUS_010_CONNECTED",
"domain": "aaaa",
"endpoint_id": "1",
"execution_status": "COMPLETED_SUCCESSFULLY",
"failed_files": 0,
}
]
}
}
)

return response_queue

@pytest.mark.parametrize(argnames='status_count', argvalues=[1, 3, 7, 9, 12, 15])
def test_script_run_command(self, mocker, status_count):
"""
Given -
core-script-run command arguments including polling true and is_core is true where each time a different amount of
response is returned.
When -
Running the core-script-run
Then
- Make sure the readable output is returned to war-room only once indicating on polling.
- Make sure the correct context output is returned once the command finished polling
- Make sure context output is returned only at the end of polling.
- Make sure the readable output is returned only in the first run.
- Make sure the correct output prefix is returned.
"""
from CoreIRApiModule import script_run_polling_command, CoreClient
from CommonServerPython import ScheduledCommand

client = CoreClient(base_url='https://test_api.com/public_api/v1', headers={})

mocker.patch.object(client, '_http_request', side_effect=self.create_mocked_responses(status_count))
mocker.patch.object(ScheduledCommand, 'raise_error_if_not_supported', return_value=None)

command_result = script_run_polling_command(args={'endpoint_ids': '1', 'script_uid': '1'}, client=client)

assert command_result.readable_output == "Waiting for the script to " \
"finish running on the following endpoints: ['1']..."
assert command_result.outputs == {'action_id': 1, 'endpoints_count': 1, 'status': 1}

polling_args = {
'endpoint_ids': '1', 'script_uid': '1', 'action_id': '1', 'hide_polling_output': True, 'is_core': 'true'
}

command_result = script_run_polling_command(args=polling_args, client=client)
# if scheduled_command is set, it means that command should still poll
while not isinstance(command_result, list) and command_result.scheduled_command:
# if command result is a list, it means command execution finished
assert not command_result.readable_output # make sure that indication of polling is printed only once
# make sure no context output is being returned to war-room during polling
assert not command_result.outputs
command_result = script_run_polling_command(polling_args, client)

assert command_result[0].outputs == {
'action_id': 1,
'results': [
{
'endpoint_name': 'test endpoint',
'endpoint_ip_address': ['1.1.1.1'],
'endpoint_status': 'STATUS_010_CONNECTED',
'domain': 'aaaa',
'endpoint_id': '1',
'execution_status': 'COMPLETED_SUCCESSFULLY',
'failed_files': 0
}
]
}
assert command_result[0].outputs_prefix == 'Core.ScriptResult'
98 changes: 94 additions & 4 deletions Packs/Core/Integrations/CortexCoreIR/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1259,10 +1259,9 @@ Retrieves the status of the requested actions according to the action ID.
>**No entries.**

### core-run-script
### core-run-script (Deprecated)
***
Initiates a new endpoint script execution action using a script from the script library.

Deprecated. Use core-script-run instead.

#### Base Command

Expand Down Expand Up @@ -2723,4 +2722,95 @@ Builtin Roles with this permission includes: "Investigator", "Responder", "Privi
>|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
>| 5 | | | 1577276587937 | 5 'This alert from content TestXDRPlaybook' alerts detected by Checkpoint - SandBlast | | 4 | 1 | 4 | 0 | | medium | 1 | 1579290004178 | | This issue was solved in Incident number 192304 | medium | false | new | 1 | `https://some.xdr.url.com/incident-view/4` |
>| 1 | [email protected] | [email protected] | 1576100096594 | 'test 1' generated by Virus Total - Firewall | | 1 | 1 | 3 | 0 | | medium | 0 | 1579237974014 | | | medium | false | new | 1 | `https://some.xdr.url.com/incident-view/3` |
>| 2 | | | 1576062816474 | 'Alert Name Example 333' along with 1 other alert generated by Virus Total - VPN & Firewall-3 and Checkpoint - SandBlast | | 2 | 1 | 2 | 0 | | high | 0 | 1579288790259 | | | high | false | under_investigation | 1 | `https://some.xdr.url.com/incident-view/2`
>| 2 | | | 1576062816474 | 'Alert Name Example 333' along with 1 other alert generated by Virus Total - VPN & Firewall-3 and Checkpoint - SandBlast | | 2 | 1 | 2 | 0 | | high | 0 | 1579288790259 | | | high | false | under_investigation | 1 | `https://some.xdr.url.com/incident-view/2`
>
### core-script-run

***
Initiates a new endpoint script execution action using a script from the script library and returns the results.

#### Base Command

`core-script-run`

#### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Allows linking the response action to the incident that triggered it. | Optional |
| endpoint_ids | A comma-separated list of endpoint IDs. Can be retrieved by running the core-get-endpoints command. | Required |
| script_uid | Unique identifier of the script. Can be retrieved by running the core-get-scripts command. | Required |
| parameters | Dictionary containing the parameter name as key and its value for this execution as the value. For example, {"param1":"param1_value","param2":"param2_value"}. | Optional |
| timeout | The timeout in seconds for this execution. Default is 600. | Optional |
| polling_interval_in_seconds | Interval in seconds between each poll. Default is 10. | Optional |
| polling_timeout_in_seconds | Polling timeout in seconds. Default is 600. | Optional |
| action_id | The action ID for polling use. | Optional |
| hide_polling_output | Whether to hide the polling result (automatically filled by polling). | Optional |
| is_core | Is the command being called from a core pack. Default is True. | Optional |

#### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Core.ScriptResult.action_id | Number | ID of the action initiated. |
| Core.ScriptResult.results.retrieved_files | Number | Number of successfully retrieved files. |
| Core.ScriptResult.results.endpoint_ip_address | String | Endpoint IP address. |
| Core.ScriptResult.results.endpoint_name | String | Name of successfully retrieved files. |
| Core.ScriptResult.results.failed_files | Number | Number of files failed to be retrieved. |
| Core.ScriptResult.results.endpoint_status | String | Endpoint status. |
| Core.ScriptResult.results.domain | String | Domain to which the endpoint belongs. |
| Core.ScriptResult.results.endpoint_id | String | Endpoint ID. |
| Core.ScriptResult.results.execution_status | String | Execution status of this endpoint. |
| Core.ScriptResult.results.return_value | String | Value returned by the script in case the type is not a dictionary. |
| Core.ScriptResult.results.standard_output | String | The STDOUT and the STDERR logged by the script during the execution. |
| Core.ScriptResult.results.retention_date | Date | Timestamp in which the retrieved files will be deleted from the server. |

#### Command example

```!core-script-run endpoint_ids=111 script_uid=111 polling_timeout_in_seconds=1200 timeout=1200```

##### Context Example

```
{
"Core.ScriptResult": [
{
"action_id": 1,
"results": [
{
"retrieved_files" : 0,
"_return_value": [],
"standard_output": ""
"domain" : "222",
"endpoint_id" : "111",
"endpoint_ip_address" : ["1.1.1.1"],
"command" : "_return_value",
"retention_date" : NULL,
"command_output" : [],
"endpoint_name" : "test",
"failed_files" : 0,
"execution_status" : "COMPLETED_SUCCESSFULLY",
"endpoint_status" : "STATUS_010_CONNECTED"
},
]
}
],
"Core.ScriptRun": [
{
"action_id": 1,
"endpoints_count": 1,
"status": 1
}
]
}
```

##### Human Readable Output

>### Script Execution Results
>| _return_value| domain | endpoint_id| endpoint_ip_address| endpoint_name| endpoint_status| execution_status| failed_files| retention_date| retrieved_files| standard_output|
>|---|---|---|---|---|---|---|---|---|---|---|
>||222|111|1.1.1.1|test|STATUS_010_CONNECTED|COMPLETED_SUCCESSFULLY|0||0||
1 change: 1 addition & 0 deletions Packs/Core/Integrations/CortexCoreIR/command_examples
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@
!core-remove-blocklist-files hash_list=11d69fb388ff59e5ba6ca217ca04ecde6a38fa8fb306aa5f1b72e22bb7c3a252
!core-allowlist-files hash_list=11d69fb388ff59e5ba6ca217ca04ecde6a38fa8fb306aa5f1b72e22bb7c3a252
!core-remove-allowlist-files hash_list=11d69fb388ff59e5ba6ca217ca04ecde6a38fa8fb306aa5f1b72e22bb7c3a252
!core-script-run endpoint_ids=111 script_uid=111 polling_timeout_in_seconds=1200 timeout=1200
7 changes: 7 additions & 0 deletions Packs/Core/ReleaseNotes/3_0_67.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

#### Integrations

##### Investigation & Response

- Added a polling command ***core-script-run***.
- Deprecated the ***core-run-script*** command- Use ***core-script-run*** instead.
2 changes: 1 addition & 1 deletion Packs/Core/pack_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Core - Investigation and Response",
"description": "Automates incident response",
"support": "xsoar",
"currentVersion": "3.0.66",
"currentVersion": "3.0.67",
"author": "Cortex XSOAR",
"url": "https://www.paloaltonetworks.com/cortex",
"email": "",
Expand Down
6 changes: 6 additions & 0 deletions Packs/CortexXDR/ReleaseNotes/6_1_75.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

#### Integrations

##### Palo Alto Networks Cortex XDR - Investigation and Response

- Updated the CoreIRApiModule to handle ***core-script-run*** command.
2 changes: 1 addition & 1 deletion Packs/CortexXDR/pack_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Cortex XDR by Palo Alto Networks",
"description": "Automates Cortex XDR incident response, and includes custom Cortex XDR incident views and layouts to aid analyst investigations.",
"support": "xsoar",
"currentVersion": "6.1.74",
"currentVersion": "6.1.75",
"author": "Cortex XSOAR",
"url": "https://www.paloaltonetworks.com/cortex",
"email": "",
Expand Down
Loading

0 comments on commit 9a7db26

Please sign in to comment.