Cortex XDR - IR
Cortex XDR is the world's first detection and response app that natively integrates network, endpoint, and cloud data to stop sophisticated attacks.
Endpoint · Cortex XDR by Palo Alto Networks
Details
| ID | Cortex XDR - IR |
|---|---|
| Provider | Palo Alto Networks |
| Category | Endpoint |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix |
README
Cortex XDR is the world’s first detection and response app that natively integrates network, endpoint, and cloud data to stop sophisticated attacks.
This integration was integrated and tested with version 2.6.5 of Cortex XDR - IR.
Configure Palo Alto Networks Cortex XDR - Investigation and Response on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for Palo Alto Networks Cortex XDR - Investigation and Response.
- Click Add instance to create and configure a new integration instance.
| Parameter | Description | Required |
|---|---|---|
| Fetch incidents | False | |
| Incident type | False | |
| Server URL (copy URL from XDR) | True | |
| API Key ID | False | |
| API Key | False | |
| Remove legacy incident fields | Not selected for backwards compatibility. Recommended to select. This will remove duplicated incident fields under file_artifacts, network_artifacts, and alerts (like client_id, clientid.) | False |
| Incident Mirroring Direction | Not supported on Cortex platform. | False |
| Close Mirrored XSOAR Incident | When selected, closing the Cortex XDR incident is mirrored in Cortex XSOAR. | False |
| Close Mirrored Cortex XDR Incident | When selected, closing the Cortex XSOAR incident is mirrored in Cortex XDR. Notice: If not selected, but ‘Close all related alerts in XDR’ is selected, the incident will automatically be closed in Cortex XDR. | False |
| XDR mirroring delay in minutes | In the event of a delay in mirroring incoming changes from XDR, use the xdr_delay parameter to extend the look-back period. However, be aware that this may result in increased latency when updating incidents. | False |
| Custom close-reason mapping (XSOAR -> XDR mirrored incident. Overwrites default close-reason mapping defined by Cortex XSOAR) | Define how to close the mirrored incidents from Cortex XSOAR into Cortex XDR with a custom close reason mapping. Enter a comma-separated list of close reasons (acceptable format {Cortex XSOAR close reason}={Cortex XDR close reason}) to override the default close reason mapping defined by Cortex XSOAR. Note that the mapping must be configured accordingly with the existing close reasons in Cortex XSOAR and Cortex XDR. Not following this format will result in closing the incident with a default close reason. Example: “Resolved=Other,Duplicate=Other”. Refer to ../README.md for possible close-reasons - `XDR Incident Mirroring`. | False |
| Custom close-reason mapping (XDR -> XSOAR mirrored incident. Overwrites default close-reason mapping defined by Cortex XSOAR) | Define how to close the mirrored incidents from Cortex XDR into Cortex XSOAR with a custom close reason mapping. Enter a comma-separated list of close reasons (acceptable format {Cortex XDR close reason}={Cortex XSOAR close reason}) to override the default close reason mapping defined by Cortex XSOAR. Note that the mapping must be configured accordingly with the existing close reasons in Cortex XSOAR and Cortex XDR. Not following this format will result in closing the incident with a default close reason. Example: “Known Issue=Resolved, Duplicate Incident=Other”. Refer to ../README.md for possible close-reasons - `XDR Incident Mirroring`. | False |
| HTTP Timeout | The timeout of the HTTP requests sent to Cortex XDR API (in seconds). | False |
| Maximum number of incidents per fetch | The maximum number of incidents per fetch. Cannot exceed 100. | False |
| Only fetch starred incidents | False | |
| Starred incidents fetch window | Starred fetch window timestamp (<number> <time unit>, e.g., 12 hours, 7 days). Fetches only starred incidents within the specified time range. | False |
| First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days) | False | |
| Sync Incident Owners | For Cortex XSOAR version 6.0.0 and above. If selected, for every incident fetched from Cortex XDR to Cortex XSOAR, the incident owners will be synced. Note that once this value is changed and synchronized between the systems, additional changes will not be reflected. For example, if you change the owner in Cortex XSOAR, the new owner will also be changed in Cortex XDR. However, if you now change the owner back in Cortex XDR, this additional change will not be reflected in Cortex XSOAR. In addition, for this change to be reflected, the owners must exist in both Cortex XSOAR and Cortex XDR. | False |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Prevent Only Mode | Whether the XDR tenant mode is prevent only | False |
| Incident Statuses to Fetch | The statuses of the incidents that will be fetched. If no status is provided then incidents of all the statuses will be fetched. Note: An incident whose status was changed to a filtered status after its creation time will not be fetched. | False |
| Minimize Incident Information | Whether to fetch only the essential incident’s fields - without Network Artifacts and File Artifacts to minimize the incident’s information. | False |
| Minimize Alert Information | Whether to fetch only the essential alert fields in order to minimize the incident’s information. Possible values: null_values to remove all null values from alerts data, or any other field of an alert. | False |
| Close all related alerts in XDR | Close all related alerts in Cortex XDR once an incident has been closed in Cortex XSOAR. | False |
- Click Test to validate the URLs, token, and connection.
Configuration
To configure the integration on Cortex XSOAR, you need to generate an API Key and obtain your Cortex XDR URL.
Generate an API Key and API Key ID
- In Cortex XDR, navigate to Settings > Configurations > API Keys.
- Click +New Key and generate an Advanced key.
- Copy the generated API Key and the Key ID from the table.
Note 1: You can assign a custom or built-in role to the API Key. Instance Admin provides the highest privileges, while Privileged Responder offers maximum command execution with fewer overall permissions. In order for the integration test to pass, the API Key must have View permissions for Cases and Issues.
Note 2: If you experience missing updates when mirroring incoming changes from XDR, increase the XDR mirroring delay in minutes parameter. Note that this may increase latency when updating incidents.
URL
- In Cortex XDR, navigate to Settings > Configurations > API Keys.
- Click Copy URL in the top right corner.
XDR & XSOAR
Playbooks
Cortex XDR Incident Handling
The playbook syncs and updates new Cortex XDR alerts that construct the incident.
It enriches indicators using Threat Intelligence integrations and Palo Alto Networks
AutoFocus. The incident’s severity is then updated based on the indicators reputation
and an analyst is assigned for manual investigation. If chosen, automated remediation
with Palo Alto Networks FireWall is initiated. After a manual review by the
SOC analyst, the Cortex XDR incident is closed automatically.
To utilize this playbook for handling Cortex XDR incidents, the classifier that should be selected is Cortex XDR - Classifier.
The selected Mapper (incoming) should be XDR - Incoming Mapper, and the selected Mapper (outgoing) should be Cortex XDR - Outgoing Mapper.
Cortex XDR Lite - Incident Handling
This playbook is a lite default playbook to handle Cortex XDR incidents, and it doesn’t require additional integrations to run. The playbook is triggered by fetching a Palo Alto Networks Cortex XDR incident. First, the playbook performs enrichment on the incident’s indicators. Then, the playbook performs investigation and analysis on the command line and searches for related Cortex XDR alerts by Mitre tactics to identify malicious activity performed on the endpoint and by the user. Based on the enrichment and the investigation results, the playbooks sets the verdict of the incident. If malicious indicators are found, the playbook takes action to block these indicators and isolate the affected endpoint to prevent further damage or the spread of threats. If the verdict is not determined, it lets the analyst decide whether to continue to the remediation stage or close the investigation as benign. As part of this playbook, you’ll receive a comprehensive layout that presents incident details, analysis, investigation findings, and the final verdict. Additionally, the layout offers convenient remediation buttons for quicker manual actions.
To utilize this playbook for handling XDR incidents, the classifier should be empty, and the selected incident type should be Cortex XDR - Lite.
The selected Mapper (incoming) should be XDR - Incoming Mapper, and the selected Mapper (outgoing) should be Cortex XDR - Outgoing Mapper.
Use Cases
- Fetch incidents from Cortex XDR
- Enrich incident with alerts and incident from Cortex XDR
- Update incident in Cortex XDR
- Search for endpoints
- Isolate/unisolate endpoints
- Insert parsed alerts into Cortex XDR
- Insert CEF alerts into Cortex XDR
- Query for agent audit reports
- Query for audit management logs
- Create distribution
- Get distribution download URL
- Get distribution versions
Automation
To sync incidents between Cortex XSOAR and Cortex XDR, you should use the XDRSyncScript script, which you can find in the automation page.
Fetched Incidents Data
incident_id:31
creation_time:1564594008755
modification_time:1566339537617
detection_time:null
status:new
severity:low
description:6 'Microsoft Windows RPC Fragment Evasion Attempt' alerts detected by PAN NGFW on 6 hosts
assigned_user_mail:null
assigned_user_pretty_name:null
alert_count:6
low_severity_alert_count:0
med_severity_alert_count:6
high_severity_alert_count:0
user_count:1
host_count:6
notes:null
resolve_comment:null
manual_severity:low
manual_description:null
xdr_url:https://1111.paloaltonetworks.com/incident-view/31
XDR Incident Mirroring
Note this feature is available from Cortex XSOAR version 6.0.0
You can enable incident mirroring between Cortex XSOAR incidents and Cortex XDR incidents.
To setup the mirroring follow these instructions:
- Navigate to Settings > Integrations > Servers & Services.
- Search for Cortex XDR - IR and select your integration instance.
- Enable Fetches incidents.
- Under Mapper (incoming), select
XDR - Incoming Mapper. - Under Mapper (outgoing), select
Cortex XDR - Outgoing Mapper. - In the Incident Mirroring Direction integration parameter, select in which direction the incidents should be mirrored:
- Incoming - Any changes in Cortex XDR incidents will be reflected in Cortex XSOAR incidents.
- Outgoing - Any changes in Cortex XSOAR incidents will be reflected in Cortex XDR incidents.
- Both - Changes in Cortex XSOAR and Cortex XDR incidents will be reflected in both directions.
- None - Choose this to turn off incident mirroring.
-
Optional: Provide a custom close-reason mapping for mirrored XDR <-> XSOAR incidents. Please use only possible close-reasons to map:
Possible Closure Reasons for Cortex XSOAR Incident Resolved False Positive Duplicate Security Testing Other Possible Closure Reasons for Cortex Cortex XDR Incident True Positive False Positive Duplicate Incident Security Testing Known Issue Other Auto Failing to use only available values will result in using default mapping of closure reasons within the mirroring process.
Close-reason default mapping XSOAR -> XDR: Other=Other, Duplicate=Duplicate Incident, False Positive=False Positive, Resolved=True Positive
Close-reason default mapping XDR -> XSOAR: Known Issue=Other, Duplicate Incident=Duplicate, False Positive=False Positive, True Positive=Resolved, Other=Other, Auto=Resolved
-
Optional: Check the Sync Incident Owners integration parameter to sync the incident owners in both Cortex XDR and Cortex XSOAR.
- Note: This feature will only work if the same users are registered in both Cortex XSOAR and Cortex XDR.
-
Newly fetched incidents will be mirrored in the chosen direction.
- Note: This will not effect existing incidents.
XDR Mirroring Notes, limitations and Troubleshooting
- While you can mirror changes in incident fields both in and out in each incident, you can only mirror in a single direction at a time. For example:
If we have an incident with two fields (A and B) in Cortex XDR and Cortex XSOAR while Incoming And Outgoing mirroring is selected:- I can mirror field A from Cortex XDR to Cortex XSOAR and field B from Cortex XSOAR to Cortex XDR.
- I cannot mirror changes from field A in both directions.
Initially all fields are mirrored in from Cortex XDR to Cortex XSOAR. Once they are changed in Cortex XSOAR, they can only be mirrored out.
-
Do not use the
XDRSyncScriptautomation nor any playbook that uses this automation
(e.gCortex XDR Incident SyncorCortex XDR incident handling v2), as it impairs the mirroring functionality. - When migrating an existing instance to the mirroring feature, or in case the mirroring does not work as expected, make sure that:
- The default playbook of the Cortex XDR Incident incident type is not Cortex XDR Incident Sync, change it to a
different playbook that does not useXDRSyncScript. - The Cortex XDR integration instance incoming mapper is set to
Cortex XDR - Incoming Mapperand the outgoing mapper is set toCortex XDR - Outgoing Mapper. - Mirroring impacts only incidents that were fetched after the mirroring was enabled for this instance. If incidents were fetched with the incorrect mapper, changing the mapper will not affect them. This can be resolved by resetting the last fetch run and re-fetching the incidents. New incidents will be created and the old ones will no longer be relevant.
- The default playbook of the Cortex XDR Incident incident type is not Cortex XDR Incident Sync, change it to a
-
The API includes a limit rate of 10 API requests per minute. Therefore, in a case of a limit rate exception, the sync loop will stop and will resume from the last incident.
OwnerandcloseReasonmappings are done using the integration code, therefore they are not part of the out-of-the-box mapper and should not be specified in any future mapper.
Fetch Behavior vs Mirroring
Note: All incidents, including those with a “resolved” status, will be fetched into Cortex XSOAR as “active” incidents to enable the execution of our automations. However, the original resolved status of the incidents will be preserved in the incident details. If you prefer to keep certain incidents closed, you can utilize the “Incident Statuses to Fetch” filter during the configuration stage and choose not to import those specific incidents. Alternatively, you can utilize pre-processing rules to define specific types of incidents to be imported as closed.
Regarding mirroring, if you have already imported an incident and the mirroring feature is enabled, changing the incident’s status to resolved on the Cortex XDR platform will trigger the mirroring process, resulting in the closure of the incident in Cortex XSOAR.
Commands
You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
xdr-get-incidents (Deprecated)
This command is deprecated please use xdr-case-list instead. Returns a list of incidents, which you can filter by a list of incident IDs (max. 100), the time the incident was last modified, and the time the incident was created.
If you pass multiple filtering arguments, they will be concatenated using the AND condition. The OR condition is not supported.
Required Permissions
Required Permissions For API call:
Alerts And Incidents –> View
Builtin Roles with this permission includes: “Investigator”, “Responder”, “Privileged Investigator”, “Privileged Responder”, “Viewer”, and “Instance Admin”.
Base Command
xdr-get-incidents
Input
| Argument Name | Description | Required |
|---|---|---|
| lte_creation_time | A date in the format 2019-12-31T23:59:00 in UTC. Only incidents that were created on or before the specified date/time will be retrieved. | Optional |
| gte_creation_time | A date in the format 2019-12-31T23:59:00 in UTC. Only incidents that were created on or after the specified date/time will be retrieved. | Optional |
| lte_modification_time | Filters returned incidents that were created on or before the specified date/time, in the format 2019-12-31T23:59:00. | Optional |
| gte_modification_time | Filters returned incidents that were modified on or after the specified date/time, in the format 2019-12-31T23:59:00. | Optional |
| incident_id_list | An array or CSV string of incident IDs. | Optional |
| since_creation_time | Filters returned incidents that were created on or after the specified date/time range, for example, 1 month, 2 days, 1 hour, and so on. | Optional |
| since_modification_time | Filters returned incidents that were modified on or after the specified date/time range, for example, 1 month, 2 days, 1 hour, and so on. | Optional |
| sort_by_modification_time | Sorts returned incidents by the date/time that the incident was last modified (“asc” - ascending, “desc” - descending). Possible values are: asc, desc. | Optional |
| sort_by_creation_time | Sorts returned incidents by the date/time that the incident was created (“asc” - ascending, “desc” - descending). Possible values are: asc, desc. | Optional |
| page | Page number (for pagination). The default is 0 (the first page). Default is 0. | Optional |
| limit | Maximum number of incidents to return per page. The default and maximum is 100. Default is 100. | Optional |
| status | Filters only incidents in the specified status. The options are: new, under_investigation, resolved_known_issue, resolved_false_positive, resolved_true_positive resolved_security_testing, resolved_other, resolved_auto, resolved_auto_resolve. | Optional |
| starred | Whether the incident is starred (Boolean value: true or false). Possible values are: true, false. | Optional |
| starred_incidents_fetch_window | Starred fetch window timestamp (<number> <time unit>, e.g., 12 hours, 7 days). Default is 3 days. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Incident.incident_id | String | Unique ID assigned to each returned incident. |
| PaloAltoNetworksXDR.Incident.manual_severity | String | Incident severity assigned by the user. This does not affect the calculated severity. Can be “low”, “medium”, “high” |
| PaloAltoNetworksXDR.Incident.manual_description | String | Incident description provided by the user. |
| PaloAltoNetworksXDR.Incident.assigned_user_mail | String | Email address of the assigned user. |
| PaloAltoNetworksXDR.Incident.high_severity_alert_count | String | Number of alerts with the severity HIGH. |
| PaloAltoNetworksXDR.Incident.host_count | number | Number of hosts involved in the incident. |
| PaloAltoNetworksXDR.Incident.xdr_url | String | A link to the incident view on Cortex XDR. |
| PaloAltoNetworksXDR.Incident.assigned_user_pretty_name | String | Full name of the user assigned to the incident. |
| PaloAltoNetworksXDR.Incident.alert_count | number | Total number of alerts in the incident. |
| PaloAltoNetworksXDR.Incident.med_severity_alert_count | number | Number of alerts with the severity MEDIUM. |
| PaloAltoNetworksXDR.Incident.user_count | number | Number of users involved in the incident. |
| PaloAltoNetworksXDR.Incident.severity | String | Calculated severity of the incident. Valid values are: “low”,”medium”,”high” |
| PaloAltoNetworksXDR.Incident.low_severity_alert_count | String | Number of alerts with the severity LOW. |
| PaloAltoNetworksXDR.Incident.status | String | Current status of the incident. Valid values are: “new”,”under_investigation”,”resolved_known_issue”,”resolved_duplicate”,”resolved_false_positive”,”resolved_true_positive”,”resolved_security_testing” or “resolved_other”. |
| PaloAltoNetworksXDR.Incident.description | String | Dynamic calculated description of the incident. |
| PaloAltoNetworksXDR.Incident.resolve_comment | String | Comments entered by the user when the incident was resolved. |
| PaloAltoNetworksXDR.Incident.notes | String | Comments entered by the user regarding the incident. |
| PaloAltoNetworksXDR.Incident.creation_time | date | Date and time the incident was created on Cortex XDR. |
| PaloAltoNetworksXDR.Incident.detection_time | date | Date and time that the first alert occurred in the incident. |
| PaloAltoNetworksXDR.Incident.modification_time | date | Date and time that the incident was last modified. |
Command Example
!xdr-get-incidents gte_creation_time=2010-10-10T00:00:00 limit=3 sort_by_creation_time=desc
Context Example
{
"PaloAltoNetworksXDR.Incident": [
{
"host_count": 1,
"incident_id": "4",
"manual_severity": "medium",
"description": "5 'This alert from content TestXDRPlaybook' alerts detected by Checkpoint - SandBlast ",
"severity": "medium",
"modification_time": 1579290004178,
"assigned_user_pretty_name": null,
"notes": null,
"creation_time": 1577276587937,
"alert_count": 5,
"med_severity_alert_count": 1,
"detection_time": null,
"assigned_user_mail": null,
"resolve_comment": "This issue was solved in Incident number 192304",
"status": "new",
"user_count": 1,
"xdr_url": "https://some.xdr.url.com/incident-view/4",
"starred": false,
"low_severity_alert_count": 0,
"high_severity_alert_count": 4,
"manual_description": null
},
{
"host_count": 1,
"incident_id": "3",
"manual_severity": "medium",
"description": "'test 1' generated by Virus Total - Firewall",
"severity": "medium",
"modification_time": 1579237974014,
"assigned_user_pretty_name": "woo@test.com",
"notes": null,
"creation_time": 1576100096594,
"alert_count": 1,
"med_severity_alert_count": 0,
"detection_time": null,
"assigned_user_mail": "woo@test.com",
"resolve_comment": null,
"status": "new",
"user_count": 1,
"xdr_url": "https://some.xdr.url.com/incident-view/3",
"starred": false,
"low_severity_alert_count": 0,
"high_severity_alert_count": 1,
"manual_description": null
},
{
"host_count": 1,
"incident_id": "2",
"manual_severity": "high",
"description": "'Alert Name Example 333' along with 1 other alert generated by Virus Total - VPN & Firewall-3 and Checkpoint - SandBlast",
"severity": "high",
"modification_time": 1579288790259,
"assigned_user_pretty_name": null,
"notes": null,
"creation_time": 1576062816474,
"alert_count": 2,
"med_severity_alert_count": 0,
"detection_time": null,
"assigned_user_mail": null,
"resolve_comment": null,
"status": "under_investigation",
"user_count": 1,
"xdr_url": "https://some.xdr.url.com/incident-view/2",
"starred": false,
"low_severity_alert_count": 0,
"high_severity_alert_count": 2,
"manual_description": null
}
]
}
Human Readable Output
Incidents
alert_count assigned_user_mail assigned_user_pretty_name creation_time description detection_time high_severity_alert_count host_count incident_id low_severity_alert_count manual_description manual_severity med_severity_alert_count modification_time notes resolve_comment severity starred status user_count xdr_url 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/41 woo@test.com woo@test.com 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/32 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
xdr-get-incident-extra-data (Deprecated)
This command is deprecated. Returns additional data for the specified incident, for example, related alerts, file artifacts, network artifacts, and so on.
Required Permissions
Required Permissions For API call:
Alerts And Incidents –> View
Builtin Roles with this permission includes: “Investigator”, “Responder”, “Privileged Investigator”, “Privileged Responder”, “Viewer”, and “Instance Admin”.
Base Command
xdr-get-incident-extra-data
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | The ID of the incident for which to get additional data. | Required |
| alerts_limit | Maximum number of alerts to return. Default is 1000. | Optional |
| return_only_updated_incident | Return data only if the incident was changed since the last time it was mirrored into Cortex XSOAR. This flag should be used only from within a Cortex XDR incident. Default is False. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Incident.incident_id | String | Unique ID assigned to each returned incident. |
| PaloAltoNetworksXDR.Incident.creation_time | Date | Date and time the incident was created on Cortex XDR. |
| PaloAltoNetworksXDR.Incident.modification_time | Date | Date and time that the incident was last modified. |
| PaloAltoNetworksXDR.Incident.detection_time | Date | Date and time that the first alert occurred in the incident. |
| PaloAltoNetworksXDR.Incident.status | String | Current status of the incident. Valid values are: |
| “new”,”under_investigation”,”resolved_known_issue”,”resolved_duplicate”,”resolved_false_positive”,”resolved_true_positive”,”resolved_security_testing”,”resolved_other” | ||
| PaloAltoNetworksXDR.Incident.severity | String | Calculated severity of the incident. Valid values are: “low”,”medium”,”high” |
| PaloAltoNetworksXDR.Incident.description | String | Dynamic calculated description of the incident. |
| PaloAltoNetworksXDR.Incident.assigned_user_mail | String | Email address of the assigned user. |
| PaloAltoNetworksXDR.Incident.assigned_user_pretty_name | String | Full name of the user assigned to the incident. |
| PaloAltoNetworksXDR.Incident.alert_count | Number | Total number of alerts in the incident. |
| PaloAltoNetworksXDR.Incident.low_severity_alert_count | Number | Number of alerts with the severity LOW. |
| PaloAltoNetworksXDR.Incident.med_severity_alert_count | Number | Number of alerts with the severity MEDIUM. |
| PaloAltoNetworksXDR.Incident.high_severity_alert_count | Number | Number of alerts with the severity HIGH. |
| PaloAltoNetworksXDR.Incident.user_count | Number | Number of users involved in the incident. |
| PaloAltoNetworksXDR.Incident.host_count | Number | Number of hosts involved in the incident |
| PaloAltoNetworksXDR.Incident.notes | Unknown | Comments entered by the user regarding the incident. |
| PaloAltoNetworksXDR.Incident.resolve_comment | String | Comments entered by the user when the incident was resolved. |
| PaloAltoNetworksXDR.Incident.manual_severity | String | Incident severity assigned by the user. This does not affect the calculated severity of low, medium, or high. |
| PaloAltoNetworksXDR.Incident.manual_description | String | Incident description provided by the user. |
| PaloAltoNetworksXDR.Incident.xdr_url | String | A link to the incident view on Cortex XDR. |
| PaloAltoNetworksXDR.Incident.starred | Boolean | Incident starred. |
| PaloAltoNetworksXDR.Incident.wildfire_hits.mitre_techniques_ids_and_names | String | Incident Mitre techniques IDs and names. |
| PaloAltoNetworksXDR.Incident.wildfire_hits.mitre_tactics_ids_and_names | String | Incident Mitre tactics ids and names. |
| PaloAltoNetworksXDR.Incident.alerts.alert_id | String | Unique ID for each alert. |
| PaloAltoNetworksXDR.Incident.alerts.detection_timestamp | Date | Date and time that the alert occurred. |
| PaloAltoNetworksXDR.Incident.alerts.source | String | Source of the alert. The product/vendor this alert came from. |
| PaloAltoNetworksXDR.Incident.alerts.severity | String | Severity of the alert.Valid values are: “low”,”medium”,”high””” |
| PaloAltoNetworksXDR.Incident.alerts.name | String | Calculated name of the alert. |
| PaloAltoNetworksXDR.Incident.alerts.category | String | Category of the alert, for example, Spyware Detected via Anti-Spyware profile. |
| PaloAltoNetworksXDR.Incident.alerts.description | String | Textual description of the alert. |
| PaloAltoNetworksXDR.Incident.alerts.host_ip_list | Unknown | Host IP involved in the alert. |
| PaloAltoNetworksXDR.Incident.alerts.host_name | String | Host name involved in the alert. |
| PaloAltoNetworksXDR.Incident.alerts.user_name | String | User name involved with the alert. |
| PaloAltoNetworksXDR.Incident.alerts.event_type | String | Event type. Valid values are: “Process Execution”,”Network Event”,”File Event”,”Registry Event”,”Injection Event”,”Load Image Event”,”Windows Event Log” |
| PaloAltoNetworksXDR.Incident.alerts.action | String | The action that triggered the alert. Valid values are: “REPORTED”, “BLOCKED”, “POST_DETECTED”, “SCANNED”, “DOWNLOAD”, “PROMPT_ALLOW”, “PROMPT_BLOCK”, “DETECTED”, “BLOCKED_1”, “BLOCKED_2”, “BLOCKED_3”, “BLOCKED_5”, “BLOCKED_6”, “BLOCKED_7”, “BLOCKED_8”, “BLOCKED_9”, “BLOCKED_10”, “BLOCKED_11”, “BLOCKED_13”, “BLOCKED_14”, “BLOCKED_15”, “BLOCKED_16”, “BLOCKED_17”, “BLOCKED_24”, “BLOCKED_25”, “DETECTED_0”, “DETECTED_4”, “DETECTED_18”, “DETECTED_19”, “DETECTED_20”, “DETECTED_21”, “DETECTED_22”, “DETECTED_23” |
| PaloAltoNetworksXDR.Incident.alerts.action_pretty | String | The action that triggered the alert. Valid values are: “Detected (Reported)” “Prevented (Blocked)” “Detected (Post Detected)” “Detected (Scanned)” “Detected (Download)” “Detected (Prompt Allow)” “Prevented (Prompt Block)” “Detected” “Prevented (Denied The Session)” “Prevented (Dropped The Session)” “Prevented (Dropped The Session And Sent a TCP Reset)” “Prevented (Blocked The URL)” “Prevented (Blocked The IP)” “Prevented (Dropped The Packet)” “Prevented (Dropped All Packets)” “Prevented (Terminated The Session And Sent a TCP Reset To Both Sides Of The Connection)” “Prevented (Terminated The Session And Sent a TCP Reset To The Client)” “Prevented (Terminated The Session And Sent a TCP Reset To The Server)” “Prevented (Continue)” “Prevented (Block-Override)” “Prevented (Override-Lockout)” “Prevented (Override)” “Prevented (Random-Drop)” “Prevented (Silently Dropped The Session With An ICMP Unreachable Message To The Host Or Application)” “Prevented (Block)” “Detected (Allowed The Session)” “Detected (Raised An Alert)” “Detected (Syncookie Sent)” “Detected (Forward)” “Detected (Wildfire Upload Success)” “Detected (Wildfire Upload Failure)” “Detected (Wildfire Upload Skip)” “Detected (Sinkhole)” |
| PaloAltoNetworksXDR.Incident.alerts.actor_process_image_name | String | Image name. |
| PaloAltoNetworksXDR.Incident.alerts.actor_process_command_line | String | Command line. |
| PaloAltoNetworksXDR.Incident.alerts.actor_process_signature_status | String | Signature status. Valid values are: “Signed” “Invalid Signature” “Unsigned” “Revoked” “Signature Fail” “N/A” “Weak Hash”. |
| PaloAltoNetworksXDR.Incident.alerts.actor_process_signature_vendor | String | Signature vendor name. |
| PaloAltoNetworksXDR.Incident.alerts.causality_actor_process_image_name | String | Image name. |
| PaloAltoNetworksXDR.Incident.alerts.causality_actor_process_command_line | String | Command line. |
| PaloAltoNetworksXDR.Incident.alerts.causality_actor_process_signature_status | String | Signature status. Valid values are: “Signed” “Invalid Signature” “Unsigned” “Revoked” “Signature Fail” “N/A” “Weak Hash” |
| PaloAltoNetworksXDR.Incident.alerts.causality_actor_process_signature_vendor | String | Signature vendor. |
| PaloAltoNetworksXDR.Incident.alerts.causality_actor_causality_id | Unknown | Causality ID. |
| PaloAltoNetworksXDR.Incident.alerts.action_process_image_name | String | Image name. |
| PaloAltoNetworksXDR.Incident.alerts.action_process_image_command_line | String | Command line. |
| PaloAltoNetworksXDR.Incident.alerts.action_process_image_sha256 | String | Image SHA256. |
| PaloAltoNetworksXDR.Incident.alerts.action_process_signature_status | String | Signature status. Valid values are: “Signed” “Invalid Signature” “Unsigned” “Revoked” “Signature Fail” “N/A” “Weak Hash” |
| PaloAltoNetworksXDR.Incident.alerts.action_process_signature_vendor | String | Signature vendor name. |
| PaloAltoNetworksXDR.Incident.alerts.action_file_path | String | File path. |
| PaloAltoNetworksXDR.Incident.alerts.action_file_md5 | String | File MD5. |
| PaloAltoNetworksXDR.Incident.alerts.action_file_sha256 | String | File SHA256. |
| PaloAltoNetworksXDR.Incident.alerts.action_registry_data | String | Registry data. |
| PaloAltoNetworksXDR.Incident.alerts.action_registry_full_key | String | Registry full key. |
| PaloAltoNetworksXDR.Incident.alerts.action_local_ip | String | Local IP. |
| PaloAltoNetworksXDR.Incident.alerts.action_local_port | Number | Local port. |
| PaloAltoNetworksXDR.Incident.alerts.action_remote_ip | String | Remote IP. |
| PaloAltoNetworksXDR.Incident.alerts.action_remote_port | Number | Remote port. |
| PaloAltoNetworksXDR.Incident.alerts.action_external_hostname | String | External hostname. |
| PaloAltoNetworksXDR.Incident.alerts.fw_app_id | Unknown | Firewall app id. |
| PaloAltoNetworksXDR.Incident.alerts.is_whitelisted | String | Is the alert on allow list. Valid values are: “Yes” “No” |
| PaloAltoNetworksXDR.Incident.alerts.starred | Boolean | Alert starred. |
| PaloAltoNetworksXDR.Incident.network_artifacts.type | String | Network artifact type. |
| PaloAltoNetworksXDR.Incident.network_artifacts.network_remote_port | number | The remote port related to the artifact. |
| PaloAltoNetworksXDR.Incident.network_artifacts.alert_count | number | Number of alerts related to the artifact. |
| PaloAltoNetworksXDR.Incident.network_artifacts.network_remote_ip | String | The remote IP related to the artifact. |
| PaloAltoNetworksXDR.Incident.network_artifacts.is_manual | boolean | Whether the artifact was created by the user (manually). |
| PaloAltoNetworksXDR.Incident.network_artifacts.network_domain | String | The domain related to the artifact. |
| PaloAltoNetworksXDR.Incident.network_artifacts.type | String | The artifact type. Valid values are: “META”, “GID”, “CID”, “HASH”, “IP”, “DOMAIN”, “REGISTRY”, “HOSTNAME” |
| PaloAltoNetworksXDR.Incident.network_artifacts.network_country | String | The country related to the artifact. |
| PaloAltoNetworksXDR.Incident.file_artifacts.file_signature_status | String | Digital signature status of the file. Valid values are: “SIGNATURE_UNAVAILABLE” “SIGNATURE_SIGNED” “SIGNATURE_INVALID” “SIGNATURE_UNSIGNED” “SIGNATURE_WEAK_HASH” |
| PaloAltoNetworksXDR.Incident.file_artifacts.is_process | boolean | Whether the file artifact is related to a process execution. |
| PaloAltoNetworksXDR.Incident.file_artifacts.file_name | String | Name of the file. |
| PaloAltoNetworksXDR.Incident.file_artifacts.file_wildfire_verdict | String | The file verdict, calculated by Wildfire. Valid values are: “BENIGN” “MALWARE” “GRAYWARE” “PHISHING” “UNKNOWN”. |
| PaloAltoNetworksXDR.Incident.file_artifacts.alert_count | number | Number of alerts related to the artifact. |
| PaloAltoNetworksXDR.Incident.file_artifacts.is_malicious | boolean | Whether the artifact is malicious, as decided by the Wildfire verdict. |
| PaloAltoNetworksXDR.Incident.file_artifacts.is_manual | boolean | Whether the artifact was created by the user (manually). |
| PaloAltoNetworksXDR.Incident.file_artifacts.type | String | The artifact type. Valid values are: “META” “GID” “CID” “HASH” “IP” “DOMAIN” “REGISTRY” “HOSTNAME” |
| PaloAltoNetworksXDR.Incident.file_artifacts.file_sha256 | String | SHA256 hash of the file. |
| PaloAltoNetworksXDR.Incident.file_artifacts.file_signature_vendor_name | String | File signature vendor name. |
| Account.Username | String | The username in the relevant system. |
| Endpoint.Hostname | String | The hostname that is mapped to this endpoint. |
| Endpoint.ID | String | The agent ID of the endpoint. |
| File.Path | String | The path where the file is located. |
| File.MD5 | String | The MD5 hash of the file. |
| File.SHA256 | String | The SHA256 hash of the file. |
| File.Name | String | The full file name (including file extension). |
| Process.Name | String | The name of the process. |
| Process.MD5 | String | The MD5 hash of the process. |
| Process.SHA256 | String | The SHA256 hash of the process. |
| Process.PID | String | The PID of the process. |
| Process.Path | String | The file system path to the binary file. |
| Process.Start Time | String | The timestamp of the process start time. |
| Process.CommandLine | String | The full command line (including arguments). |
| Process.is_malicious | boolean | Whether the artifact is malicious, as decided by the Wildfire verdict. |
| IP.Address | String | IP address. |
| IP.Geo.Country | String | The country in which the IP address is located. |
| Domain.Name | String | The domain name, for example: “google.com”. |
Human Readable Output
Incident 4
alert_count assigned_user_mail assigned_user_pretty_name creation_time description detection_time high_severity_alert_count host_count incident_id low_severity_alert_count manual_description manual_severity med_severity_alert_count modification_time notes resolve_comment severity starred status user_count xdr_url 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/4Alerts
action action_external_hostname action_file_md5 action_file_path action_file_sha256 action_local_ip action_local_port action_pretty action_process_image_command_line action_process_image_name action_process_image_sha256 action_process_signature_status action_process_signature_vendor action_registry_data action_registry_full_key action_remote_ip action_remote_port actor_process_command_line actor_process_image_name actor_process_signature_status actor_process_signature_vendor alert_id category causality_actor_causality_id causality_actor_process_command_line causality_actor_process_image_name causality_actor_process_signature_status causality_actor_process_signature_vendor description detection_timestamp event_type fw_app_id host_ip_list host_name is_whitelisted name severity source starred user_name VALUE_NA,
N/A196.168.0.1 7000 VALUE_NA,
N/AN/A N/A 2.2.2.2 8000 N/A N/A 6 N/A N/A Test - alert generated by Test XDR Playbook 1577276586921 Network Event No Test - alert generated by Test XDR Playbook medium Cisco - Sandblast false VALUE_NA,
N/A196.168.0.111 2000 VALUE_NA,
N/AN/A N/A 2.2.2.2 6000 N/A N/A 7 N/A N/A This alert from content TestXDRPlaybook description 1577776701589 Network Event No This alert from content TestXDRPlaybook high Checkpoint - SandBlast false VALUE_NA,
N/A196.168.0.111 2000 VALUE_NA,
N/AN/A N/A 2.2.2.2 6000 N/A N/A 8 N/A N/A This alert from content TestXDRPlaybook description 1577958479843 Network Event No This alert from content TestXDRPlaybook high Checkpoint - SandBlast false VALUE_NA,
N/A196.168.0.111 2000 VALUE_NA,
N/AN/A N/A 2.2.2.2 6000 N/A N/A 9 N/A N/A This alert from content TestXDRPlaybook description 1578123895414 Network Event No This alert from content TestXDRPlaybook high Checkpoint - SandBlast false VALUE_NA,
N/A196.168.0.111 2000 VALUE_NA,
N/AN/A N/A 2.2.2.2 6000 N/A N/A 10 N/A N/A This alert from content TestXDRPlaybook description 1578927443615 Network Event No This alert from content TestXDRPlaybook high Checkpoint - SandBlast false Network Artifacts
alert_count is_manual network_country network_domain network_remote_ip network_remote_port type 5 false 2.2.2.2 8000 IP File Artifacts
No entries.
xdr-update-incident (Deprecated)
This command is deprecated please use xdr-case-update instead. Updates one or more fields of a specified incident. Missing fields will be ignored. To remove the assignment for an incident, pass a null value in the assignee email argument.
Required Permissions
Required Permissions For API call:
Alerts And Incidents –> View / Edit
Builtin Roles with this permission includes: “Investigator”, “Privileged Investigator”, “Privileged Responder”, and “Instance Admin”.
Base Command
xdr-update-incident
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | XDR incident ID. You can get the incident ID from the output of the ‘xdr-get-incidents’ command or the ‘xdr-get-incident-extra-details’ command. | Required |
| manual_severity | Severity to assign to the incident (LOW, MEDIUM, or HIGH). Possible values are: HIGH, MEDIUM, LOW. | Optional |
| assigned_user_mail | Email address of the user to assign to the incident. | Optional |
| assigned_user_pretty_name | Full name of the user assigned to the incident. To supply a new value in this field, you must also provide a value for the ‘assigned_user_mail’ argument. | Optional |
| status | Status of the incident. Valid values are: NEW, UNDER_INVESTIGATION, RESOLVED_KNOWN_ISSUE, RESOLVED_DUPLICATE, RESOLVED_FALSE_POSITIVE, RESOLVED_TRUE_POSITIVE, RESOLVED_SECURITY_TESTING, RESOLVED_OTHER. Possible values are: NEW, UNDER_INVESTIGATION, RESOLVED_KNOWN_ISSUE, RESOLVED_DUPLICATE, RESOLVED_FALSE_POSITIVE, RESOLVED_TRUE_POSITIVE, RESOLVED_SECURITY_TESTING, RESOLVED_OTHER. | Optional |
| resolve_comment | Comment explaining why the incident was resolved. This should be set when the incident is resolved. | Optional |
| unassign_user | If true, will remove all assigned users from the incident. Possible values are: true. | Optional |
Command Example
!xdr-update-incident incident_id=4
Context Output
There is no context output for this command.
Human Readable Output
Incident 4 has been updated
xdr-insert-parsed-alert (Deprecated)
This command is deprecated. Uploads an alert from external alert sources in Cortex XDR format. Cortex XDR displays alerts that are parsed
successfully in related incidents and views. You can send 600 alerts per minute. Each request can contain a
maximum of 60 alerts.
Required Permissions
Required Permissions For API call:
External Alerts Mapping–> View
Builtin Roles with this permission includes: “Instance Admin”.
Base Command
xdr-insert-parsed-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| product | String value that defines the product. | Required |
| vendor | String value that defines the vendor. | Required |
| local_ip | String value for the source IP address. | Optional |
| local_port | Integer value for the source port. | Required |
| remote_ip | String value of the destination IP address. |
Required |
| remote_port | Integer value for the destination port. |
Required |
| event_timestamp | Integer value representing the time the alert occurred in milliseconds, or a string value in date format 2019-10-23T10:00:00. If not set, the event time will be defined as now. | Optional |
| severity | String value of alert severity. Valid values are: Informational, Low, Medium or High. Possible values are: Informational, Low, Medium, High. Default is Medium. |
Optional |
| alert_name | String defining the alert name. | Required |
| alert_description | String defining the alert description. | Optional |
Context Output
There is no context output for this command.
xdr-insert-cef-alerts (Deprecated)
This command is deprecated. Upload alerts in CEF format from external alert sources. After you map CEF alert fields to Cortex XDR fields, Cortex XDR displays the alerts in related incidents and views. You can send 600 requests per minute. Each request can contain a maximum of 60 alerts.
Required Permissions
Required Permissions For API call:
External Alerts Mapping–> View
Builtin Roles with this permission includes: “Instance Admin”.
Base Command
xdr-insert-cef-alerts
Input
| Argument Name | Description | Required |
|---|---|---|
| cef_alerts | List of alerts in CEF format. | Required |
Context Output
There is no context output for this command.
xdr-endpoint-isolate
Isolates the specified endpoint.
Required Permissions
Required Permissions For API call:
Endpoint Administrations –> View
Action Center –> View/ Edit
Action Center –> Isolate
Builtin Roles with this permission includes: “Privileged Responder” and “Instance Admin”.
Base Command
xdr-endpoint-isolate
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | Allows linking the response action to the incident that triggered it. | Optional |
| endpoint_id | The endpoint ID (string) to isolate. You can retrieve the string from the xdr-get-endpoints command. | Required |
| suppress_disconnected_endpoint_error | Whether to suppress an error when trying to isolate a disconnected endpoint. When sets to false, an error will be returned. Possible values are: true, false. Default is false. | Optional |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | For polling use. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Isolation.endpoint_id | String | The endpoint ID. |
xdr-endpoint-unisolate
Reverses the isolation of an endpoint.
Required Permissions
Required Permissions For API call:
Endpoint Administrations –> View
Action Center –> View/ Edit
Action Center –> Isolate
Builtin Roles with this permission includes: “Privileged Responder” and “Instance Admin”.
Base Command
xdr-endpoint-unisolate
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | Allows linking the response action to the incident that triggered it. | Optional |
| endpoint_id | The endpoint ID (string) for which to reverse the isolation. You can retrieve it from the xdr-get-endpoints command. | Required |
| suppress_disconnected_endpoint_error | Whether to suppress an error when trying to unisolate a disconnected endpoint. When sets to false, an error will be returned. Possible values are: true, false. Default is false. | Optional |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | For polling use. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.UnIsolation.endpoint_id | String | Isolates the specified endpoint. |
xdr-get-endpoints
Gets a list of endpoints, according to the passed filters. If there are no filters, all endpoints are returned. Filtering by multiple fields will be concatenated using AND condition (OR is not supported). Maximum result set size is 100. Offset is the zero-based number of endpoint from the start of the result set (start by counting from 0).
Required Permissions
Required Permissions For API call:
Endpoint Administrations –> View
Builtin Roles with this permission includes: “Privileged Responder”, “Viewer” and “Instance Admin”.
Base Command
xdr-get-endpoints
Input
| Argument Name | Description | Required |
|---|---|---|
| status | A comma-separated list of endpoints statuses to filter. Valid values are: connected, disconnected, lost, uninstalled, windows, linux, macos, android, isolated, unisolated. | Optional |
| endpoint_id_list | A comma-separated list of endpoint IDs. | Optional |
| dist_name | A comma-separated list of distribution package names or installation package names. Example: dist_name1,dist_name2. |
Optional |
| ip_list | A comma-separated list of private IP addresses. Example: Example: 10.1.1.1,192.168.1.1. |
Optional |
| public_ip_list | A comma-separated list of public IP addresses that correlate to the last IPv4 address from which the Cortex XDR agent connected (know as Last Origin IP).Example: 8.8.8.8,1.1.1.1. |
Optional |
| group_name | The group name to which the agent belongs. Example: group_name1,group_name2. |
Optional |
| platform | The endpoint platform. Valid values are: “windows”, “linux”, “macos”, or “android”. . Possible values are: windows, linux, macos, android. | Optional |
| alias_name | A comma-separated list of alias names. Examples: alias_name1,alias_name2. |
Optional |
| isolate | Specifies whether the endpoint was isolated or unisolated. Possible values are: isolated, unisolated. | Optional |
| hostname | Hostname Example: hostname1,hostname2. |
Optional |
| first_seen_gte | All the agents that were first seen after {first_seen_gte}. Supported values: 1579039377301 (time in milliseconds) “3 days” (relative date) “2019-10-21T23:45:00” (date). |
Optional |
| first_seen_lte | All the agents that were first seen before {first_seen_lte}. Supported values: 1579039377301 (time in milliseconds) “3 days” (relative date) “2019-10-21T23:45:00” (date). |
Optional |
| last_seen_gte | All the agents that were last seen before {last_seen_gte}. Supported values: 1579039377301 (time in milliseconds) “3 days” (relative date) “2019-10-21T23:45:00” (date). |
Optional |
| last_seen_lte | All the agents that were last seen before {last_seen_lte}. Supported values: 1579039377301 (time in milliseconds) “3 days” (relative date) “2019-10-21T23:45:00” (date). |
Optional |
| page | Page number (for pagination). The default is 0 (the first page). Default is 0. | Optional |
| limit | Maximum number of endpoints to return per page. The default and maximum is 30. Default is 30. | Optional |
| sort_by | Specifies whether to sort endpoints by the first time or last time they were seen. Can be “first_seen” or “last_seen”. Possible values are: first_seen, last_seen. | Optional |
| sort_order | The order by which to sort results. Can be “asc” (ascending) or “desc” ( descending). Default set to asc. Possible values are: asc, desc. Default is asc. | Optional |
| username | The usernames to query for, accepts a single user, or comma-separated list of usernames. | Optional |
| all_results | Whether to return all endpoints. If true, will override the ‘limit’ and ‘page’ arguments. Possible values are: false, true. Default is false. | Optional |
| use_hr_timestamps | Whether to return timestamp values in human-readable format as opposed to Unix epoch timestamp format. Possible values are: false, true. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Endpoint.endpoint_id | String | The endpoint ID. |
| PaloAltoNetworksXDR.Endpoint.endpoint_name | String | The endpoint name. |
| PaloAltoNetworksXDR.Endpoint.endpoint_type | String | The endpoint type. |
| PaloAltoNetworksXDR.Endpoint.endpoint_status | String | The status of the endpoint. |
| PaloAltoNetworksXDR.Endpoint.os_type | String | The endpoint OS type. |
| PaloAltoNetworksXDR.Endpoint.ip | Unknown | A list of IP addresses. |
| PaloAltoNetworksXDR.Endpoint.users | Unknown | A list of users. |
| PaloAltoNetworksXDR.Endpoint.domain | String | The endpoint domain. |
| PaloAltoNetworksXDR.Endpoint.alias | String | The endpoint’s aliases. |
| PaloAltoNetworksXDR.Endpoint.first_seen | Unknown | First seen date/time in Epoch (milliseconds). |
| PaloAltoNetworksXDR.Endpoint.last_seen | Date | Last seen date/time in Epoch (milliseconds). |
| PaloAltoNetworksXDR.Endpoint.content_version | String | Content version. |
| PaloAltoNetworksXDR.Endpoint.installation_package | String | Installation package. |
| PaloAltoNetworksXDR.Endpoint.active_directory | String | Active directory. |
| PaloAltoNetworksXDR.Endpoint.install_date | Date | Install date in Epoch (milliseconds). |
| PaloAltoNetworksXDR.Endpoint.endpoint_version | String | Endpoint version. |
| PaloAltoNetworksXDR.Endpoint.is_isolated | String | Whether the endpoint is isolated. |
| PaloAltoNetworksXDR.Endpoint.group_name | String | The name of the group to which the endpoint belongs. |
| PaloAltoNetworksXDR.Endpoint.count | String | Number of endpoints returned. |
| Endpoint.Hostname | String | The hostname that is mapped to this endpoint. |
| Endpoint.ID | String | The unique ID within the tool retrieving the endpoint. |
| Endpoint.IPAddress | String | The IP address of the endpoint. |
| Endpoint.Domain | String | The domain of the endpoint. |
| Endpoint.OS | String | The endpoint’s operation system. |
| Account.Username | String | The username in the relevant system. |
| Account.Domain | String | The domain of the account. |
| Endpoint.Status | String | The endpoint’s status. |
| Endpoint.IsIsolated | String | The endpoint’s isolation status. |
| Endpoint.MACAddress | String | The endpoint’s MAC address. |
| Endpoint.Vendor | String | The integration name of the endpoint vendor. |
Command Example
!xdr-get-endpoints isolate="unisolated" first_seen_gte="3 month" page="0" limit="30" sort_order="asc"
Context Example
{
"Endpoint": [
{
"Domain": "WORKGROUP",
"Hostname": "aaaaa.compute.internal",
"ID": "ea303670c76e4ad09600c8b346f7c804",
"IPAddress": [
"172.31.11.11"
],
"OS": "Windows",
"Status" : "Online",
"IsIsolated" : "No",
"Vendor": "Cortex XDR - IR"
},
{
"Domain": "WORKGROUP",
"Hostname": "EC2AMAZ-P7PPOI4",
"ID": "f8a2f58846b542579c12090652e79f3d",
"IPAddress": [
"2.2.2.2"
],
"OS": "Windows",
"Status" : "Online",
"IsIsolated" : "No",
"Vendor": "Cortex XDR - IR"
}
],
"PaloAltoNetworksXDR.Endpoint": [
{
"domain": "",
"users": [
"ec2-user"
],
"endpoint_name": "aaaaa.compute.internal",
"ip": [
"172.31.11.11"
],
"install_date": 1575795969644,
"endpoint_version": "7.0.0.1915",
"group_name": null,
"installation_package": "linux",
"alias": "",
"active_directory": null,
"endpoint_status": "CONNECTED",
"os_type": "AGENT_OS_LINUX",
"endpoint_id": "ea303670c76e4ad09600c8b346f7c804",
"content_version": "111-17757",
"first_seen": 1575795969644,
"endpoint_type": "AGENT_TYPE_SERVER",
"is_isolated": "AGENT_UNISOLATED",
"last_seen": 1579290023629
},
{
"domain": "WORKGROUP",
"users": [
"Administrator"
],
"endpoint_name": "EC2AMAZ-P7PPOI4",
"ip": [
"2.2.2.2"
],
"install_date": 1575796381739,
"endpoint_version": "7.0.0.27797",
"group_name": null,
"installation_package": "Windows Server 2016",
"alias": "",
"active_directory": null,
"endpoint_status": "CONNECTED",
"os_type": "AGENT_OS_WINDOWS",
"endpoint_id": "f8a2f58846b542579c12090652e79f3d",
"content_version": "111-17757",
"first_seen": 1575796381739,
"endpoint_type": "AGENT_TYPE_SERVER",
"is_isolated": "AGENT_UNISOLATED",
"last_seen": 1579289957412
}
]
}
Human Readable Output
Endpoints
active_directory alias content_version domain endpoint_id endpoint_name endpoint_status endpoint_type endpoint_version first_seen group_name install_date installation_package ip is_isolated last_seen os_type users 111-17757 ea303670c76e4ad09600c8b346f7c804 aaaaa.compute.internal CONNECTED AGENT_TYPE_SERVER 7.0.0.1915 1575795969644 1575795969644 linux 172.31.11.11 AGENT_UNISOLATED 1579290023629 AGENT_OS_LINUX ec2-user 111-17757 WORKGROUP f8a2f58846b542579c12090652e79f3d EC2AMAZ-P7PPOI4 CONNECTED AGENT_TYPE_SERVER 7.0.0.27797 1575796381739 1575796381739 Windows Server 2016 2.2.2.2 AGENT_UNISOLATED 1579289957412 AGENT_OS_WINDOWS Administrator
xdr-get-distribution-versions
Gets a list of all the agent versions to use for creating a distribution list.
Required Permissions
Required Permissions For API call:
Endpoint Installations –> View
Builtin Roles with this permission includes: “Viewer” and “Instance Admin”.
Base Command
xdr-get-distribution-versions
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.DistributionVersions.windows | Unknown | A list of Windows agent versions. |
| PaloAltoNetworksXDR.DistributionVersions.linux | Unknown | A list of Linux agent versions. |
| PaloAltoNetworksXDR.DistributionVersions.macos | Unknown | A list of Mac agent versions. |
Command Example
##### Context Example
{
“PaloAltoNetworksXDR.DistributionVersions”: {
“windows”: [
“5.0.8.29673”,
“5.0.9.30963”,
“6.1.4.28751”,
“7.0.0.28644”
],
“macos”: [
“6.1.4.1681”,
“7.0.0.1914”
],
“linux”: [
“6.1.4.1680”,
“7.0.0.1916”
]
}
}
##### Human Readable Output
>### windows
>|versions|
>|---|
>| 5.0.8.29673 |
>| 5.0.9.30963 |
>| 6.1.4.28751 |
>| 7.0.0.28644 |
>
>
>### linux
>|versions|
>|---|
>| 6.1.4.1680 |
>| 7.0.0.1916 |
>
>
>### macos
>|versions|
>|---|
>| 6.1.4.1681 |
>| 7.0.0.1914 |
### xdr-create-distribution
***
Creates an installation package. This is an asynchronous call that returns the distribution ID. This does not mean that the creation succeeded. To confirm that the package has been created, check the status of the distribution by running the Get Distribution Status API.
##### Required Permissions
Required Permissions For API call:
`Endpoint Installations` --> `View/ Edit`
Builtin Roles with this permission includes: "Instance Admin".
#### Base Command
`xdr-create-distribution`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| name | A string representing the name of the installation package. | Required |
| platform | String, valid values are:<br/>• windows <br/>• linux<br/>• macos <br/>• android. Possible values are: windows, linux, macos, android. | Required |
| package_type | A string representing the type of package to create.<br/>standalone - An installation for a new agent<br/>upgrade - An upgrade of an agent from ESM. Possible values are: standalone, upgrade. | Required |
| agent_version | agent_version returned from xdr-get-distribution-versions. Not required for Android platform. | Required |
| description | Information about the package. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.Distribution.id | String | The installation package ID. |
| PaloAltoNetworksXDR.Distribution.name | String | The name of the installation package. |
| PaloAltoNetworksXDR.Distribution.platform | String | The installation OS. |
| PaloAltoNetworksXDR.Distribution.agent_version | String | Agent version. |
| PaloAltoNetworksXDR.Distribution.description | String | Information about the package. |
##### Command Example
```!xdr-create-distribution agent_version=6.1.4.1680 name="dist_1" package_type=standalone platform=linux description="some description"```
##### Context Example
{
“PaloAltoNetworksXDR.Distribution”: {
“description”: “some description”,
“package_type”: “standalone”,
“platform”: “linux”,
“agent_version”: “6.1.4.1680”,
“id”: “43aede7f846846fa92b50149663fbb25”,
“name”: “dist_1”
}
}
##### Human Readable Output
Distribution 43aede7f846846fa92b50149663fbb25 created successfully
### xdr-get-distribution-url
***
Gets the distribution URL for downloading the installation package.
##### Required Permissions
Required Permissions For API call:
`Endpoint Installations` --> `View`
Builtin Roles with this permission includes: "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-distribution-url`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| distribution_id | The ID of the installation package.<br/>Copy the distribution_id from the "id" field on Endpoints > Agent Installation page. | Required |
| package_type | The installation package type. Valid<br/>values are:<br/>• upgrade<br/>• sh - For Linux<br/>• rpm - For Linux<br/>• deb - For Linux<br/>• pkg - For Mac<br/>• x86 - For Windows<br/>• x64 - For Windows. Possible values are: upgrade, sh, rpm, deb, pkg, x86, x64. | Required |
| download_package | Supported only for package_type x64 or x86. Whether to download the installation package file. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.Distribution.id | String | Distribution ID. |
| PaloAltoNetworksXDR.Distribution.url | String | URL for downloading the installation package. |
##### Command Example
```!xdr-get-distribution-url distribution_id=2c74c11b63074653aa01d575a82bf52a package_type=sh```
### xdr-get-create-distribution-status
***
Gets the status of the installation package.
##### Required Permissions
Required Permissions For API call:
`Endpoint Installations` --> `View`
Builtin Roles with this permission includes: "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-create-distribution-status`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| distribution_ids | A comma-separated list of distribution IDs to get the status for. | Required |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.Distribution.id | String | Distribution ID. |
| PaloAltoNetworksXDR.Distribution.status | String | The status of installation package. |
##### Command Example
```!xdr-get-create-distribution-status distribution_ids=2c74c11b63074653aa01d575a82bf52a```
### xdr-get-audit-management-logs
***
Gets management logs. You can filter by multiple fields, which will be concatenated using the AND condition (OR is not supported). Maximum result set size is 100. Offset is the zero-based number of management logs from the start of the result set (start by counting from 0).
##### Required Permissions
Required Permissions For API call:
`Auditing` --> `View`
Builtin Roles with this permission includes: "Viewer" and "Instance Admin".
##### Context Example
{
“PaloAltoNetworksXDR.Distribution”: [
{
“status”: “Completed”,
“id”: “2c74c11b63074653aa01d575a82bf52a”
}
]
}
##### Human Readable Output
>### Distribution Status
>|id|status|
>|---|---|
>| 2c74c11b63074653aa01d575a82bf52a | Completed |
#### Base Command
`xdr-get-audit-management-logs`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| email | User’s email address. | Optional |
| type | The audit log type. Possible values are: LIVE_TERMINAL, RULES, AUTH, RESPONSE, INCIDENT_MANAGEMENT, ENDPOINT_MANAGEMENT, ALERT_WHITELIST, PUBLIC_API, DISTRIBUTIONS, STARRED_INCIDENTS, POLICY_PROFILES, DEVICE_CONTROL_PROFILE, HOST_FIREWALL_PROFILE, POLICY_RULES, PROTECTION_POLICY, DEVICE_CONTROL_TEMP_EXCEPTIONS, DEVICE_CONTROL_GLOBAL_EXCEPTIONS, GLOBAL_EXCEPTIONS, MSSP, REPORTING, DASHBOARD, BROKER_VM. | Optional |
| sub_type | The audit log subtype. | Optional |
| result | Result type. Possible values are: SUCCESS, FAIL, PARTIAL. | Optional |
| timestamp_gte | Return logs for which the timestamp is after 'log_time_after'.<br/>Supported values:<br/>1579039377301 (time in milliseconds)<br/>"3 days" (relative date)<br/>"2019-10-21T23:45:00" (date). | Optional |
| timestamp_lte | Return logs for which the timestamp is before the 'log_time_after'.<br/>Supported values:<br/>1579039377301 (time in milliseconds)<br/>"3 days" (relative date)<br/>"2019-10-21T23:45:00" (date). | Optional |
| page | Page number (for pagination). The default is 0 (the first page). Default is 0. | Optional |
| limit | Maximum number of audit logs to return per page. The default and maximum is 30. Default is 30. | Optional |
| sort_by | Specifies the field by which to sort the results. By default the sort is defined as creation-time and DESC. Can be "type", "sub_type", "result", or "timestamp". Possible values are: type, sub_type, result, timestamp. | Optional |
| sort_order | The sort order. Can be "asc" (ascending) or "desc" (descending). Default set to "desc". Possible values are: asc, desc. Default is desc. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_ID | Number | Audit log ID. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_OWNER_NAME | String | Audit owner name. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_OWNER_EMAIL | String | Audit owner email address. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_ASSET_JSON | String | Asset JSON. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_ASSET_NAMES | String | Audit asset names. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_HOSTNAME | String | Host name. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_RESULT | String | Audit result. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_REASON | String | Audit reason. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_DESCRIPTION | String | Description of the audit. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_ENTITY | String | Audit entity (e.g., AUTH, DISTRIBUTIONS). |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_ENTITY_SUBTYPE | String | Entity subtype (e.g., Login, Create). |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_CASE_ID | Number | Audit case ID. |
| PaloAltoNetworksXDR.AuditManagementLogs.AUDIT_INSERT_TIME | Date | Log's insert time. |
### xdr-get-audit-agent-reports
***
Gets agent event reports. You can filter by multiple fields, which will be concatenated using the AND condition (OR is not supported). Maximum result set size is 100. Offset is the zero-based number of reports from the start of the result set (start by counting from 0).
##### Required Permissions
Required Permissions For API call:
`Auditing` --> `View`
Builtin Roles with this permission includes: "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-audit-agent-reports`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| endpoint_ids | A comma-separated list of endpoint IDs. | Optional |
| endpoint_names | A comma-separated list of endpoint names. | Optional |
| type | The report type. Can be "Installation", "Policy", "Action", "Agent Service", "Agent Modules", or "Agent Status". Possible values are: Installation, Policy, Action, Agent Service, Agent Modules, Agent Status. | Optional |
| sub_type | The report subtype. Possible values are: Install, Uninstall, Upgrade, Local Configuration, Content Update, Policy Update, Process Exception, Hash Exception, Scan, File Retrieval, File Scan, Terminate Process, Isolate, Cancel Isolation, Payload Execution, Quarantine, Restore, Stop, Start, Module Initialization, Local Analysis Model, Local Analysis Feature Extraction, Fully Protected, OS Incompatible, Software Incompatible, Kernel Driver Initialization, Kernel Extension Initialization, Proxy Communication, Quota Exceeded, Minimal Content, Reboot Required, Missing Disc Access. | Optional |
| result | The result type. Can be "Success" or "Fail". If not passed, returns all event reports. Possible values are: Success, Fail. | Optional |
| timestamp_gte | Return logs that their timestamp is greater than 'log_time_after'.<br/>Supported values:<br/>1579039377301 (time in milliseconds)<br/>"3 days" (relative date)<br/>"2019-10-21T23:45:00" (date). | Optional |
| timestamp_lte | Return logs for which the timestamp is before the 'timestamp_lte'.<br/><br/>Supported values:<br/>1579039377301 (time in milliseconds)<br/>"3 days" (relative date)<br/>"2019-10-21T23:45:00" (date). | Optional |
| page | Page number (for pagination). The default is 0 (the first page). Default is 0. | Optional |
| limit | The maximum number of reports to return. Default and maximum is 30. Default is 30. | Optional |
| sort_by | The field by which to sort results. Can be "type", "category", "trapsversion", "timestamp", or "domain"). Possible values are: type, category, trapsversion, timestamp, domain. | Optional |
| sort_order | The sort order. Can be "asc" (ascending) or "desc" (descending). Default is "asc". Possible values are: asc, desc. Default is asc. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.AuditAgentReports.ENDPOINTID | String | Endpoint ID. |
| PaloAltoNetworksXDR.AuditAgentReports.ENDPOINTNAME | String | Endpoint name. |
| PaloAltoNetworksXDR.AuditAgentReports.DOMAIN | String | Agent domain. |
| PaloAltoNetworksXDR.AuditAgentReports.TRAPSVERSION | String | Traps version. |
| PaloAltoNetworksXDR.AuditAgentReports.RECEIVEDTIME | Date | Received time in Epoch time. |
| PaloAltoNetworksXDR.AuditAgentReports.TIMESTAMP | Date | Timestamp in Epoch time. |
| PaloAltoNetworksXDR.AuditAgentReports.CATEGORY | String | Report category (e.g., Audit). |
| PaloAltoNetworksXDR.AuditAgentReports.TYPE | String | Report type (e.g., Action, Policy). |
| PaloAltoNetworksXDR.AuditAgentReports.SUBTYPE | String | Report subtype (e.g., Fully Protected,Policy Update,Cancel Isolation\). |
| PaloAltoNetworksXDR.AuditAgentReports.RESULT | String | Report result. |
| PaloAltoNetworksXDR.AuditAgentReports.REASON | String | Report reason. |
| PaloAltoNetworksXDR.AuditAgentReports.DESCRIPTION | String | Agent report description. |
| Endpoint.ID | String | The unique ID within the tool retrieving the endpoint. |
| Endpoint.Hostname | String | The hostname that is mapped to this endpoint. |
| Endpoint.Domain | String | The domain of the endpoint. |
### xdr-blocklist-files
***
Block lists requested files which have not already been block listed or added to allow lists.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View/ Edit`
`Action Center` --> `Allow List/Block List`
Builtin Roles with this permission includes: "Responder", "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-blocklist-files`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Links the response action to the triggered incident. | Optional |
| hash_list | String that represents a list of hashed files you want to block list. Must be a valid SHA256 hash. | Required |
| comment | String that represents additional information regarding the action. | Optional |
| detailed_response | Choose either regular response or detailed response. Default value = false, regular response. Possible values are: true, false. Default is false. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.blocklist.added_hashes | Number | Number of file hashes added to block list. |
| PaloAltoNetworksXDR.blocklist.excluded_hashes | Number | Number of file hashes excluded from block list. |
### xdr-allowlist-files
***
Adds requested files to allow list if they are not already on block list or allow list.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View/ Edit`
`Action Center` --> `Allow List/Block List`
Builtin Roles with this permission includes: "Responder", "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-allowlist-files`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Links the response action to the triggered incident. | Optional |
| hash_list | String that represents a list of hashed files you want to add to allow lists. Must be a valid SHA256 hash. | Required |
| comment | String that represents additional information regarding the action. | Optional |
| detailed_response | Choose either regular response or detailed response. Default value = false, regular response. Possible values are: true, false. Default is false. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.allowlist.added_hashes | Number | Number of added file hashes to allowlist. |
| PaloAltoNetworksXDR.allowlist.excluded_hashes | Number | Number of excluded file hashes from allowlist. |
### xdr-file-quarantine
***
Quarantines a file on selected endpoints. You can select up to 1000 endpoints.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View/ Edit`
`Action Center` --> `Quarantine`
Builtin Roles with this permission includes: "Responder", "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-file-quarantine`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Allows linking the response action to the incident that triggered it. | Optional |
| endpoint_id_list | List of endpoint IDs. | Required |
| file_path | String that represents the path of the file you want to quarantine. | Required |
| file_hash | String that represents the file's hash. Must be a valid SHA256 hash. | Required |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | The action IDs for polling use. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.bucket | String | The bucket in which the error occurred. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_name | String | The name of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_path | String | The path of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_size | Number | The size of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.missing_files | Unknown | The missing files that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorData | String | The error reason data. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminated_by | String | The instance ID which terminated the action and caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorDescription | String | The error reason description. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminate_result | Unknown | The error reason terminate result. |
### xdr-get-quarantine-status
***
Retrieves the quarantine status for a selected file.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View/ Edit`
`Action Center` --> `Quarantine`
Builtin Roles with this permission includes: "Responder", "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-get-quarantine-status`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| endpoint_id | String the represents the endpoint ID. | Required |
| file_hash | String that represents the file hash. Must be a valid SHA256 hash. | Required |
| file_path | String that represents the file path. | Required |
#### Context Output
There is no context output for this command.
### xdr-file-restore
***
Restores a quarantined file on requested endpoints.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View/ Edit`
`Action Center` --> `Quarantine`
Builtin Roles with this permission includes: "Responder", "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-file-restore`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Allows linking the response action to the incident that triggered it. | Optional |
| file_hash | The hash code of the file. Must be a valid SHA256 hash. | Required |
| endpoint_id | String that represents the endpoint ID. If you do not enter a specific endpoint ID, the request will run restore on all endpoints that relate to the quarantined file you defined. | Optional |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | The action IDs for polling use. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.bucket | String | The bucket in which the error occurred. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_name | String | The name of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_path | String | The path of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_size | Number | The size of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.missing_files | Unknown | The missing files that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorData | String | The error reason data. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminated_by | String | The instance ID which terminated the action and caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorDescription | String | The error reason description. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminate_result | Unknown | The error reason terminate result. |
### xdr-endpoint-scan-execute
***
Runs a scan on a selected endpoint. To scan all endpoints, run this command with argument all=true. Note: scanning all the endpoints may cause performance issues and latency.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View`
`Endpoint Administrations` --> `View/ Edit`
`Endpoint Administrations` --> `Endpoint Scan`
Builtin Roles with this permission includes: "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-endpoint-scan-execute`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Allows linking the response action to the incident that triggered it. | Optional |
| endpoint_id_list | List of endpoint IDs. | Optional |
| dist_name | Name of the distribution list. | Optional |
| gte_first_seen | Greater than or equal to first seen timestamp in milliseconds. | Optional |
| gte_last_seen | Greater than or equal to last seen timestamp in milliseconds. | Optional |
| lte_first_seen | Less than or equal to first seen timestamp in milliseconds. | Optional |
| lte_last_seen | Less than or equal to last seen timestamp in milliseconds. | Optional |
| ip_list | List of IP addresses. | Optional |
| group_name | Name of the endpoint group. | Optional |
| platform | Type of operating system. Possible values are: windows, linux, macos, android. | Optional |
| alias | Endpoint alias name. | Optional |
| isolate | Whether an endpoint has been isolated. Possible values are: isolated, unisolated. | Optional |
| hostname | Name of the host. | Optional |
| all | Whether to scan all of the endpoints. Scanning all of the endpoints may cause performance issues and latency. Possible values are: true, false. Default is false. | Optional |
| action_id | The action IDs for polling use. | Optional |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.endpointScan.actionId | Number | The action ID of the scan request. |
| PaloAltoNetworksXDR.endpointScan.aborted | Boolean | Was the scan aborted? |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.bucket | String | The bucket in which the error occurred. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_name | String | The name of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_path | String | The path of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_size | Number | The size of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.missing_files | Unknown | The missing files that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorData | String | The error reason data. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminated_by | String | The instance ID which terminated the action and caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorDescription | String | The error reason description. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminate_result | Unknown | The error reason terminate result. |
### xdr-endpoint-scan-abort
***
Cancels the scan of selected endpoints. A scan can only be aborted if the selected endpoints are Pending or In Progress. To scan all endpoints, run the command with the argument all=true. Note that scanning all of the endpoints may cause performance issues and latency.
##### Required Permissions
Required Permissions For API call:
`Endpoint Administrations` --> `View/ Edit`
`Endpoint Administrations` --> `Endpoint Scan`
Builtin Roles with this permission includes: "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-endpoint-scan-abort`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Allows linking the response action to the incident that triggered it. | Optional |
| endpoint_id_list | List of endpoint IDs. | Optional |
| dist_name | Name of the distribution list. | Optional |
| gte_first_seen | GTE first seen timestamp in milliseconds. | Optional |
| gte_last_seen | GTE last seen timestamp in milliseconds. | Optional |
| lte_first_seen | LTE first seen timestamp in milliseconds. | Optional |
| lte_last_seen | LTE last seen timestamp in milliseconds. | Optional |
| ip_list | List of IP addresses. | Optional |
| group_name | Name of the endpoint group. | Optional |
| platform | Type of operating system. Possible values are: windows, linux, macos, android. | Optional |
| alias | Endpoint alias name. | Optional |
| isolate | Whether an endpoint has been isolated. Can be "isolated" or "unisolated". Possible values are: isolated, unisolated. | Optional |
| hostname | Name of the host. | Optional |
| all | Whether to scan all of the endpoints. Note: scanning all of the endpoints may cause performance issues and latency. Possible values are: true, false. Default is false. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.endpointScan.actionId | Unknown | The action ID of the abort scan request. |
| PaloAltoNetworksXDR.endpointScan.aborted | Boolean | Was the scan aborted? |
### get-mapping-fields
***
Gets mapping fields from remote incident. Note: This method will not update the current incident, it's here for debugging purposes.
#### Base Command
`get-mapping-fields`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
#### Context Output
There is no context output for this command.
### get-remote-data
***
Gets remote data from a remote incident. Note: This method will not update the current incident, it's here for debugging purposes.
#### Base Command
`get-remote-data`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| id | The remote incident ID. | Required |
| lastUpdate | UTC timestamp in seconds. The incident is only updated if it was modified after the last update time. Default is 0. | Optional |
#### Context Output
There is no context output for this command.
### get-modified-remote-data
***
Gets the list of incidents that were modified since the last update. Note: This method is here for debugging purposes. get-modified-remote-data is used as part of a Mirroring feature, which is available since version 6.1.
#### Base Command
`get-modified-remote-data`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| lastUpdate | Date string representing the local time.The incident is only returned if it was modified after the last update time. | Optional |
#### Context Output
There is no context output for this command.
### xdr-get-policy
***
Gets the policy name for a specific endpoint.
##### Required Permissions
Required Permissions For API call:
`Endpoint Prevention Policies` --> `View`
Builtin Roles with this permission includes: "Privileged Investigator", "Privileged Responder", "Viewer", and "Instance Admin".
#### Base Command
`xdr-get-policy`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| endpoint_id | The endpoint ID. Can be retrieved by running the xdr-get-endpoints command. | Required |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.Policy | string | The policy allocated with the endpoint. |
| PaloAltoNetworksXDR.Policy.policy_name | string | Name of the policy allocated with the endpoint. |
| PaloAltoNetworksXDR.Policy.endpoint_id | string | Endpoint ID. |
### xdr-get-scripts
***
Gets a list of scripts available in the scripts library.
##### Required Permissions
Required Permissions For API call:
`Agent Scripts library` --> `View`
`Endpoint Administrations` --> `View/ Edit`
`Endpoint Administrations` --> `Endpoint Scan`
Builtin Roles with this permission includes: "Privileged Responder", "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-scripts`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| script_name | A comma-separated list of the script names. | Optional |
| description | A comma-separated list of the script descriptions. | Optional |
| created_by | A comma-separated list of the users who created the script. | Optional |
| limit | The maximum number of scripts returned to the War Room. | Optional |
| offset | (Int) Offset in the data set. | Optional |
| windows_supported | Whether the script can be executed on a Windows operating system. Possible values are: true, false. | Optional |
| linux_supported | Whether the script can be executed on a Linux operating system. Possible values are: true, false. | Optional |
| macos_supported | Whether the script can be executed on a Mac operating system. Possible values are: true, false. | Optional |
| is_high_risk | Whether the script has a high-risk outcome. Possible values are: true, false. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.Scripts | Unknown | The scripts command results. |
| PaloAltoNetworksXDR.Scripts.script_id | Unknown | Script ID. |
| PaloAltoNetworksXDR.Scripts.name | string | Name of the script. |
| PaloAltoNetworksXDR.Scripts.description | string | Description of the script. |
| PaloAltoNetworksXDR.Scripts.modification_date | Unknown | Timestamp of when the script was last modified. |
| PaloAltoNetworksXDR.Scripts.created_by | string | Name of the user who created the script. |
| PaloAltoNetworksXDR.Scripts.windows_supported | boolean | Whether the script can be executed on a Windows operating system. |
| PaloAltoNetworksXDR.Scripts.linux_supported | boolean | Whether the script can be executed on a Linux operating system. |
| PaloAltoNetworksXDR.Scripts.macos_supported | boolean | Whether the script can be executed on Mac operating system. |
| PaloAltoNetworksXDR.Scripts.is_high_risk | boolean | Whether the script has a high-risk outcome. |
| PaloAltoNetworksXDR.Scripts.script_uid | string | Globally Unique Identifier of the script, used to identify the script when executing. |
### xdr-delete-endpoints
***
Deletes selected endpoints in the Cortex XDR app. You can delete up to 1000 endpoints.
##### Required Permissions
Required Permissions For API call:
`Endpoint Administrations` --> `View/ Edit`
Builtin Roles with this permission includes: "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-delete-endpoints`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| endpoint_ids | A comma-separated list of endpoint IDs. You can retrieve the endpoint IDs from the xdr-get-endpoints command. | Required |
#### Context Output
There is no context output for this command.
### xdr-get-endpoint-device-control-violations
***
Gets a list of device control violations filtered by selected fields. You can retrieve up to 100 violations.
##### Required Permissions
Required Permissions For API call:
`Device Control` --> `View`
Builtin Roles with this permission includes: "Privileged Investigator", "Privileged Responder", "Viewer", and "Instance Admin".
#### Base Command
`xdr-get-endpoint-device-control-violations`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| endpoint_ids | A comma-separated list of endpoint IDs. You can retrieve the endpoint IDs from the xdr-get-endpoints command. | Optional |
| type | Type of violation. Possible values are: "cd-rom", "disk drive", "floppy disk", and "portable device". Possible values are: cd-rom, disk drive, floppy disk, portable device. | Optional |
| timestamp_gte | Timestamp of the violation. Violations that are greater than or equal to this timestamp will be returned. Values can be in either ISO date format, relative time, or epoch timestamp. For example: "2019-10-21T23:45:00" (ISO date format), "3 days ago" (relative time) 1579039377301 (epoch time). | Optional |
| timestamp_lte | Timestamp of the violation. Violations that are less than or equal to this timestamp will be returned. Values can be in either ISO date format, relative time, or epoch timestamp. For example: "2019-10-21T23:45:00" (ISO date format), "3 days ago" (relative time) 1579039377301 (epoch time). | Optional |
| ip_list | A comma-separated list of IP addresses. | Optional |
| vendor | Name of the vendor. | Optional |
| vendor_id | Vendor ID. | Optional |
| product | Name of the product. | Optional |
| product_id | Product ID. | Optional |
| serial | Serial number. | Optional |
| hostname | Hostname. | Optional |
| violation_id_list | A comma-separated list of violation IDs. | Optional |
| username | Username. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.EndpointViolations | Unknown | Endpoint violations command results. |
| PaloAltoNetworksXDR.EndpointViolations.violations | Unknown | A list of violations. |
| PaloAltoNetworksXDR.EndpointViolations.violations.os_type | string | Type of the operating system. |
| PaloAltoNetworksXDR.EndpointViolations.violations.hostname | string | Host name of the violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.username | string | Username of the violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.ip | string | IP address of the violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.timestamp | number | Timestamp of the violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.violation_id | number | Violation ID. |
| PaloAltoNetworksXDR.EndpointViolations.violations.type | string | Type of violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.vendor_id | string | Vendor ID of the violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.vendor | string | Name of the vendor of the violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.product_id | string | Product ID of the violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.product | string | Name of the product of the violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.serial | string | Serial number of the violation. |
| PaloAltoNetworksXDR.EndpointViolations.violations.endpoint_id | string | Endpoint ID of the violation. |
### xdr-file-retrieve
***
Retrieves files from selected endpoints. You can retrieve up to 20 files, from no more than 10 endpoints. At least one endpoint ID and one file path are necessary in order to run the command. After running this command, you can use the xdr-action-status-get command with returned action_id, to check the action status.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View/ Edit`
`Action Center` --> `File Retrieval`
Builtin Roles with this permission includes: "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-file-retrieve`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Allows to link the response action to the incident that triggered it. | Optional |
| endpoint_ids | A comma-separated list of endpoint IDs. | Required |
| windows_file_paths | A comma-separated list of file paths on the Windows platform. | Optional |
| linux_file_paths | A comma-separated list of file paths on the Linux platform. | Optional |
| mac_file_paths | A comma-separated list of file paths on the Mac platform. | Optional |
| generic_file_path | A comma-separated list of file paths in any platform. Can be used instead of the mac/windows/linux file paths. The order of the files path list must be parallel to the endpoints list order, so the first file path in the list is related to the first endpoint and so on. | Optional |
| paths_separator | The delimiter used to separate multiple file paths. Set to a different character (for example, ";") when a file path contains a comma. Default is ,. | Optional |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | The action IDs for polling use. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.RetrievedFiles.action_id | string | ID of the action to retrieve files from selected endpoints. |
| PaloAltoNetworksXDR.RetrievedFiles.endpoint_id | string | Endpoint ID. Added only when the operation is successful. |
| PaloAltoNetworksXDR.RetrievedFiles.file_link | string | Link to the file. Added only when the operation is successful. |
| PaloAltoNetworksXDR.RetrievedFiles.status | string | The action status. Added only when the operation is unsuccessful. |
| PaloAltoNetworksXDR.RetrievedFiles.ErrorReasons.bucket | String | The bucket in which the error occurred. |
| PaloAltoNetworksXDR.RetrievedFiles.ErrorReasons.file_name | String | The name of the file that caused the error. |
| PaloAltoNetworksXDR.RetrievedFiles.ErrorReasons.file_path | String | The path of the file that caused the error. |
| PaloAltoNetworksXDR.RetrievedFiles.ErrorReasons.file_size | Number | The size of the file that caused the error. |
| PaloAltoNetworksXDR.RetrievedFiles.ErrorReasons.missing_files | Unknown | The missing files that caused the error. |
| PaloAltoNetworksXDR.RetrievedFiles.ErrorReasons.errorData | String | The error reason data. |
| PaloAltoNetworksXDR.RetrievedFiles.ErrorReasons.terminated_by | String | The instance ID which terminated the action and caused the error. |
| PaloAltoNetworksXDR.RetrievedFiles.ErrorReasons.errorDescription | String | The error reason description. |
| PaloAltoNetworksXDR.RetrievedFiles.ErrorReasons.terminate_result | Unknown | The error reason terminate result. |
### xdr-retrieve-file-details
***
View the file retrieved by the xdr-retrieve-files command according to the action ID. Before running this command, you can use the xdr-action-status-get command to check if this action completed successfully.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View/ Edit`
`Action Center` --> `File Retrieval`
Builtin Roles with this permission includes: "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-retrieve-file-details`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| action_id | Action ID retrieved from the xdr-retrieve-files command. | Required |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| File | Unknown | The file details command results. |
| File.Name | String | The full file name \(including the file extension\). |
| File.EntryID | String | The ID for locating the file in the War Room. |
| File.Size | Number | The size of the file in bytes. |
| File.MD5 | String | The MD5 hash of the file. |
| File.SHA1 | String | The SHA1 hash of the file. |
| File.SHA256 | String | The SHA256 hash of the file. |
| File.SHA512 | String | The SHA512 hash of the file. |
| File.Extension | String | The file extension. For example: "xls". |
| File.Type | String | The file type, as determined by libmagic \(same as displayed in file entries\). |
### xdr-get-script-metadata
***
Gets the full definition of a specific script in the scripts library.
##### Required Permissions
Required Permissions For API call:
`Agent Scripts library` --> `View`
Builtin Roles with this permission includes: "Privileged Responder", "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-script-metadata`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| script_uid | Unique identifier of the script, returned by the xdr-get-scripts command. | Required |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptMetadata | Unknown | The script metadata command results. |
| PaloAltoNetworksXDR.ScriptMetadata.script_id | number | Script ID. |
| PaloAltoNetworksXDR.ScriptMetadata.name | string | Script name. |
| PaloAltoNetworksXDR.ScriptMetadata.description | string | Script description. |
| PaloAltoNetworksXDR.ScriptMetadata.modification_date | unknown | Timestamp of when the script was last modified. |
| PaloAltoNetworksXDR.ScriptMetadata.created_by | string | Name of the user who created the script. |
| PaloAltoNetworksXDR.ScriptMetadata.is_high_risk | boolean | Whether the script has a high-risk outcome. |
| PaloAltoNetworksXDR.ScriptMetadata.windows_supported | boolean | Whether the script can be executed on a Windows operating system. |
| PaloAltoNetworksXDR.ScriptMetadata.linux_supported | boolean | Whether the script can be executed on a Linux operating system. |
| PaloAltoNetworksXDR.ScriptMetadata.macos_supported | boolean | Whether the script can be executed on a Mac operating system. |
| PaloAltoNetworksXDR.ScriptMetadata.entry_point | string | Name of the entry point selected for the script. An empty string indicates the script defined as just run. |
| PaloAltoNetworksXDR.ScriptMetadata.script_input | string | Name and type for the specified entry point. |
| PaloAltoNetworksXDR.ScriptMetadata.script_output_type | string | Type of the output. |
| PaloAltoNetworksXDR.ScriptMetadata.script_output_dictionary_definitions | Unknown | If the script_output_type is a dictionary, an array with friendly name, name, and type for each output. |
### xdr-get-script-code
***
Gets the code of a specific script in the script library.
##### Required Permissions
Required Permissions For API call:
`Agent Scripts library` --> `View`
Builtin Roles with this permission includes: "Privileged Responder", "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-script-code`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| script_uid | Unique identifier of the script, returned by the xdr-get-scripts command. | Required |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptCode | Unknown | The script code command results. |
| PaloAltoNetworksXDR.ScriptCode.code | string | The code of a specific script in the script library. |
| PaloAltoNetworksXDR.ScriptCode.script_uid | string | Unique identifier of the script. |
### xdr-action-status-get
***
Retrieves the status of the requested actions according to the action ID.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View`
Builtin Roles with this permission includes: "Responder", "Privileged Investigator", "Privileged Responder", "Viewer", and "Instance Admin".
#### Base Command
`xdr-action-status-get`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| action_id | The action ID of the selected request. After performing an action, you will receive an action ID. | Required |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.GetActionStatus | Unknown | The action status command results. |
| PaloAltoNetworksXDR.GetActionStatus.endpoint_id | string | Endpoint ID. |
| PaloAltoNetworksXDR.GetActionStatus.status | string | The status of the specific endpoint ID. |
| PaloAltoNetworksXDR.GetActionStatus.action_id | number | The specified action ID. |
### xdr-run-script
***
Deprecated. Use the `xdr-script-run` command instead. Initiates a new endpoint script execution action using a script from the script library.
#### Base Command
`xdr-run-script`
#### 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 xdr-get-endpoints command. | Required |
| script_uid | Unique identifier of the script. Can be retrieved by running the xdr-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 |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptRun.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptRun.endpoints_count | Number | Number of endpoints the action was initiated on. |
### xdr-snippet-code-script-execute
***
Initiates a new endpoint script execution action using the provided snippet code.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View`
Builtin Roles with this permission includes: "Responder", "Privileged Investigator", "Privileged Responder", "Viewer", and "Instance Admin".
#### Base Command
`xdr-snippet-code-script-execute`
#### 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 xdr-get-endpoints command. | Required |
| snippet_code | Section of a script to initiate on an endpoint (e.g., print("7")). | Required |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | Action IDs for polling use. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptRun.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptRun.endpoints_count | Number | Number of endpoints the action was initiated on. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.bucket | String | The bucket in which the error occurred. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_name | String | The name of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_path | String | The path of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_size | Number | The size of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.missing_files | Unknown | The missing files that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorData | String | The error reason data. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminated_by | String | The instance ID which terminated the action and caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorDescription | String | The error reason description. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminate_result | Unknown | The error reason terminate result. |
### xdr-get-script-execution-status
***
Retrieves the status of a script execution action.
##### Required Permissions
Required Permissions For API call:
`Agent Scripts library` --> `View`
Builtin Roles with this permission includes: "Privileged Responder", "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-script-execution-status`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| action_id | Action IDs retrieved from the xdr-run-script command. | Required |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptStatus.general_status | String | General status of the action, considering the status of all the endpoints. |
| PaloAltoNetworksXDR.ScriptStatus.error_message | String | Error message regarding permissions for running APIs or the action doesn’t exist. |
| PaloAltoNetworksXDR.ScriptStatus.endpoints_timeout | Number | Number of endpoints in "timeout" status. |
| PaloAltoNetworksXDR.ScriptStatus.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptStatus.endpoints_pending_abort | Number | Number of endpoints in "pending abort" status. |
| PaloAltoNetworksXDR.ScriptStatus.endpoints_pending | Number | Number of endpoints in "pending" status. |
| PaloAltoNetworksXDR.ScriptStatus.endpoints_in_progress | Number | Number of endpoints in "in progress" status. |
| PaloAltoNetworksXDR.ScriptStatus.endpoints_failed | Number | Number of endpoints in "failed" status. |
| PaloAltoNetworksXDR.ScriptStatus.endpoints_expired | Number | Number of endpoints in "expired" status. |
| PaloAltoNetworksXDR.ScriptStatus.endpoints_completed_successfully | Number | Number of endpoints in "completed successfully" status. |
| PaloAltoNetworksXDR.ScriptStatus.endpoints_canceled | Number | Number of endpoints in "canceled" status. |
| PaloAltoNetworksXDR.ScriptStatus.endpoints_aborted | Number | Number of endpoints in "aborted" status. |
### xdr-get-script-execution-results
***
Retrieve the results of a script execution action.
##### Required Permissions
Required Permissions For API call:
`Agent Scripts library` --> `View`
Builtin Roles with this permission includes: "Privileged Responder", "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-script-execution-results`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| action_id | Action IDs retrieved from the xdr-run-script command. | Required |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptResult.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptResult.results.retrieved_files | Number | Number of successfully retrieved files. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_ip_address | String | Endpoint IP address. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_name | String | Name of successfully retrieved files. |
| PaloAltoNetworksXDR.ScriptResult.results.failed_files | Number | Number of files failed to retrieve. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_status | String | Endpoint status. |
| PaloAltoNetworksXDR.ScriptResult.results.domain | String | Domain to which the endpoint belongs. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_id | String | Endpoint ID. |
| PaloAltoNetworksXDR.ScriptResult.results.execution_status | String | Execution status of this endpoint. |
| PaloAltoNetworksXDR.ScriptResult.results.return_value | String | Value returned by the script in case the type is not a dictionary. |
| PaloAltoNetworksXDR.ScriptResult.results.standard_output | String | The STDOUT and the STDERR logged by the script during the execution. |
| PaloAltoNetworksXDR.ScriptResult.results.retention_date | Date | Timestamp in which the retrieved files will be deleted from the server. |
### xdr-get-script-execution-result-files
***
Gets the files retrieved from a specific endpoint during a script execution.
##### Required Permissions
Required Permissions For API call:
`Agent Scripts library` --> `View`
Builtin Roles with this permission includes: "Privileged Responder", "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-script-execution-result-files`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| action_id | Action ID retrieved from the xdr-run-script command. | Required |
| endpoint_id | Endpoint ID. Can be retrieved by running the xdr-get-endpoints command. | Required |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| File.Size | String | The size of the file. |
| File.SHA1 | String | The SHA1 hash of the file. |
| File.SHA256 | String | The SHA256 hash of the file. |
| File.SHA512 | String | The SHA512 hash of the file. |
| File.Name | String | The name of the file. |
| File.SSDeep | String | The SSDeep hash of the file. |
| File.EntryID | String | EntryID of the file |
| File.Info | String | Information about the file. |
| File.Type | String | The file type. |
| File.MD5 | String | The MD5 hash of the file. |
| File.Extension | String | The extension of the file. |
### xdr-script-commands-execute
***
Initiates a new endpoint script execution of shell commands.
#### Base Command
`xdr-script-commands-execute`
#### 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 xdr-get-endpoints command. | Required |
| commands | A comma-separated list of shell commands to execute. Set the `is_raw_command` argument to `true` to prevent splitting by commas. (Useful when using `\|\|`, `&&`, `;` separators for controlling the flow of multiple commands). | Required |
| is_raw_command | Whether to pass the command as-is. When false, the command is split by commas and sent as a list of commands, that are run independently. | Optional |
| command_type | Type of shell command. Possible values are: powershell, native. | Optional |
| timeout | The timeout in seconds for this execution. Default is 600. | Optional |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | The action IDs for polling use. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptRun.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptRun.endpoints_count | Number | Number of endpoints the action was initiated on. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.bucket | String | The bucket in which the error occurred. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_name | String | The name of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_path | String | The path of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_size | Number | The size of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.missing_files | Unknown | The missing files that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorData | String | The error reason data. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminated_by | String | The instance ID which terminated the action and caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorDescription | String | The error reason description. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminate_result | Unknown | The error reason terminate result. |
### xdr-file-delete-script-execute
***
Initiates a new endpoint script execution to delete the specified file.
#### Base Command
`xdr-file-delete-script-execute`
#### 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 xdr-get-endpoints command. | Required |
| file_path | A comma-separated list of paths of the files to delete. All of the given file paths will run on all of the endpoints. | Required |
| timeout | The timeout in seconds for this execution. Default is 600. | Optional |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | The action IDs for polling use. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptRun.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptRun.endpoints_count | Number | Number of endpoints the action was initiated on. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.bucket | String | The bucket in which the error occurred. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_name | String | The name of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_path | String | The path of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_size | Number | The size of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.missing_files | Unknown | The missing files that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorData | String | The error reason data. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminated_by | String | The instance ID which terminated the action and caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorDescription | String | The error reason description. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminate_result | Unknown | The error reason terminate result. |
### xdr-file-exist-script-execute
***
Initiates a new endpoint script execution to check if the file exists.
#### Base Command
`xdr-file-exist-script-execute`
#### 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 xdr-get-endpoints command. | Required |
| file_path | A comma-separated list of paths of the files to check for existence. All of the given file paths will run on all of the endpoints. | Required |
| timeout | The timeout in seconds for this execution. Default is 600. | Optional |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | The action IDs for polling use. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptRun.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptRun.endpoints_count | Number | Number of endpoints the action was initiated on. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.bucket | String | The bucket in which the error occurred. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_name | String | The name of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_path | String | The path of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_size | Number | The size of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.missing_files | Unknown | The missing files that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorData | String | The error reason data. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminated_by | String | The instance ID which terminated the action and caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorDescription | String | The error reason description. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminate_result | Unknown | The error reason terminate result. |
### xdr-kill-process-script-execute
***
Initiates a new endpoint script execution kill process.
#### Base Command
`xdr-kill-process-script-execute`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Allows to link 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 xdr-get-endpoints command. | Required |
| process_name | Names of processes to kill. Will kill all of the given processes on all of the endpoints. | Required |
| timeout | The timeout in seconds for this execution. Default is 600. | Optional |
| interval_in_seconds | Interval in seconds between each poll. | Optional |
| timeout_in_seconds | Polling timeout in seconds. | Optional |
| action_id | The action IDs for polling use. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.ScriptRun.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptRun.endpoints_count | Number | Number of endpoints the action was initiated on. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.bucket | String | The bucket in which the error occurred. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_name | String | The name of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_path | String | The path of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.file_size | Number | The size of the file that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.missing_files | Unknown | The missing files that caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorData | String | The error reason data. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminated_by | String | The instance ID which terminated the action and caused the error. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.errorDescription | String | The error reason description. |
| PaloAltoNetworksXDR.GetActionStatus.ErrorReasons.terminate_result | Unknown | The error reason terminate result. |
### endpoint
***
Returns information about an endpoint.
##### Required Permissions
Required Permissions For API call:
`Endpoint Administrations` --> `View`
Builtin Roles with this permission includes: "Privileged Responder", "Viewer" and "Instance Admin".
#### Base Command
`endpoint`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| id | The endpoint ID. | Optional |
| ip | The endpoint IP address. | Optional |
| hostname | The endpoint host name. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Endpoint.Hostname | String | The endpoint hostname. |
| Endpoint.OS | String | The endpoint operation system. |
| Endpoint.IPAddress | String | The endpoint IP address. |
| Endpoint.ID | String | The endpoint ID. |
| Endpoint.Status | String | The endpoint status. |
| Endpoint.IsIsolated | String | The endpoint isolation status. |
| Endpoint.MACAddress | String | The endpoint MAC address. |
| Endpoint.Vendor | String | The integration name of the endpoint vendor. |
### xdr-get-endpoints-by-status
***
Returns the number of the connected\disconnected endpoints.
##### Required Permissions
Required Permissions For API call:
`Endpoint Administrations` --> `View`
Builtin Roles with this permission includes: "Privileged Responder", "Viewer" and "Instance Admin".
#### Base Command
`xdr-get-endpoints-by-status`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| status | The status of the endpoint to filter. Possible values are: connected, disconnected, lost, uninstalled. | Required |
| last_seen_gte | All the agents that were last seen before {last_seen_gte}. Supported<br/> values: 1579039377301 (time in milliseconds) "3 days" (relative date) "2019-10-21T23:45:00"<br/> (date). | Optional |
| last_seen_lte | All the agents that were last seen before {last_seen_lte}. Supported<br/> values: 1579039377301 (time in milliseconds) "3 days" (relative date) "2019-10-21T23:45:00"<br/> (date). | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.EndpointsStatus.status | String | The endpoint status. |
| PaloAltoNetworksXDR.EndpointsStatus.count | Number | The number of endpoints with this status. |
### xdr-get-cloud-original-alerts (Deprecated)
***
This command is deprecated. Returns information about each alert ID.
##### Required Permissions
Required Permissions For API call:
`Alerts & Incidents` --> `View`
Builtin Roles with this permission includes: "Investigator", "Responder", "Privileged Investigator", "Privileged Responder", "Viewer", and "Instance Admin".
#### Base Command
`xdr-get-cloud-original-alerts`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_ids | A comma-separated list of alert IDs. | Required |
| events_from_decider_format | Whether to return events_from_decider context output as a dictionary (the raw API response) or as a list (improved for playbook automation) - relevant only when filter_alert_fields is set to False. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.OriginalAlert.event._time | String | The timestamp of the occurrence of the event. |
| PaloAltoNetworksXDR.OriginalAlert.event.vendor | String | Vendor name. |
| PaloAltoNetworksXDR.OriginalAlert.event.event_timestamp | Number | Event timestamp. |
| PaloAltoNetworksXDR.OriginalAlert.event.event_type | Number | Event type \(static 500\). |
| PaloAltoNetworksXDR.OriginalAlert.event.cloud_provider | String | The cloud provider - GCP, AZURE, or AWS. |
| PaloAltoNetworksXDR.OriginalAlert.event.project | String | The project in which the event occurred. |
| PaloAltoNetworksXDR.OriginalAlert.event.cloud_provider_event_id | String | The ID given to the event by the cloud provider, if the ID exists. |
| PaloAltoNetworksXDR.OriginalAlert.event.cloud_correlation_id | String | The ID the cloud provider is using to aggregate events that are part of the same general event. |
| PaloAltoNetworksXDR.OriginalAlert.event.operation_name_orig | String | The name of the operation that occurred, as supplied by the cloud provider. |
| PaloAltoNetworksXDR.OriginalAlert.event.operation_name | String | The normalized name of the operation performed by the event. |
| PaloAltoNetworksXDR.OriginalAlert.event.identity_orig | String | Contains the original identity related fields as provided by the cloud provider. |
| PaloAltoNetworksXDR.OriginalAlert.event.identity_name | String | The name of the identity that initiated the action. |
| PaloAltoNetworksXDR.OriginalAlert.event.identity_uuid | String | Same as identity_name but also contains the UUID of the identity if it exists. |
| PaloAltoNetworksXDR.OriginalAlert.event.identity_type | String | An enum representing the type of the identity. |
| PaloAltoNetworksXDR.OriginalAlert.event.identity_sub_type | String | An enum representing the sub-type of the identity, respective to its identity_type. |
| PaloAltoNetworksXDR.OriginalAlert.event.identity_invoked_by_name | String | The name of the identity that invoked the action as it appears in the log. |
| PaloAltoNetworksXDR.OriginalAlert.event.identity_invoked_by_uuid | String | The UUID of the identity that invoked the action as it appears in the log. |
| PaloAltoNetworksXDR.OriginalAlert.event.identity_invoked_by_type | String | An enum that represents the type of identity event that invoked the action. |
| PaloAltoNetworksXDR.OriginalAlert.event.identity_invoked_by_sub_type | String | An enum that represents the respective sub_type of the type of identity \(identity_type\) that has invoked the action. |
| PaloAltoNetworksXDR.OriginalAlert.event.operation_status | String | Status of whether the operation has succeed or failed, if provided. |
| PaloAltoNetworksXDR.OriginalAlert.event.operation_status_orig | String | The operation status code as it appears in the log, including lookup from code number to code name. |
| PaloAltoNetworksXDR.OriginalAlert.event.operation_status_orig_code | String | The operation status code as it appears in the log. |
| PaloAltoNetworksXDR.OriginalAlert.event.operation_status_reason_provided | String | Description of the error, if the log record indicates an error and the cloud provider supplied the reason. |
| PaloAltoNetworksXDR.OriginalAlert.event.resource_type | String | The normalized type of the service that emitted the log row. |
| PaloAltoNetworksXDR.OriginalAlert.event.resource_type_orig | String | The type of the service that omitted the log as provided by the cloud provider. |
| PaloAltoNetworksXDR.OriginalAlert.event.resource_sub_type | String | The sub-type respective to the resource_type field, normalized across all cloud providers. |
| PaloAltoNetworksXDR.OriginalAlert.event.resource_sub_type_orig | String | The sub-type of the service that emitted this log row as provided by the cloud provider. |
| PaloAltoNetworksXDR.OriginalAlert.event.region | String | The cloud region of the resource that emitted the log. |
| PaloAltoNetworksXDR.OriginalAlert.event.zone | String | The availability zone of the resource that emitted the log. |
| PaloAltoNetworksXDR.OriginalAlert.event.referenced_resource | String | The cloud resource referenced in the audit log. |
| PaloAltoNetworksXDR.OriginalAlert.event.referenced_resource_name | String | Same as referenced_resource but provides only the substring that represents the resource name instead of the full asset ID. |
| PaloAltoNetworksXDR.OriginalAlert.event.referenced_resources_count | Number | The number of extracted resources referenced in this audit log. |
| PaloAltoNetworksXDR.OriginalAlert.event.user_agent | String | The user agent provided in the call to the API of the cloud provider. |
| PaloAltoNetworksXDR.OriginalAlert.event.caller_ip | String | The IP of the caller that performed the action in the log. |
| PaloAltoNetworksXDR.OriginalAlert.event.caller_ip_geolocation | String | The geolocation associated with the caller_ip's value. |
| PaloAltoNetworksXDR.OriginalAlert.event.caller_ip_asn | Number | The ASN of the caller_ip's value. |
| PaloAltoNetworksXDR.OriginalAlert.event.caller_project | String | The project of the caller entity. |
| PaloAltoNetworksXDR.OriginalAlert.event.raw_log | Unknown | The raw log that is being normalized. |
| PaloAltoNetworksXDR.OriginalAlert.event.log_name | String | The name of the log that contains the log row. |
| PaloAltoNetworksXDR.OriginalAlert.event.caller_ip_asn_org | String | The organization associated with the ASN of the caller_ip's value. |
| PaloAltoNetworksXDR.OriginalAlert.event.event_base_id | String | Event base ID. |
| PaloAltoNetworksXDR.OriginalAlert.event.ingestion_time | String | Ingestion time. |
### xdr-remove-allowlist-files
***
Removes requested files from allow list.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View/ Edit`
`Action Center` --> `Allow List/Block List`
Builtin Roles with this permission includes: "Responder", "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-remove-allowlist-files`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Links the response action to the incident that triggered it. | Optional |
| hash_list | String that represents a list of hashed files you want to add to allow list. Must be a valid SHA256 hash. | Required |
| comment | String that represents additional information regarding the action. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.allowlist.removed_hashes | Number | Removed file hash |
### xdr-remove-blocklist-files
***
Removes requested files from block list.
##### Required Permissions
Required Permissions For API call:
`Action Center` --> `View/ Edit`
`Action Center` --> `Allow List/Block List`
Builtin Roles with this permission includes: "Responder", "Privileged Responder" and "Instance Admin".
#### Base Command
`xdr-remove-blocklist-files`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| incident_id | Links the response action to the incident that triggered it. | Optional |
| hash_list | String that represents a list of hashed files you want to add to allow list. Must be a valid SHA256 hash. | Required |
| comment | String that represents additional information regarding the action. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.blocklist.removed_hashes | Number | Removed fileHash from blocklist |
There is no context output for this command.
### xdr-get-alerts (Deprecated)
***
This command is deprecated, please use xdr-issue-list instead. Returns a list of alerts and their metadata, which you can filter by built-in arguments or use the custom_filter to input a JSON filter object.
Multiple filter arguments will be concatenated using the AND operator, while arguments that support a comma-separated list of values will use an OR operator between each value.
##### Required Permissions
Required Permissions For API call:
`Alerts & Incidents` --> `View`
Builtin Roles with this permission includes: "Investigator", "Responder", "Privileged Investigator", "Privileged Responder", "Viewer", and "Instance Admin".
#### Base Command
`xdr-get-alerts`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | The unique ID of the alert. | Optional |
| severity | The severity of the alert. Possible values are: low, medium, high. | Optional |
| custom_filter | a custom filter, when using this argument, other filter arguments are not relevant. example: <br/>`{<br/> "OR": [<br/> {<br/> "SEARCH_FIELD": "actor_process_command_line",<br/> "SEARCH_TYPE": "EQ",<br/> "SEARCH_VALUE": "path_to_file"<br/> }<br/> ]<br/> }`. | Optional |
| Identity_type | Account type. Possible values are: ANONYMOUS, APPLICATION, COMPUTE, FEDERATED_IDENTITY, SERVICE, SERVICE_ACCOUNT, TEMPORARY_CREDENTIALS, TOKEN, UNKNOWN, USER. | Optional |
| agent_id | A unique identifier per agent. | Optional |
| action_external_hostname | The host name to connect to. In case of a proxy connection, this value will differ from action_remote_ip. | Optional |
| rule_id | A string identifying the user rule. | Optional |
| rule_name | The name of the user rule. | Optional |
| alert_name | The alert name. | Optional |
| alert_source | The alert source. | Optional |
| time_frame | Supports relative times or “custom” time option. If you choose the "custom" option, you should use start_time and end_time arguments. Possible values are: 60 minutes, 3 hours, 12 hours, 24 hours, 2 days, 7 days, 14 days, 30 days, custom. | Optional |
| user_name | The name assigned to the user_id during agent runtime. | Optional |
| actor_process_image_name | The file name of the binary file. | Optional |
| causality_actor_process_image_command_line | CGO CMD. | Optional |
| actor_process_image_command_line | Trimmed to 128 unicode chars during event serialization.<br/>Full value reported as part of the original process event. | Optional |
| action_process_image_command_line | The command line of the process created. | Optional |
| actor_process_image_sha256 | SHA256 of the binary file. | Optional |
| causality_actor_process_image_sha256 | SHA256 of the binary file. | Optional |
| action_process_image_sha256 | SHA256 of the binary file. | Optional |
| action_file_image_sha256 | SHA256 of the file related to the event. | Optional |
| action_registry_name | The name of the registry. | Optional |
| action_registry_key_data | The key data of the registry. | Optional |
| host_ip | The host IP. | Optional |
| action_local_ip | The local IP address for the connection. | Optional |
| action_remote_ip | Remote IP address for the connection. | Optional |
| alert_action_status | Alert action status. Possible values are: detected, detected (allowed the session), detected (download), detected (forward), detected (post detected), detected (prompt allow), detected (raised an alert), detected (reported), detected (on write), detected (scanned), detected (sinkhole), detected (syncookie sent), detected (wildfire upload failure), detected (wildfire upload success), detected (wildfire upload skip), detected (xdr managed threat hunting), prevented (block), prevented (blocked), prevented (block-override), prevented (blocked the url), prevented (blocked the ip), prevented (continue), prevented (denied the session), prevented (dropped all packets), prevented (dropped the session), prevented (dropped the session and sent a tcp reset), prevented (dropped the packet), prevented (override), prevented (override-lockout), prevented (post detected), prevented (prompt block), prevented (random-drop), prevented (silently dropped the session with an icmp unreachable message to the host or application), prevented (terminated the session and sent a tcp reset to both sides of the connection), prevented (terminated the session and sent a tcp reset to the client), prevented (terminated the session and sent a tcp reset to the server), prevented (on write). | Optional |
| action_local_port | The local IP address for the connection. | Optional |
| action_remote_port | The remote port for the connection. | Optional |
| dst_action_external_hostname | The hostname we connect to. In case of a proxy connection, this value will differ from action_remote_ip. | Optional |
| sort_field | The field by which we sort the results. Default is source_insert_ts. | Optional |
| sort_order | The order in which we sort the results. Possible values are: DESC, ASC. | Optional |
| offset | The first page from which we bring the alerts. Default is 0. | Optional |
| limit | The last page from which we bring the alerts. Default is 50. | Optional |
| start_time | Relevant when "time_frame" argument is "custom". Supports Epoch timestamp and simplified extended ISO format (YYYY-MM-DDThh:mm:ss). | Optional |
| end_time | Relevant when "time_frame" argument is "custom". Supports Epoch timestamp and simplified extended ISO format (YYYY-MM-DDThh:mm:ss). | Optional |
| starred | Whether the alert is starred or not. Possible values are: true, false. | Optional |
| mitre_technique_id_and_name | The MITRE attack technique. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| PaloAltoNetworksXDR.Alert.internal_id | String | The unique ID of the alert. |
| PaloAltoNetworksXDR.Alert.source_insert_ts | Number | The detection timestamp |
| PaloAltoNetworksXDR.Alert.alert_name | String | The name of the alert. |
| PaloAltoNetworksXDR.Alert.severity | String | The severity of the alert. |
| PaloAltoNetworksXDR.Alert.alert_category | String | The category of the alert. |
| PaloAltoNetworksXDR.Alert.alert_action_status | String | The alert action. Possible values.
DETECTED: detected
DETECTED_0: detected \(allowed the session\)
DOWNLOAD: detected \(download\)
DETECTED_19: detected \(forward\)
POST_DETECTED: detected \(post detected\)
PROMPT_ALLOW: detected \(prompt allow\)
DETECTED_4: detected \(raised an alert\)
REPORTED: detected \(reported\)
REPORTED_TRIGGER_4: detected \(on write\)
SCANNED: detected \(scanned\)
DETECTED_23: detected \(sinkhole\)
DETECTED_18: detected \(syncookie sent\)
DETECTED_21: detected \(wildfire upload failure\)
DETECTED_20: detected \(wildfire upload success\)
DETECTED_22: detected \(wildfire upload skip\)
DETECTED_MTH: detected \(xdr managed threat hunting\)
BLOCKED_25: prevented \(block\)
BLOCKED: prevented \(blocked\)
BLOCKED_14: prevented \(block-override\)
BLOCKED_5: prevented \(blocked the url\)
BLOCKED_6: prevented \(blocked the ip\)
BLOCKED_13: prevented \(continue\)
BLOCKED_1: prevented \(denied the session\)
BLOCKED_8: prevented \(dropped all packets\)
BLOCKED_2: prevented \(dropped the session\)
BLOCKED_3: prevented \(dropped the session and sent a tcp reset\)
BLOCKED_7: prevented \(dropped the packet\)
BLOCKED_16: prevented \(override\)
BLOCKED_15: prevented \(override-lockout\)
BLOCKED_26: prevented \(post detected\)
PROMPT_BLOCK: prevented \(prompt block\)
BLOCKED_17: prevented \(random-drop\)
BLOCKED_24: prevented \(silently dropped the session with an icmp unreachable message to the host or application\)
BLOCKED_9: prevented \(terminated the session and sent a tcp reset to both sides of the connection\)
BLOCKED_10: prevented \(terminated the session and sent a tcp reset to the client\)
BLOCKED_11: prevented \(terminated the session and sent a tcp reset to the server\)
BLOCKED_TRIGGER_4: prevented \(on write\)
|
| PaloAltoNetworksXDR.Alert.alert_action_status_readable | String | The alert action. |
| PaloAltoNetworksXDR.Alert.alert_name | String | The alert name. |
| PaloAltoNetworksXDR.Alert.alert_description | String | The alert description. |
| PaloAltoNetworksXDR.Alert.agent_ip_addresses | String | The host IP. |
| PaloAltoNetworksXDR.Alert.agent_hostname | String | The host name. |
| PaloAltoNetworksXDR.Alert.mitre_tactic_id_and_name | String | The MITRE attack tactic. |
| PaloAltoNetworksXDR.Alert.mitre_technique_id_and_name | String | The MITRE attack technique. |
| PaloAltoNetworksXDR.Alert.starred | Boolean | Whether the alert is starred or not. |
#### Command example
```!xdr-get-alerts severity="high" alert_action_status="detected (reported)" sort_field="source_insert_ts" offset="0" limit="1"```
#### Context Example
```json
{
"PaloAltoNetworksXDR": {
"Alert": {
"action_country": [
"UNKNOWN"
],
"action_external_hostname": null,
"action_file_macro_sha256": null,
"action_file_md5": null,
"action_file_name": null,
"action_file_path": null,
"action_file_sha256": null,
"action_local_ip": null,
"action_local_ip_v6": null,
"action_local_port": null,
"action_process_causality_id": null,
"action_process_image_command_line": null,
"action_process_image_md5": [
"ddcd2be64212b10c3cf84496a879b098"
],
"action_process_image_name": null,
"action_process_image_path": [
"C:\Users\administrator\Downloads\svchost.exe"
],
"action_process_image_sha256": null,
"action_process_instance_id": null,
"action_process_os_pid": [
5172
],
"action_process_signature_status": [
"SIGNATURE_UNAVAILABLE"
],
"action_process_signature_vendor": null,
"action_process_user_sid": null,
"action_registry_data": null,
"action_registry_full_key": null,
"action_registry_key_name": null,
"action_registry_value_name": null,
"action_remote_ip": null,
"action_remote_ip_v6": null,
"action_remote_port": null,
"activity_first_seen_at": null,
"activity_last_seen_at": null,
"actor_causality_id": null,
"actor_effective_user_sid": null,
"actor_effective_username": [
"env1.local\administrator"
],
"actor_process_causality_id": [
"AdhDcc/XHpAAABQ0AAAAAA=="
],
"actor_process_command_line": [
"\"C:\Users\administrator\Downloads\svchost.exe\" "
],
"actor_process_execution_time": [
1648560911622
],
"actor_process_image_md5": [
"ddcd2be64212b10c3cf84496a879b098"
],
"actor_process_image_name": [
"svchost.exe"
],
"actor_process_image_path": [
"C:\Users\administrator\Downloads\svchost.exe"
],
"actor_process_image_sha256": [
"b013074d220d71877112b61e16927abbbb98ad29aa40609aca1b936332fbe4b7"
],
"actor_process_instance_id": [
"AdhDcc/XHpAAABQ0AAAAAA=="
],
"actor_process_os_pid": [
5172
],
"actor_process_signature_status": [
"SIGNATURE_UNSIGNED"
],
"actor_process_signature_vendor": null,
"actor_thread_thread_id": [
2468
],
"agent_data_collection_status": true,
"agent_device_domain": "env1.local",
"agent_fqdn": "DC1ENV1APC02.env1.local",
"agent_host_boot_time": [
0
],
"agent_hostname": "DC1ENV1APC02",
"agent_id": "63f88a9e797440ccac742a6adc926fb2",
"agent_install_type": "STANDARD",
"agent_ip_addresses": [
"10.111.230.11"
],
"agent_ip_addresses_v6": null,
"agent_is_vdi": null,
"agent_os_sub_type": "10.0.10240",
"agent_os_type": "AGENT_OS_WINDOWS",
"agent_version": "7.6.1.46600",
"alert_action_status": "REPORTED",
"alert_action_status_readable": "detected (reported)",
"alert_category": "Malware",
"alert_description": "Behavioral threat detected (rule: bioc.masquerade_svchost)",
"alert_description_raw": "Behavioral threat detected (rule: bioc.masquerade_svchost)",
"alert_is_fp": false,
"alert_name": "Behavioral Threat",
"alert_source": "TRAPS",
"alert_sub_type": null,
"alert_type": "Unclassified",
"association_strength": [
50
],
"attack_techniques": null,
"attempt_counter": 0,
"audit_ids": null,
"bioc_category_enum_key": null,
"bioc_indicator": null,
"caller_ip": null,
"case_id": 48,
"causality_actor_causality_id": [
"AdhDcc/XHpAAABQ0AAAAAA=="
],
"causality_actor_process_command_line": [
"\"C:\Users\administrator\Downloads\svchost.exe\" "
],
"causality_actor_process_execution_time": [
1648560911622
],
"causality_actor_process_image_md5": null,
"causality_actor_process_image_name": [
"svchost.exe"
],
"causality_actor_process_image_path": [
"C:\Users\administrator\Downloads\svchost.exe"
],
"causality_actor_process_image_sha256": [
"b013074d220d71877112b61e16927abbbb98ad29aa40609aca1b936332fbe4b7"
],
"causality_actor_process_instance_id": [
"AdhDcc/XHpAAABQ0AAAAAA=="
],
"causality_actor_process_os_pid": [
5172
],
"causality_actor_process_signature_status": [
"SIGNATURE_UNSIGNED"
],
"causality_actor_process_signature_vendor": null,
"cloud_provider": null,
"cluster_name": null,
"container_id": null,
"contains_featured_host": [
"NO"
],
"contains_featured_ip": [
"NO"
],
"contains_featured_user": [
"NO"
],
"deduplicate_tokens": null,
"detection_modules": null,
"dns_query_name": null,
"drilldown_max_ts": null,
"drilldown_min_ts": null,
"drilldown_query": null,
"dss_country": null,
"dss_department": null,
"dss_groups": null,
"dss_job_title": null,
"dst_action_country": null,
"dst_action_external_hostname": null,
"dst_action_external_port": null,
"dst_actor_process_image_name": null,
"dst_actor_process_os_pid": null,
"dst_agent_hostname": null,
"dst_agent_id": null,
"dst_agent_os_type": [
"NO_HOST"
],
"dst_association_strength": null,
"dst_causality_actor_process_execution_time": null,
"dst_os_actor_process_image_name": null,
"dst_os_actor_process_os_pid": null,
"dynamic_fields": {
"action_country": [
"UNKNOWN"
],
"action_process_signature_status": [
"SIGNATURE_UNAVAILABLE"
],
"activated": "0001-01-01T00:00:00Z",
"activatingingUserId": "",
"actor_effective_username": [
"env1.local\administrator"
],
"actor_process_command_line": [
"\"C:\Users\administrator\Downloads\svchost.exe\" "
],
"actor_process_image_md5": [
"ddcd2be64212b10c3cf84496a879b098"
],
"actor_process_image_name": [
"svchost.exe"
],
"actor_process_image_path": [
"C:\Users\administrator\Downloads\svchost.exe"
],
"actor_process_image_sha256": [
"b013074d220d71877112b61e16927abbbb98ad29aa40609aca1b936332fbe4b7"
],
"actor_process_os_pid": [
5172
],
"actor_process_signature_status": [
"SIGNATURE_UNSIGNED"
],
"actor_thread_thread_id": [
2468
],
"agent_device_domain": "env1.local",
"agent_fqdn": "DC1ENV1APC02.env1.local",
"agent_hostname": "DC1ENV1APC02",
"agent_id": "63f88a9e797440ccac742a6adc926fb2",
"agent_ip_addresses": [
"10.111.230.11"
],
"agent_os_sub_type": "10.0.10240",
"agent_os_type": "AGENT_OS_WINDOWS",
"alert_action_status": "REPORTED",
"alert_category": "Malware",
"alert_description": "Behavioral threat detected (rule: bioc.masquerade_svchost)",
"alert_name": "Behavioral Threat",
"alert_source": "TRAPS",
"alert_type": "Unclassified",
"attachment": null,
"category": "",
"causality_actor_causality_id": [
"AdhDcc/XHpAAABQ0AAAAAA=="
],
"causality_actor_process_command_line": [
"\"C:\Users\administrator\Downloads\svchost.exe\" "
],
"causality_actor_process_image_name": [
"svchost.exe"
],
"causality_actor_process_image_path": [
"C:\Users\administrator\Downloads\svchost.exe"
],
"causality_actor_process_image_sha256": [
"b013074d220d71877112b61e16927abbbb98ad29aa40609aca1b936332fbe4b7"
],
"causality_actor_process_signature_status": [
"SIGNATURE_UNSIGNED"
],
"closeReason": "",
"closed": "0001-01-01T00:00:00Z",
"closingUserId": "",
"contains_featured_host": [
"NO"
],
"contains_featured_ip": [
"NO"
],
"contains_featured_user": [
"NO"
],
"dbotCurrentDirtyFields": null,
"dbotDirtyFields": null,
"dbotMirrorDirection": "",
"dbotMirrorId": "",
"dbotMirrorInstance": "",
"dbotMirrorLastSync": "0001-01-01T00:00:00Z",
"dbotMirrorTags": null,
"droppedCount": 0,
"dueDate": "0001-01-01T00:00:00Z",
"event_type": [
1
],
"feedBased": false,
"fw_is_phishing": [
"NOT_AVAILABLE"
],
"internal_id": 6887,
"investigationId": "6887",
"isDebug": false,
"is_whitelisted": false,
"labels": null,
"lastJobRunTime": "0001-01-01T00:00:00Z",
"lastOpen": "0001-01-01T00:00:00Z",
"linkedCount": 0,
"linkedIncidents": null,
"mac": "00:50:56:89:8b:8e",
"mitre_tactic_id_and_name": [
"TA0005 - Defense Evasion",
"TA0002 - Execution"
],
"mitre_technique_id_and_name": [
"T1036.005 - Masquerading: Match Legitimate Name or Location"
],
"module_id": [
"Behavioral Threat Protection"
],
"notifyTime": "2022-09-21T06:45:17.746532863Z",
"occurred": "0001-01-01T00:00:00Z",
"openDuration": 0,
"os_actor_process_signature_status": [
"SIGNATURE_UNAVAILABLE"
],
"os_actor_thread_thread_id": [
2468
],
"phase": "",
"playbookId": "T1036 - Masquerading",
"reason": "",
"reminder": "0001-01-01T00:00:00Z",
"resolution_comment": "",
"resolution_status": "STATUS_020_UNDER_INVESTIGATION",
"runStatus": "error",
"severity": "SEV_040_HIGH",
"sla": 0,
"sourceInstance": "",
"source_insert_ts": 1648560949000,
"starred": false
},
"end_match_attempt_ts": null,
"event_id": null,
"event_sub_type": null,
"event_timestamp": [
1648560949290
],
"event_type": [
1
],
"events_length": 1,
"external_id": "d4c2983dfab74741b087dce1bbffd8d5",
"family_tags": null,
"filter_rule_id": null,
"forensics_artifact_type": null,
"from_dml": null,
"fw_app_category": null,
"fw_app_id": null,
"fw_app_subcategory": null,
"fw_app_technology": null,
"fw_device_name": null,
"fw_email_recipient": null,
"fw_email_sender": null,
"fw_email_subject": null,
"fw_interface_from": null,
"fw_interface_to": null,
"fw_is_phishing": [
"NOT_AVAILABLE"
],
"fw_misc": null,
"fw_rule": null,
"fw_rule_id": null,
"fw_serial_number": null,
"fw_url_domain": null,
"fw_vsys": null,
"fw_xff": null,
"identity_invoked_by_type": null,
"identity_name": null,
"identity_sub_type": null,
"identity_type": null,
"image_name": null,
"internal_id": "6887",
"iot_pivot_url": null,
"is_disintegrated": null,
"is_pcap": false,
"is_whitelisted": false,
"is_xsoar_alert": false,
"last_modified_ts": 1663742717853,
"local_insert_ts": 1648560958017,
"mac": "00:50:56:89:8b:8e",
"matching_service_rule_id": null,
"matching_status": "MATCHED",
"mitre_tactic_id_and_name": [
"TA0005 - Defense Evasion",
"TA0002 - Execution"
],
"mitre_technique_id_and_name": [
"T1036.005 - Masquerading: Match Legitimate Name or Location"
],
"module_id": [
"Behavioral Threat Protection"
],
"module_name": [
"COMPONENT_DSE"
],
"operation_name": null,
"original_severity": "SEV_040_HIGH",
"os_actor_causality_id": null,
"os_actor_effective_username": null,
"os_actor_process_causality_id": null,
"os_actor_process_command_line": null,
"os_actor_process_execution_time": null,
"os_actor_process_image_md5": null,
"os_actor_process_image_name": null,
"os_actor_process_image_path": null,
"os_actor_process_image_sha256": null,
"os_actor_process_instance_id": null,
"os_actor_process_os_pid": null,
"os_actor_process_signature_status": [
"SIGNATURE_UNAVAILABLE"
],
"os_actor_process_signature_vendor": null,
"os_actor_thread_thread_id": [
2468
],
"phone_number": null,
"pivot_url": null,
"playbook_suggestion_rule_id": null,
"policy_id": null,
"project": null,
"query_tables": null,
"referenced_resource": null,
"remote_cid": null,
"resolution_comment": "",
"resolution_status": "STATUS_020_UNDER_INVESTIGATION",
"resource_sub_type": null,
"resource_type": null,
"severity": "SEV_040_HIGH",
"source_insert_ts": 1648560949290,
"starred": false,
"story_id": null,
"suggested_playbook_id": null,
"tim_main_indicator": null,
"user_agent": null,
"xpanse_asset_id": null,
"xpanse_asset_name": null,
"xpanse_policy_id": null,
"xpanse_primary_asset_id": null,
"xpanse_service_id": null
}
}
}
Human Readable Output
Alerts
Action Alert ID Category Description Detection Timestamp Host IP Host Name Name Severity detected (reported) 6887 Malware Behavioral threat detected (rule: bioc.masquerade_svchost) 2022-03-29T13:35:49.000Z 10.111.230.11 DC1ENV1APC02 Behavioral Threat SEV_040_HIGH
xdr-get-contributing-event
Retrieves contributing events for a specific correlation alert.
Known limitation: the command is compatible only with correlation alerts, otherwise an error will be raised.
Required Permissions
Required Permissions For API call:
Alerts & Incidents –> View
Builtin Roles with this permission includes: “Investigator”, “Responder”, “Privileged Investigator”, “Privileged Responder”, “Viewer”, and “Instance Admin”.
Base Command
xdr-get-contributing-event
Input
| Argument Name | Description | Required |
|---|---|---|
| alert_ids | The alert ID’s from where to retrieve the contributing events. | Required |
| limit | The maximum number of contributing events to retrieve. Default is 50. | Optional |
| page_number | The page number to retrieve. Minimum is 1. Default is 1. | Optional |
| page_size | The page size. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.ContributingEvent.alertID | String | The alert ID. |
| PaloAltoNetworksXDR.ContributingEvent.events | Unknown | Contributing events per alert. |
Command example
!xdr-get-contributing-event alert_ids=`[123456 , 123457]`
Context Example
{
"PaloAltoNetworksXDR": {
"ContributingEvent": [
{
"alertID": "123456",
"events": [
{
"Domain": "WIN10X64",
"Host_Name": "WIN10X64",
"Logon_Type": "7",
"Process_Name": "C:\\Windows\\System32\\svchost.exe",
"Raw_Message": "An account was successfully logged on.",
"Source_IP": "1.1.1.1",
"User_Name": "xsoar",
"111111": 15,
"222222": 165298280000,
"333333": "abcdef",
"444444": 1,
"555555": "ghijk",
"_is_cardable": true,
"_product": "XDR agent",
"_time": 165298280000,
"_vendor": "PANW",
"insert_timestamp": 165298280001
}
]
},
{
"alert_id": "123457",
"events": [
{
"Domain": "WIN10X64",
"Host_Name": "WIN10X64",
"Logon_Type": "7",
"Process_Name": "C:\\Windows\\System32\\svchost.exe",
"Raw_Message": "An account was successfully logged on",
"Source_IP": "1.1.1.1",
"User_Name": "xsoar",
"111111": 15,
"222222": 165298280000,
"333333": "abcdef",
"444444": 1,
"555555": "ghijk",
"_is_cardable": true,
"_product": "XDR agent",
"_time": 165298280000,
"_vendor": "PANW",
"insert_timestamp": 165298280001
}
]
}
]
}
}
Human Readable Output
Contributing events
Alert _ Id Events 123456 - Logon_Type: 7
User_Name: xsoar
Domain: WIN10X64
Source_IP: 1.1.1.1
Process_Name: C:\Windows\System32\svchost.exe
Host_Name: WIN10X64
Raw_Message: An account was successfully logged on. _time: 165298280000
555555: a1b2c3d4
222222: 165298280000
333333: abcdef
111111: 15
444444: 1
insert_timestamp: 165298280001
_vendor: PANW
_product: XDR agent
_is_cardable: true123457 - Logon_Type: 7
User_Name: xsoar
Domain: WIN10X64
Source_IP: 1.1.1.1
Process_Name: C:\Windows\System32\svchost.exe
Host_Name: WIN10X64
Raw_Message: An account was successfully logged on. _time: 165298280000
555555: ghijk
222222: 165298280000
333333: abcdef
111111: 15
444444: 1
insert_timestamp: 165298280001
_vendor: PANW
_product: XDR agent
_is_cardable: true
xdr-replace-featured-field
Replace the featured hosts\users\IP addresses\active directory groups listed in your environment.
Required Permissions
Required Permissions For API call:
Alerts & Incidents –> View/ Edit
Builtin Roles with this permission includes: “Investigator”, “Privileged Investigator”, “Privileged Responder” and “Instance Admin”.
Base Command
xdr-replace-featured-field
Input
| Argument Name | Description | Required |
|---|---|---|
| field_type | The field type to change. Possible values are: hosts, users, ip_addresses, ad_groups. | Required |
| values | The string value, which defines the new field. Maximum length is 256 characters. | Required |
| comments | The string value, which represents additional information regarding the featured alert field. | Optional |
| ad_type | The string value to replace an active directory group or organizational unit. Possible values are: group, ou. Default is group. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.FeaturedField.fieldType | String | The field type that changed. |
| PaloAltoNetworksXDR.FeaturedField.fields | String | String value that defines the new field. |
Command example
!xdr-replace-featured-field field_type=ip_addresses values=`["1.1.1.1"]` comments=`new ip address`
Context Example
{
"PaloAltoNetworksXDR": {
"FeaturedField": {
"fieldType": "ip_addresses",
"fields": [
{
"comment": "new ip address",
"value": "1.1.1.1"
}
]
}
}
}
Human Readable Output
Replaced featured: ip_addresses
Comment Value new ip address 1.1.1.1
xdr-list-users
Retrieve a list of the current users in the environment.
Required license: Cortex XDR Pro per Endpoint, Cortex XDR Pro, or Cortex XDR Pro per GB.
Base Command
xdr-list-users
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.User.user_email | string | Email address of the user |
| PaloAltoNetworksXDR.User.user_first_name | string | First name of the user |
| PaloAltoNetworksXDR.User.user_last_name | string | Last name of the user. |
| PaloAltoNetworksXDR.User.role_name | string | Role name associated with the user. |
| PaloAltoNetworksXDR.User.last_logged_in | Number | Timestamp of when the user last logged in. |
| PaloAltoNetworksXDR.User.user_type | string | Type of user. |
| PaloAltoNetworksXDR.User.groups | array | Name of user groups associated with the user, if applicable. |
| PaloAltoNetworksXDR.User.scope | array | Name of scope associated with the user, if applicable. |
Command example
#### Context Example
```json
{
"dummy": {
"User": [
{
"groups": [],
"last_logged_in": 1648158415051,
"role_name": "dummy",
"scope": [],
"user_email": "dummy@dummy.com",
"user_first_name": "dummy",
"user_last_name": "dummy",
"user_type": "dummy"
},
{
"groups": [],
"last_logged_in": null,
"role_name": "dummy",
"scope": [],
"user_email": "dummy@dummy.com",
"user_first_name": "dummy",
"user_last_name": "dummy",
"user_type": "dummy"
}
]
}
}
Human Readable Output
Users
First Name Groups Last Name Role Type User email dummy dummy dummy dummy dummy dummy dummy dummy dummy dummy
xdr-list-risky-users
Retrieve the risk score of a specific user or list of users with the highest risk score in the environment along with the reason affecting each score.
Required license: Cortex XDR Pro per Endpoint, Cortex XDR Pro, or Cortex XDR Pro per GB.
Base Command
xdr-list-risky-users
Input
| Argument Name | Description | Required |
|---|---|---|
| user_id | Unique ID of a specific user. User ID could be either of the foo/dummy format, or just dummy.. |
Optional |
| limit | Limit the number of users that will appear in the list. (Use limit when no specific host is requested.). Default is 10. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.RiskyUser.type | String | Form of identification element. |
| PaloAltoNetworksXDR.RiskyUser.id | String | Identification value of the type field. |
| PaloAltoNetworksXDR.RiskyUser.score | Number | The score assigned to the user. |
| PaloAltoNetworksXDR.RiskyUser.reasons.date created | String | Date when the incident was created. |
| PaloAltoNetworksXDR.RiskyUser.reasons.description | String | Description of the incident. |
| PaloAltoNetworksXDR.RiskyUser.reasons.severity | String | The severity of the incident |
| PaloAltoNetworksXDR.RiskyUser.reasons.status | String | The incident status |
| PaloAltoNetworksXDR.RiskyUser.reasons.points | Number | The score. |
Command example
!xdr-list-risky-users user_id=dummy
Context Example
{
"PaloAltoNetworksXDR": {
"RiskyUser": {
"id": "dummy",
"reasons": [],
"score": 0,
"type": "user"
}
}
}
Human Readable Output
Risky Users
User ID Score Description dummy 0
xdr-list-risky-hosts
Retrieve the risk score of a specific host or list of hosts with the highest risk score in the environment along with the reason affecting each score.
Required license: Cortex XDR Pro per Endpoint, Cortex XDR Pro, or Cortex XDR Pro per GB.
Base Command
xdr-list-risky-hosts
Input
| Argument Name | Description | Required |
|---|---|---|
| host_id | The host name of a specific host. | Optional |
| limit | Limit the number of hosts that will appear in the list. By default, the limit is 50 hosts.(Use limit when no specific host is requested.). Default is 10. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.RiskyHost.type | String | Form of identification element. |
| PaloAltoNetworksXDR.RiskyHost.id | String | Identification value of the type field. |
| PaloAltoNetworksXDR.RiskyHost.score | Number | The score assigned to the host. |
| PaloAltoNetworksXDR.RiskyHost.reasons.date created | String | Date when the incident was created. |
| PaloAltoNetworksXDR.RiskyHost.reasons.description | String | Description of the incident. |
| PaloAltoNetworksXDR.RiskyHost.reasons.severity | String | The severity of the incident |
| PaloAltoNetworksXDR.RiskyHost.reasons.status | String | The incident status |
| PaloAltoNetworksXDR.RiskyHost.reasons.points | Number | The score. |
Command example
!xdr-list-risky-hosts host_id=dummy
Context Example
{
"PaloAltoNetworksXDR": {
"RiskyHost": {
"id": "dummy",
"reasons": [],
"score": 0,
"type": "dummy"
}
}
}
Human Readable Output
Risky Hosts
Host ID Score Description dummy 0
xdr-list-user-groups
Retrieve a list of the current user emails associated with one or more user groups in the environment.
Required license: Cortex XDR Pro per Endpoint, Cortex XDR Pro, or Cortex XDR Pro per GB.
Base Command
xdr-list-user-groups
Input
| Argument Name | Description | Required |
|---|---|---|
| group_names | A comma-separated list of one or more user group names for which you want the associated users. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.UserGroup.group_name | String | Name of the user group. |
| PaloAltoNetworksXDR.UserGroup.description | String | Description of the user group, if available. |
| PaloAltoNetworksXDR.UserGroup.pretty_name | String | Name of the user group as it appears in the management console. |
| PaloAltoNetworksXDR.UserGroup.insert_time | Number | Timestamp of when the user group was created. |
| PaloAltoNetworksXDR.UserGroup.update_time | Number | Timestamp of when the user group was last updated. |
| PaloAltoNetworksXDR.UserGroup.user_email | array | List of email addresses belonging to the users associated with the user group. |
| PaloAltoNetworksXDR.UserGroup.source | String | Type of user group. |
Command example
!xdr-list-user-groups group_names=test
Context Example
{
"PaloAltoNetworksXDR": {
"UserGroup": {
"description": "test",
"group_name": "test",
"insert_time": 1684746187678,
"pretty_name": null,
"source": "Custom",
"update_time": 1684746209062,
"user_email": [
null
]
}
}
}
Human Readable Output
Groups
Group Name Group Description User email test test for demo
xdr-list-roles
Retrieve information about one or more roles created in the environment.
Required license: Cortex XDR Pro per Endpoint, Cortex XDR Pro, or Cortex XDR Pro per GB.
Base Command
xdr-list-roles
Input
| Argument Name | Description | Required |
|---|---|---|
| role_names | A comma-separated list of one or more role names in your environment for which you want detailed information. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Role.pretty_name | String | Name of the role as it appears in the management console. |
| PaloAltoNetworksXDR.Role.permissions | array | List of permissions associated with this role. |
| PaloAltoNetworksXDR.Role.insert_time | Number | Timestamp of when the role was created. |
| PaloAltoNetworksXDR.Role.update_time | Number | Timestamp of when the role was last updated. |
| PaloAltoNetworksXDR.Role.created_by | String | Email of the user who created the role. |
| PaloAltoNetworksXDR.Role.description | String | Description of the role, if available. |
| PaloAltoNetworksXDR.Role.groups | array | Group names associated with the role. |
| PaloAltoNetworksXDR.Role.users | array | Email address of users associated with the role. |
Command example
!xdr-list-roles role_names=dummy
Context Example
{
"PaloAltoNetworksXDR": {
"Role": [
[
{
"created_by": "dummy dummy",
"description": "The user(s) have full access.",
"groups": [],
"insert_time": null,
"permissions": [
"dummy"
],
"pretty_name": "dummy",
"update_time": null,
"users": []
}
]
]
}
}
Human Readable Output
Roles
Role Name Description Permissions Users Groups dummy The user(s) have full access. ADMIN
xdr-set-user-role
Add one or more users to a role.
Required license: Cortex XDR Pro per Endpoint, Cortex XDR Pro, or Cortex XDR Pro per GB.
Base Command
xdr-set-user-role
Input
| Argument Name | Description | Required |
|---|---|---|
| user_emails | A comma-separated list of one or more user emails of users you want to add to a role. | Required |
| role_name | Name of the role you want to add a user to. | Required |
Context Output
There is no context output for this command.
Command example
!xdr-set-user-role role_name=dummy user_emails=dummy
Human Readable Output
Role was updated successfully for 1 user.
xdr-remove-user-role
Remove one or more users from a role.
Required license: Cortex XDR Pro per Endpoint, Cortex XDR Pro, or Cortex XDR Pro per GB.
Base Command
xdr-remove-user-role
Input
| Argument Name | Description | Required |
|---|---|---|
| user_emails | A comma-separate list of one or more user emails of users you want to remove from a role. | Required |
Context Output
There is no context output for this command.
Command example
!xdr-remove-user-role user_emails=dummy
Human Readable Output
Role was removed successfully for 1 user.
xdr-script-run
Initiates a new endpoint script execution action using a script from the script library and returns the results.
Required Permissions
Required Permissions For API call:
Agent Scripts library –> View
Builtin Roles with this permission includes: “Privileged Responder”, “Viewer” and “Instance Admin”.
Base Command
xdr-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 xdr-get-endpoints command. | Required |
| script_uid | Unique identifier of the script. Can be retrieved by running the xdr-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 | action ID for polling. | Optional |
| hide_polling_output | whether to hide the polling result (automatically filled by polling). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.ScriptResult.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptResult.results.retrieved_files | Number | Number of successfully retrieved files. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_ip_address | String | Endpoint IP address. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_name | String | Number of successfully retrieved files. |
| PaloAltoNetworksXDR.ScriptResult.results.failed_files | Number | Number of files failed to retrieve. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_status | String | Endpoint status. |
| PaloAltoNetworksXDR.ScriptResult.results.domain | String | Domain to which the endpoint belongs. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_id | String | Endpoint ID. |
| PaloAltoNetworksXDR.ScriptResult.results.execution_status | String | Execution status of this endpoint. |
| PaloAltoNetworksXDR.ScriptResult.results.return_value | String | Value returned by the script in case the type is not a dictionary. |
| PaloAltoNetworksXDR.ScriptResult.results.standard_output | String | The STDOUT and the STDERR logged by the script during the execution. |
| PaloAltoNetworksXDR.ScriptResult.results.retention_date | Date | Timestamp in which the retrieved files will be deleted from the server. |
Base Command
xdr-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 xdr-get-endpoints command. | Required |
| script_uid | Unique identifier of the script. Can be retrieved by running the xdr-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 |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.ScriptResult.action_id | Number | ID of the action initiated. |
| PaloAltoNetworksXDR.ScriptResult.results.retrieved_files | Number | Number of successfully retrieved files. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_ip_address | String | Endpoint IP address. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_name | String | Number of successfully retrieved files. |
| PaloAltoNetworksXDR.ScriptResult.results.failed_files | Number | Number of files failed to retrieve. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_status | String | Endpoint status. |
| PaloAltoNetworksXDR.ScriptResult.results.domain | String | Domain to which the endpoint belongs. |
| PaloAltoNetworksXDR.ScriptResult.results.endpoint_id | String | Endpoint ID. |
| PaloAltoNetworksXDR.ScriptResult.results.execution_status | String | Execution status of this endpoint. |
| PaloAltoNetworksXDR.ScriptResult.results.return_value | String | Value returned by the script in case the type is not a dictionary. |
| PaloAltoNetworksXDR.ScriptResult.results.standard_output | String | The STDOUT and the STDERR logged by the script during the execution. |
| PaloAltoNetworksXDR.ScriptResult.results.retention_date | Date | Timestamp in which the retrieved files will be deleted from the server. |
Command example
!xdr-script-run endpoint_ids=1 script_uid=123
Human Readable Output
Waiting for the script to finish running on the following endpoints: [‘1’]…
Script Execution Results - 10368
_return_value domain endpoint_id endpoint_ip_address endpoint_name endpoint_status execution_status failed_files retention_date retrieved_files standard_output Name: return value WORKGROUP 1 1.1.1.1 WIN10X64 STATUS_010_CONNECTED COMPLETED_SUCCESSFULLY 0 0
Context Example
{
"PaloAltoNetworksXDR": {
"ScriptResult": {
"results": [
{
"domain": "WORKGROUP",
"endpoint_name": "WIN10X64",
"retrieved_files": 0,
"failed_files": 0,
"standard_output": "",
"_return_value": [
"return_value"
],
"command_output": [
"command_output"
],
"endpoint_status": "STATUS_010_CONNECTED",
"command": "_return_value",
"endpoint_id": "1",
"endpoint_ip_address": [
"1.1.1.1"
],
"execution_status": "COMPLETED_SUCCESSFULLY",
"retention_date": null
}
],
"action_id": 4444
}
}
}
xdr-endpoint-tag-add
Adds a tag to specified endpoint_ids
Required Permissions
Required Permissions For API call:
Endpoint Administrations –> View/ Edit
Builtin Roles with this permission includes: “Privileged Responder” and “Instance Admin”.
Base Command
xdr-endpoint-tag-add
Input
| Argument Name | Description | Required |
|---|---|---|
| endpoint_ids | List of endpoint IDs. Supports comma-separated list. | Optional |
| tag | Tag to add. | Optional |
Context Output
There is no context output for this command.
xdr-endpoint-tag-remove
Removes a tag from specified endpoint_ids.
Required Permissions
Required Permissions For API call:
Endpoint Administrations –> View/ Edit
Builtin Roles with this permission includes: “Privileged Responder” and “Instance Admin”.
Base Command
xdr-endpoint-tag-remove
Input
| Argument Name | Description | Required |
|---|---|---|
| endpoint_ids | List of endpoint IDs. Supports comma separated list. | Optional |
| tag | Tag to remove from specified endpoint_ids. | Optional |
Context Output
There is no context output for this command.
xdr-get-tenant-info
Provides information about the tenant.
Base Command
xdr-get-tenant-info
Input
There are no arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.TenantInformation.pro_per_endpoint_expiration | Date | Expiration time pro per endpoint. |
| PaloAltoNetworksXDR.TenantInformation.purchased_pro_per_endpoint.agents | Number | Number of endpoints agent purchased. |
| PaloAltoNetworksXDR.TenantInformation.data_enabled_pro_per_endpoint | Number | Enabled data per pro endpoint. |
| PaloAltoNetworksXDR.TenantInformation.prevent_expiration | Number | Number of prevent expirations. |
| PaloAltoNetworksXDR.TenantInformation.purchased_prevent | Number | Number of purchased prevents. |
| PaloAltoNetworksXDR.TenantInformation.installed_prevent | Number | Number of installed prevents. |
| PaloAltoNetworksXDR.TenantInformation.pro_tb_expiration | Date | pro_tb license expiration time. |
| PaloAltoNetworksXDR.TenantInformation.purchased_pro_tb.tb | Number | Number of pro_tbs purchased. |
| PaloAltoNetworksXDR.TenantInformation.installed_pro_tb | Number | Number of pro_tbs installed. |
| PaloAltoNetworksXDR.TenantInformation.compute_unit_expiration | Date | Compute unit expiration time. |
| PaloAltoNetworksXDR.TenantInformation.purchased_compute_unit | Number | Number of compute units purchased. |
| PaloAltoNetworksXDR.TenantInformation.compute_unit_is_trial | Boolean | Whether the compute unit is a trial. |
| PaloAltoNetworksXDR.TenantInformation.host_insights_expiration | Date | Host insight expiration time. |
| PaloAltoNetworksXDR.TenantInformation.enabled_host_insights | Number | Number of host insights enabled. |
| PaloAltoNetworksXDR.TenantInformation.purchased_host_insights | Number | Number of purchased host insights. |
| PaloAltoNetworksXDR.TenantInformation.forensics_expiration | Date | Forensic expiration time. |
| PaloAltoNetworksXDR.TenantInformation.purchased_forensics | Number | Number of forensics purchased. |
Command example
#### Context Example
```json
{
"PaloAltoNetworksXDR": {
"TenantInformation": {
"compute_unit_expiration": 0,
"data_enabled_pro_per_endpoint": 2,
"forensics_expiration": 0,
"installed_prevent": 2,
"installed_pro_tb": 0,
"prevent_expiration": 0,
"pro_per_endpoint_expiration": "May 7th 2025 06:59:59",
"pro_tb_expiration": "May 7th 2025 06:59:59",
"purchased_compute_unit": 2000,
"purchased_prevent": 0,
"purchased_pro_per_endpoint": {
"agents": 300
},
"purchased_pro_tb": {
"tb": 1
}
}
}
}
Human Readable Output
Tenant Information
Compute Unit Expiration Data Enabled Pro Per Endpoint Forensics _ Expiration Installed _ Prevent Installed Pro Tb Prevent _ Expiration Pro Per Endpoint _ Expiration Pro Tb Expiration Purchased Compute Unit Purchased _ Prevent Purchased Pro Per _ Endpoint Purchased Pro Tb May 7th 2025 06:59:59 May 7th 2025 06:59:59 agents: 300 tb: 1
Incident Mirroring
You can enable incident mirroring between Cortex XSOAR incidents and Palo Alto Networks Cortex XDR - Investigation and Response corresponding events (available from Cortex XSOAR version 6.0.0).
To set up the mirroring:
- Enable Fetching incidents in your instance configuration.
-
In the Mirroring Direction integration parameter, select in which direction the incidents should be mirrored:
Option Description None Turns off incident mirroring. Incoming Any changes in Palo Alto Networks Cortex XDR - Investigation and Response events (mirroring incoming fields) will be reflected in Cortex XSOAR incidents. Outgoing Any changes in Cortex XSOAR incidents will be reflected in Palo Alto Networks Cortex XDR - Investigation and Response events (outgoing mirrored fields). Both
Newly fetched incidents will be mirrored in the chosen direction. However, this selection does not affect existing incidents.
Important Note: To ensure the mirroring works as expected, mappers are required, both for incoming and outgoing, to map the expected fields in Cortex XSOAR and Palo Alto Networks Cortex XDR - Investigation and Response.
xdr-endpoint-alias-change
Gets a list of endpoints according to the passed filters, and changes their alias name. Filtering by multiple fields will be concatenated using the AND condition (OR is not supported).
Base Command
xdr-endpoint-alias-change
Input
| Argument Name | Description | Required |
|---|---|---|
| status | The status of the endpoint to use as a filter. Possible values are: connected, disconnected. | Optional |
| endpoint_id_list | A comma-separated list of endpoint IDs to use as a filter. | Optional |
| dist_name | A comma-separated list of distribution package names or installation package names to use as a filter. Example: dist_name1,dist_name2. |
Optional |
| ip_list | A comma-separated list of IP addresses to use as a filter. Example: 8.8.8.8,1.1.1.1. |
Optional |
| group_name | A comma-separated list of group names to which the agent belongs to use as a filter. Example: group_name1,group_name2. |
Optional |
| platform | The endpoint platform to use as a filter. Possible values are: windows, linux, macos, android. | Optional |
| alias_name | A comma-separated list of alias names to use as a filter. Examples: alias_name1,alias_name2. |
Optional |
| isolate | Specifies whether the endpoint was isolated or unisolated to use as a filter. Possible values are: isolated, unisolated. Note: This argument returns only the first endpoint that matches the filter. | Optional |
| hostname | A comma-separated list of hostnames to use as a filter. Example: hostname1,hostname2. |
Optional |
| first_seen_gte | All the agents that were first seen after {first_seen_gte} to use as a filter. Supported values: 1579039377301 (time in milliseconds) “3 days” (relative date) “2019-10-21T23:45:00” (date). |
Optional |
| first_seen_lte | All the agents that were first seen before {first_seen_lte} to use as a filter. Supported values: 1579039377301 (time in milliseconds) “3 days” (relative date) “2019-10-21T23:45:00” (date). |
Optional |
| last_seen_gte | All the agents that were last seen after {last_seen_gte} to use as a filter. Supported values: 1579039377301 (time in milliseconds) “3 days” (relative date) “2019-10-21T23:45:00” (date). |
Optional |
| last_seen_lte | All the agents that were last seen before {last_seen_lte} to use as a filter. Supported values: 1579039377301 (time in milliseconds) “3 days” (relative date) “2019-10-21T23:45:00” (date). |
Optional |
| username | The usernames to query for to use as a filter. Accepts a single user, or comma-separated list of usernames. | Optional |
| new_alias_name | The alias name to change to. Note: If you send an empty field, (e.g new_alias_name="") the current alias name is deleted. | Required |
| scan_status | The scan status of the endpoint to use as a filter. Possible values are: none, pending, in_progress, canceled, aborted, pending_cancellation, success, error. | Optional |
Context Output
There is no context output for this command.
Command example
!xdr-endpoint-alias-change new_alias_name=test scan_status=success ip_list=1.1.1.1
Human Readable Output
The endpoint alias was changed successfully.
Note: If there is no error in the process, then this is the output even when the specific endpoint does not exist.
xdr-update-alert (Deprecated)
This command is deprecated, please use xdr-issue-update instead. Update one or more alerts. You can update up to 100 alerts per request. Missing fields are ignored. Required license: Cortex XDR Prevent, Cortex XDR Pro per Endpoint, or Cortex XDR Pro per GB.
Base Command
xdr-update-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| alert_ids | Comma-separated list of alert IDs. | Required |
| severity | Severity of the incident which was closed. Possible values are: critical, high, medium, low. | Optional |
| status | New status for updated alerts. Possible values are: new, resolved_threat_handled, under_investigation, resolved_security_testing, resolved_auto, resolved_auto_resolve, resolved_known_issue, resolved_duplicate, resolved_other, resolved_false_positive, resolved_true_positive. | Optional |
| comment | Comment to append to updated alerts. | Optional |
Context Output
There is no context output for this command.
Command example
!xdr-update-alert alert_ids=35326 severity=low
Human Readable Output
Alerts with IDs 35326 have been updated successfully.
xdr-asset-group-update
Updates an asset group.
Base Command
xdr-asset-group-update
Input
| Argument Name | Description | Required |
|---|---|---|
| group_id | The ID of the asset group to update. | Required |
| group_name | The name of the asset group. | Optional |
| group_type | The type of the asset group. Possible values are: Static, Dynamic. | Optional |
| group_description | The description of the asset group. | Optional |
| membership_predicate_json | Define the filter conditions for selecting which assets to be included in a dynamic Asset Group. For example: “{"AND":[{"SEARCH_FIELD":"xdm.asset.type.class","SEARCH_TYPE":"NEQ","SEARCH_VALUE":"Other"}]}”. The SEARCH_FIELD needs to be in lower case. For more information, please refer to the documentation: https://docs-cortex.paloaltonetworks.com/r/Cortex-XDR-Platform-APIs/Update-an-Asset-Group. | Optional |
Context Output
There is no context output for this command.
xdr-asset-group-create
Creates an asset group.
Base Command
xdr-asset-group-create
Input
| Argument Name | Description | Required |
|---|---|---|
| group_name | The name of the asset group. | Required |
| group_type | The type of the asset group. Possible values are: Static, Dynamic. | Required |
| group_description | The description of the asset group. | Optional |
| membership_predicate_json | Define the filter conditions for selecting which assets to be included in a dynamic Asset Group. For example: “{"AND":[{"SEARCH_FIELD":"xdm.asset.type.class","SEARCH_TYPE":"NEQ","SEARCH_VALUE":"Other"}]}”. The SEARCH_FIELD needs to be in lower case. For more information, please refer to the documentation: https://docs-cortex.paloaltonetworks.com/r/Cortex-XDR-Platform-APIs/Create-an-Asset-Group. | Optional |
Context Output
There is no context output for this command.
xdr-asset-group-list
Returns a list of asset groups.
Base Command
xdr-asset-group-list
Input
| Argument Name | Description | Required |
|---|---|---|
| sort_field | The field by which to sort the results. For example: XDM.ASSET_GROUP.NAME. Use the documentation for finding more fields here. | Optional |
| sort_order | The order in which to sort the results. Possible values are: asc, desc. | Optional |
| filter_json | The JSON to use for the “filter” field in the API. For example: “{"AND": [{"SEARCH_FIELD": "XDM.ASSET_GROUP.TYPE", "SEARCH_TYPE": "EQ", "SEARCH_VALUE": "Dynamic"}]}”. For more information, please refer to the documentation: https://docs-cortex.paloaltonetworks.com/r/Cortex-XDR-Platform-APIs/Get-all-or-filtered-asset-groups. | Optional |
| limit | Maximum number of asset groups to return. Default is 50. Default is 50. | Optional |
| page_size | Page size for pagination. | Optional |
| page | Page number for pagination. 0 is the first page. Default is 0. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_ID | String | The unique identifier of the asset group. |
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_NAME | String | The name of the asset group. |
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_TYPE | String | The type of the asset group (Static or Dynamic). |
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_FILTER | String | The filter query string used to define the members of the XDM asset group. |
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_DESCRIPTION | String | The description of the asset group. |
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_CREATION_TIME | Date | The timestamp when the group was created (Epoch). |
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_LAST_UPDATE_TIME | Date | The timestamp when the group was last updated (Epoch). |
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_CREATED_BY_PRETTY | String | The user or API key that created the group. |
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_MODIFIED_BY_PRETTY | String | The user or API key that last modified the group. |
| PaloAltoNetworksXDR.AssetGroup.XDM_ASSET_GROUP_MEMBERSHIP_PREDICATE | Unknown | The JSON object defining the search criteria for dynamic groups. |
| PaloAltoNetworksXDR.AssetGroup.IS_USED_BY_SBAC | Boolean | Indicates whether this asset group is currently utilized to define Scope-Based Access Control (SBAC) rules. |
xdr-asset-group-delete
Deletes an asset group.
Base Command
xdr-asset-group-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| group_id | The ID of the asset group to delete. | Required |
Context Output
There is no context output for this command.
xdr-asset-schema-field-options-get
Gets the enum values of a specified field in the asset schema.
Base Command
xdr-asset-schema-field-options-get
Input
| Argument Name | Description | Required |
|---|---|---|
| field_name | The name of the field to get options for. You can use xdr-asset-schema-get in order to get the schema. The field must be of type ENUM, for example: xdm.asset.provider. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.AssetSchema.field_name | String | The name of the field. |
| PaloAltoNetworksXDR.AssetSchema.options | Unknown | The enum values of the field. |
xdr-asset-schema-get
Gets the schema of the asset inventory.
Base Command
xdr-asset-schema-get
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.AssetSchema.field_name | String | The name of the field. |
| PaloAltoNetworksXDR.AssetSchema.field_type | String | The type of the field. |
| PaloAltoNetworksXDR.AssetSchema.field_pretty_name | String | The pretty name of the field. |
xdr-asset-list
Returns a list of assets.
Base Command
xdr-asset-list
Input
| Argument Name | Description | Required |
|---|---|---|
| asset_id | A comma-separated list of asset IDs. For example: “1,2,3”. When using this argument, the other filters will not be used. | Optional |
| sort_field | The field by which to sort the results. For example: xdm.asset.first_observed. Use the documentation for finding more fields here. | Optional |
| sort_order | The order in which to sort the results. Possible values are: asc, desc. | Optional |
| filter_json | The JSON to use for the “filter” field in the API. You can use xdr-asset-schema-get to get the schema. For more information, please refer to the documentation: here. | Optional |
| limit | Maximum number of assets to return. Default is 50. Default is 50. | Optional |
| page_size | Page size for pagination. Default is 50. | Optional |
| page | Page number for pagination. Default is 0. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Asset.xdm_asset_id | String | The unique identifier of the asset. |
| PaloAltoNetworksXDR.Asset.xdm_asset_name | String | The name of the asset (e.g., image SHA). |
| PaloAltoNetworksXDR.Asset.xdm_asset_strong_id | String | The strong identifier (SHA256) of the asset. |
| PaloAltoNetworksXDR.Asset.xdm_asset_provider | String | The provider of the asset. |
| PaloAltoNetworksXDR.Asset.xdm_asset_external_provider_id | String | External provider ID (if applicable). |
| PaloAltoNetworksXDR.Asset.xdm_asset_first_observed | Date | Timestamp when the asset was first observed. |
| PaloAltoNetworksXDR.Asset.xdm_asset_last_observed | Date | Timestamp when the asset was last observed. |
| PaloAltoNetworksXDR.Asset.xdm_asset_type_id | String | The ID of the asset type (e.g., CORE_IMAGE). |
| PaloAltoNetworksXDR.Asset.xdm_asset_type_name | String | The name of the asset type. |
| PaloAltoNetworksXDR.Asset.xdm_asset_type_category | String | The category of the asset (e.g., Container Image). |
| PaloAltoNetworksXDR.Asset.xdm_asset_type_class | String | The class of the asset (e.g., Compute). |
| PaloAltoNetworksXDR.Asset.xdm_development_cycle_stages | String | The development cycle stages (e.g., RUNTIME). |
| PaloAltoNetworksXDR.Asset.xdm_image_architecture | String | The architecture of the image (e.g., amd64). |
| PaloAltoNetworksXDR.Asset.xdm_image_digest | String | The image digest hash. |
| PaloAltoNetworksXDR.Asset.xdm_image_identifier | String | The image identifier. |
| PaloAltoNetworksXDR.Asset.xdm_image_names | String | List of names/tags associated with the image. |
| PaloAltoNetworksXDR.Asset.xdm_image_os | String | The OS version of the image. |
| PaloAltoNetworksXDR.Asset.xdm_image_os_distribution | String | The OS distribution (e.g., UBUNTU). |
| PaloAltoNetworksXDR.Asset.xdm_image_os_family | String | The OS family (e.g., Linux). |
| PaloAltoNetworksXDR.Asset.xdm_image_os_release | String | The OS release name (e.g., noble). |
| PaloAltoNetworksXDR.Asset.xdm_image_labels | Unknown | Labels associated with the image. |
| PaloAltoNetworksXDR.Asset.xdm_image_layers | Unknown | List of layers making up the image. |
| PaloAltoNetworksXDR.Asset.xdm_image_layers_created_at | Number | Timestamp of when the layer was created. |
| PaloAltoNetworksXDR.Asset.xdm_image_layers_instruction | String | The instruction used to create the layer (e.g., RUN, ADD). |
| PaloAltoNetworksXDR.Asset.xdm_image_layers_size | Number | The size of the layer in bytes. |
| PaloAltoNetworksXDR.Asset.xdm_asset_related_cases_cases_breakdown | Unknown | Breakdown of related cases by severity. |
| PaloAltoNetworksXDR.Asset.xdm_asset_related_cases_critical_cases | Number | Count of critical cases. |
| PaloAltoNetworksXDR.Asset.xdm_asset_related_issues_issues_breakdown | Unknown | Breakdown of related issues by severity. |
| PaloAltoNetworksXDR.Asset.xdm_asset_relations | Unknown | Relations to other assets. |
| PaloAltoNetworksXDR.Asset.xdm_asset_group_ids | Number | Group IDs associated with the asset. |
xdr-api-key-delete
Deletes the specified API keys.
Base Command
xdr-api-key-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| api_id | A comma-separated list of API key IDs to delete. | Required |
Context Output
There is no context output for this command.
xdr-api-key-list
Gets a list of existing API keys.
Base Command
xdr-api-key-list
Input
| Argument Name | Description | Required |
|---|---|---|
| api_id | A comma-separated list of API key IDs to retrieve. | Optional |
| role | A comma-separated list of API key roles to retrieve. | Optional |
| expires_before | Filters API keys that expire before this date. For example: “1 year”. Filters API keys that have an expiration date. | Optional |
| expires_after | Filters API keys that expire after this date. For example: “1 year”. Filters API keys that have an expiration date. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.APIKeyData.id | String | The API key ID. |
| PaloAltoNetworksXDR.APIKeyData.roles | String | The roles associated with the API key. |
| PaloAltoNetworksXDR.APIKeyData.expiration | Date | The expiration date of the API key. |
xdr-bioc-list
Returns a list of BIOCs.
Base Command
xdr-bioc-list
Input
| Argument Name | Description | Required |
|---|---|---|
| name | The BIOC name to filter by. Can filter by only one name at a time. | Optional |
| severity | The BIOC severity to filter by. Possible values are: info, low, medium, high, critical. | Optional |
| type | The BIOC type to filter by. Possible values are: other, persistence, evasion, tampering, file_type_obfuscation, privilege_escalation, credential_access, lateral_movement, execution, collection, exfiltration, infiltration, dropper, file_privilege_manipulation, reconnaissance, discovery. | Optional |
| is_xql | Whether the BIOC is XQL. Possible values are: true, false. | Optional |
| comment | The BIOC comment to filter by. | Optional |
| status | The BIOC status to filter by. Possible values are: enabled, disabled. | Optional |
| indicator | The BIOC indicator to filter by. | Optional |
| mitre_technique_id_and_name | The MITRE technique ID and name. Must be in format ‘ID - Name’, for example: [‘T1566 - Phishing’]. | Optional |
| mitre_tactic_id_and_name | The MITRE tactic ID and name. Must be in format ‘ID - Name’, for example: [‘T1566 - Phishing’]. | Optional |
| extra_data | Whether to return extended data. Possible values are: true, false. | Optional |
| limit | Maximum number of results to return. | Optional |
| page_size | Page size. | Optional |
| page | Page number. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.BIOC.rule_id | String | BIOC rule ID. |
| PaloAltoNetworksXDR.BIOC.name | String | BIOC name. |
| PaloAltoNetworksXDR.BIOC.type | String | BIOC type. |
| PaloAltoNetworksXDR.BIOC.severity | String | BIOC severity. |
| PaloAltoNetworksXDR.BIOC.status | String | BIOC status. |
| PaloAltoNetworksXDR.BIOC.is_xql | Boolean | Whether the BIOC is XQL. |
| PaloAltoNetworksXDR.BIOC.comment | String | The BIOC comment. |
| PaloAltoNetworksXDR.BIOC.indicator | String | The BIOC indicator. |
xdr-bioc-create
Creates a new BIOC.
Base Command
xdr-bioc-create
Input
| Argument Name | Description | Required |
|---|---|---|
| name | The BIOC name. | Required |
| severity | The BIOC severity. Possible values are: info, low, medium, high, critical. | Required |
| type | The BIOC type. Possible values are: other, persistence, evasion, tampering, file_type_obfuscation, privilege_escalation, credential_access, lateral_movement, execution, collection, exfiltration, infiltration, dropper, file_privilege_manipulation, reconnaissance, discovery. | Optional |
| is_xql | Whether the new BIOC is XQL. Possible values are: true, false. | Optional |
| comment | The BIOC comment. | Optional |
| status | The BIOC status. Possible values are: enabled, disabled. | Optional |
| indicator | The BIOC indicator, for example: ‘{“runOnCGO”:true,”investigationType”:”FILE_EVENT”,”investigation”:{“FILE_EVENT”:{“filter”:{“AND”:[{“SEARCH_FIELD”:”action_file_name”,”SEARCH_TYPE”:”EQ”,”SEARCH_VALUE”:”testfile.exe”}]}}}}’. For more information, refer to the documentation here. |
Required |
| mitre_technique_id_and_name | The MITRE technique ID and name. Must be in format ‘ID - Name’, for example: [‘T1566 - Phishing’]. | Optional |
| mitre_tactic_id_and_name | The MITRE tactic ID and name. Must be in format ‘ID - Name’, for example: [‘TA0001 - Initial Access’]. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.BIOC.rule_id | String | BIOC ID. |
xdr-bioc-update
Updates an existing BIOC.
Base Command
xdr-bioc-update
Input
| Argument Name | Description | Required |
|---|---|---|
| rule_id | BIOC rule ID. | Required |
| name | BIOC name. | Required |
| severity | BIOC severity. Possible values are: info, low, medium, high, critical. | Required |
| type | BIOC type. Possible values are: other, persistence, evasion, tampering, file_type_obfuscation, privilege_escalation, credential_access, lateral_movement, execution, collection, exfiltration, infiltration, dropper, file_privilege_manipulation, reconnaissance, discovery. | Optional |
| is_xql | Whether the BIOC is XQL. Possible values are: true, false. | Optional |
| comment | BIOC comment. | Optional |
| status | BIOC status. Possible values are: enabled, disabled. | Optional |
| indicator | The BIOC indicator, for example: ‘{“runOnCGO”:true,”investigationType”:”FILE_EVENT”,”investigation”:{“FILE_EVENT”:{“filter”:{“AND”:[{“SEARCH_FIELD”:”action_file_name”,”SEARCH_TYPE”:”EQ”,”SEARCH_VALUE”:”testfile.exe”}]}}}}’. For more information, refer to the documentation here. |
Required |
| mitre_technique_id_and_name | The MITRE technique ID and name. Must be in format ‘ID - Name’, for example: [‘T1566 - Phishing’]. | Optional |
| mitre_tactic_id_and_name | The MITRE tactic ID and name. Must be in format ‘ID - Name’, for example: [‘TA0001 - Initial Access’]. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.BIOC.rule_id | String | BIOC ID. |
xdr-bioc-delete
Deletes a BIOC.
Base Command
xdr-bioc-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| name | BIOC name. | Optional |
| severity | BIOC severity. Possible values are: info, low, medium, high, critical. | Optional |
| type | BIOC type. Possible values are: other, persistence, evasion, tampering, file_type_obfuscation, privilege_escalation, credential_access, lateral_movement, execution, collection, exfiltration, infiltration, dropper, file_privilege_manipulation, reconnaissance, discovery. | Optional |
| is_xql | Whether the BIOC is XQL. Possible values are: true, false. | Optional |
| comment | BIOC comment. | Optional |
| indicator | BIOC indicator. | Optional |
| mitre_technique_id_and_name | The MITRE technique ID and name. Must be in format ‘ID - Name’, for example: [‘T1566 - Phishing’]. | Optional |
| mitre_tactic_id_and_name | The MITRE tactic ID and name. Must be in format ‘ID - Name’, for example: [‘TA0001 - Initial Access’]. | Optional |
Context Output
There is no context output for this command.
xdr-correlation-rule-list
Returns a list of correlation rules.
Base Command
xdr-correlation-rule-list
Input
| Argument Name | Description | Required |
|---|---|---|
| name | Correlation rule name. | Optional |
| severity | Correlation rule severity. Possible values are: info, low, medium, high, critical. | Optional |
| xql_query | Correlation rule XQL query. | Optional |
| is_xql | Whether the correlation rule is XQL. Possible values are: true, false. | Optional |
| dataset | Correlation rule dataset. | Optional |
| alert_name | Alert name. | Optional |
| alert_category | Alert category. | Optional |
| alert_fields | Alert fields. Can be a string or a dictionary. | Optional |
| alert_domain | Alert domain. | Optional |
| filter_json | Filter JSON. | Optional |
| extra_data | Whether to return extended view. Possible values are: true, false. | Optional |
| limit | Maximum number of results to return. | Optional |
| page_size | Page size. | Optional |
| page | Page number. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.CorrelationRule.suppression_duration | String | The duration for which alerts are suppressed. |
| PaloAltoNetworksXDR.CorrelationRule.alert_category | String | The category of the alert (e.g., DROPPER). |
| PaloAltoNetworksXDR.CorrelationRule.mitre_defs | Unknown | MITRE ATT&CK definitions associated with the rule. |
| PaloAltoNetworksXDR.CorrelationRule.simple_schedule | String | The frequency at which the rule runs in a human-readable format. |
| PaloAltoNetworksXDR.CorrelationRule.mapping_strategy | String | The strategy used for field mapping. |
| PaloAltoNetworksXDR.CorrelationRule.suppression_fields | String | Fields used to determine alert suppression. |
| PaloAltoNetworksXDR.CorrelationRule.alert_domain | String | The security domain the alert belongs to. |
| PaloAltoNetworksXDR.CorrelationRule.crontab | String | The cron expression for the rule execution schedule. |
| PaloAltoNetworksXDR.CorrelationRule.search_window | String | The time window the query searches across. |
| PaloAltoNetworksXDR.CorrelationRule.user_defined_severity | String | Custom severity level defined by the user. |
| PaloAltoNetworksXDR.CorrelationRule.drilldown_query_timeframe | String | The timeframe used for drilldown queries. |
| PaloAltoNetworksXDR.CorrelationRule.user_defined_category | String | Custom category defined by the user. |
| PaloAltoNetworksXDR.CorrelationRule.lookup_mapping | String | Mapping details for lookups. |
| PaloAltoNetworksXDR.CorrelationRule.execution_mode | String | How the rule is executed, for example: SCHEDULED. |
| PaloAltoNetworksXDR.CorrelationRule.name | String | The name of the correlation rule. |
| PaloAltoNetworksXDR.CorrelationRule.is_enabled | Boolean | Whether the correlation rule is currently active. |
| PaloAltoNetworksXDR.CorrelationRule.investigation_query_link | String | The query used for further investigation. |
| PaloAltoNetworksXDR.CorrelationRule.alert_name | String | The specific name assigned to the generated alert. |
| PaloAltoNetworksXDR.CorrelationRule.suppression_enabled | Boolean | Whether suppression is enabled for this rule. |
| PaloAltoNetworksXDR.CorrelationRule.action | String | The action taken when the rule triggers, for example: ALERTS. |
| PaloAltoNetworksXDR.CorrelationRule.dataset | String | The dataset the rule queries. |
| PaloAltoNetworksXDR.CorrelationRule.alert_description | String | Detailed description of the generated alert. |
| PaloAltoNetworksXDR.CorrelationRule.timezone | String | The timezone used for the rule schedule. |
| PaloAltoNetworksXDR.CorrelationRule.xql_query | String | The XQL query string executed by the rule. |
| PaloAltoNetworksXDR.CorrelationRule.alert_fields | Unknown | Specific fields included in the alert output. |
| PaloAltoNetworksXDR.CorrelationRule.description | String | General description of the correlation rule. |
| PaloAltoNetworksXDR.CorrelationRule.alert_type | String | The type of alert generated. |
| PaloAltoNetworksXDR.CorrelationRule.severity | String | The severity level of the rule. |
| PaloAltoNetworksXDR.CorrelationRule.rule_id | Number | The unique identifier for the correlation rule. |
xdr-correlation-rule-create
Creates a new correlation rule.
Base Command
xdr-correlation-rule-create
Input
| Argument Name | Description | Required |
|---|---|---|
| name | The correlation rule name. | Required |
| severity | The correlation rule severity. Example: severity=low. Possible values are: info, low, medium, high, critical. | Required |
| xql_query | The correlation rule XQL query. Example: xql_query=”dataset = xdr_data | limit 1”. | Required |
| is_enabled | Whether the rule is enabled. Example: is_enabled=true. Possible values are: true, false. | Required |
| alert_category | The alert category. Example: alert_category=dropper. Possible values are: other, persistence, evasion, tampering, file_type_obfuscation, privilege_escalation, credential_access, lateral_movement, execution, collection, exfiltration, infiltration, dropper, file_privilege_manipulation, reconnaissance, discovery. | Required |
| execution_mode | The rule execution mode. Example: execution_mode=scheduled. Possible values are: scheduled, real_time. | Required |
| timezone | The correlation rule timezone. Example: timezone=”Asia/Jerusalem”. | Required |
| mapping_strategy | The rule mapping strategy. Example: mapping_strategy=auto. Possible values are: auto, custom. | Required |
| description | The correlation rule description. | Optional |
| alert_name | The alert name. | Optional |
| alert_description | The alert description. | Optional |
| alert_fields | Alert fields (string or dictionary). | Optional |
| search_window | The search window timeframe. Example: search_window=”1 hours”. | Optional |
| schedule | The correlation rule schedule. Example: schedule=”10 minutes”. | Optional |
| schedule_linux | Linux scheduling for the rule. Example: schedule_linux=”/10 ** *”. | Optional |
| suppression_enabled | Whether suppression is enabled. Possible values are: true, false. | Optional |
| suppression_duration | Duration of correlation rule suppression. | Optional |
| suppression_fields | Suppression fields. | Optional |
| dataset | The correlation rule dataset. Example: dataset=alerts. | Required |
| user_defined_severity | User-defined severity. | Optional |
| user_defined_category | User-defined category. | Optional |
| mitre_defs_json | MITRE definitions. For example: ‘{“TA0005 - Defense Evasion”: [“T1014 - Rootkit”]}’. | Optional |
| investigation_query_link | Investigation query link. | Optional |
| drilldown_query_timeframe | The drilldown query timeframe. Example: drilldown_query_timeframe=”ALERT”. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.CorrelationRule.rule_id | String | Correlation rule ID. |
xdr-correlation-rule-update
Updates an existing correlation rule.
Base Command
xdr-correlation-rule-update
Input
| Argument Name | Description | Required |
|---|---|---|
| rule_id | Correlation rule ID. | Required |
| name | The correlation rule name. | Required |
| severity | The correlation rule severity. Example: severity=low. Possible values are: info, low, medium, high, critical. | Required |
| xql_query | The correlation rule XQL query. Example: xql_query=”dataset = xdr_data | limit 1”. | Required |
| is_enabled | Whether the rule is enabled. Example: is_enabled=true. Possible values are: true, false. | Required |
| alert_category | The alert category. Example: alert_category=dropper. Possible values are: other, persistence, evasion, tampering, file_type_obfuscation, privilege_escalation, credential_access, lateral_movement, execution, collection, exfiltration, infiltration, dropper, file_privilege_manipulation, reconnaissance, discovery. | Required |
| execution_mode | The rule execution mode. Example: execution_mode=scheduled. Possible values are: scheduled, real_time. | Required |
| timezone | The correlation rule timezone. Example: timezone=”Asia/Jerusalem”. | Required |
| mapping_strategy | The rule mapping strategy. Example: mapping_strategy=auto. Possible values are: auto, custom. | Required |
| description | The correlation rule description. | Optional |
| alert_name | The alert name. | Optional |
| alert_description | The alert description. | Optional |
| alert_fields | Alert fields (string or dictionary). | Optional |
| search_window | The search window timeframe. Example: search_window=”1 hours”. | Optional |
| schedule | The correlation rule schedule. Example: schedule=”10 minutes”. | Optional |
| schedule_linux | Linux scheduling for the rule. Example: schedule_linux=”/10 ** *”. | Optional |
| suppression_enabled | Whether suppression is enabled. Possible values are: true, false. | Optional |
| suppression_duration | Duration of correlation rule suppression. | Optional |
| suppression_fields | Suppression fields. | Optional |
| dataset | The correlation rule dataset. Example: dataset=alerts. | Required |
| user_defined_severity | User-defined severity. | Optional |
| user_defined_category | User-defined category. | Optional |
| mitre_defs_json | MITRE definitions. For example: ‘{“TA0005 - Defense Evasion”: [“T1014 - Rootkit”]}’. | Optional |
| investigation_query_link | Investigation query link. | Optional |
| drilldown_query_timeframe | The drilldown query timeframe. Example: drilldown_query_timeframe=”ALERT”. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.CorrelationRule.rule_id | String | Correlation rule ID. |
xdr-correlation-rule-delete
Deletes correlation rules.
Base Command
xdr-correlation-rule-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| rule_id | Correlation rule ID. | Required |
Context Output
There is no context output for this command.
xdr-case-list
Returns a list of cases based on the specified filters.
Base Command
xdr-case-list
Input
| Argument Name | Description | Required |
|---|---|---|
| case_id | A comma-separated list of case IDs to filter by. | Optional |
| case_domain | A comma-separated list of case domains to filter by. Note: this filter is not applied when extra_data is set to true. | Optional |
| severity | A comma-separated list of severities to filter by. Note: this filter is not applied when extra_data is set to true. | Optional |
| created_before | Filters cases that were created before this date. Supports natural language expressions such as “one year”. | Optional |
| created_after | Filters cases that were created after this date. Supports natural language expressions such as “one year”. | Optional |
| status | A comma-separated list of statuses to filter by. | Optional |
| sort_field | The field by which to sort the results. Note: sorting by severity is not supported when extra_data is set to true. Possible values are: case_id, severity, creation_time. | Optional |
| sort_order | The order in which to sort the results. Possible values are: asc, desc. | Optional |
| limit | Maximum number of cases to return. | Optional |
| page_size | Page size for pagination. | Optional |
| page | Page number for pagination. | Optional |
| extra_data | Whether to retrieve extra case data including the associated issues, file artifacts, and network artifacts for each case. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Case.case_id | String | The unique identifier of the case. |
| PaloAltoNetworksXDR.Case.case_name | String | The name of the case. |
| PaloAltoNetworksXDR.Case.severity | String | The severity of the case. |
| PaloAltoNetworksXDR.Case.creation_time | String | The creation time of the case. |
| PaloAltoNetworksXDR.Case.modification_time | String | The modification time of the case. |
| PaloAltoNetworksXDR.Case.status_progress | String | The progress status of the case (e.g., New, Under Investigation). |
| PaloAltoNetworksXDR.Case.description | String | A detailed description of the case and involved entities. |
| PaloAltoNetworksXDR.Case.low_severity_issue_count | Number | The number of low severity issues associated with the case. |
| PaloAltoNetworksXDR.Case.med_severity_issue_count | Number | The number of medium severity issues associated with the case. |
| PaloAltoNetworksXDR.Case.case_domain | String | The security domain of the case. |
| PaloAltoNetworksXDR.Case.xdr_url | String | The direct URL to the incident view in the XDR console. |
| PaloAltoNetworksXDR.Case.is_blocked | Boolean | Indicates if the threat was blocked. |
| PaloAltoNetworksXDR.Case.aggregated_score | Number | The overall risk score calculated for the case. |
| PaloAltoNetworksXDR.Case.host_count | Number | The number of hosts involved in the case. |
| PaloAltoNetworksXDR.Case.user_count | Number | The number of users involved in the case. |
| PaloAltoNetworksXDR.Case.wildfire_hits | Number | The number of WildFire malware hits associated with the case. |
| PaloAltoNetworksXDR.Case.tags | String | A list of tags associated with the case. |
| PaloAltoNetworksXDR.Case.starred | Boolean | Whether the case has been starred/flagged. |
| PaloAltoNetworksXDR.Case.high_severity_issue_count | Number | The number of high-severity issues associated with the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.critical_severity_issue_count | Number | The number of critical-severity issues associated with the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.resolved_timestamp | String | The time the case was resolved. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.assigned_user_mail | String | The email address of the user assigned to the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.assigned_user_pretty_name | String | The display name of the user assigned to the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.hosts | String | The hosts involved in the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.users | String | The users involved in the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.mitre_tactics_ids_and_names | String | The MITRE ATT&CK tactics associated with the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.mitre_techniques_ids_and_names | String | The MITRE ATT&CK techniques associated with the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.issue_categories | String | The categories of the issues associated with the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.resolve_comment | String | The comment provided when the case was resolved. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.notes | String | Notes associated with the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.manual_severity | String | The severity manually set for the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.manual_description | String | The description manually set for the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.rule_based_score | Number | The rule-based risk score of the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.predicted_score | Number | The predicted risk score of the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.issue_count | Number | The total number of issues associated with the case. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.issue_id | String | The unique identifier of the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.case_id | String | The identifier of the case the issue belongs to. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.detection_timestamp | Number | The detection time of the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.name | String | The name of the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.category | String | The category of the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.severity | String | The severity of the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.source | String | The source of the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.action | String | The action taken for the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.action_pretty | String | The human-readable action taken for the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.host_ip | String | The host IP addresses associated with the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.host_name | String | The host name associated with the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.user_name | String | The user name associated with the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.action_file_name | String | The file name involved in the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.action_file_path | String | The file path involved in the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.mitre_tactic_id_and_name | String | The MITRE ATT&CK tactic associated with the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.Issues.mitre_technique_id_and_name | String | The MITRE ATT&CK technique associated with the issue. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.case_id | String | The identifier of the case associated with the file artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.type | String | The type of the file artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.file_name | String | The name of the file. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.file_sha256 | String | The SHA256 hash of the file. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.file_wildfire_verdict | String | The WildFire verdict for the file. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.is_malicious | Boolean | Whether the file has been identified as malicious. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.is_process | Boolean | Whether the file was a running process. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.is_manual | Boolean | Whether the file artifact was added manually. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.file_signature_vendor_name | String | The vendor name from the file signature. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.file_signature_status | String | The status of the file digital signature. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.FileArtifacts.alert_count | Number | The number of issues associated with the file artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.NetworkArtifacts.case_id | String | The identifier of the case associated with the network artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.NetworkArtifacts.type | String | The type of the network artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.NetworkArtifacts.network_remote_ip | String | The remote IP address associated with the network artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.NetworkArtifacts.network_remote_port | Number | The remote port associated with the network artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.NetworkArtifacts.network_domain | String | The domain associated with the network artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.NetworkArtifacts.network_country | String | The country associated with the network artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.NetworkArtifacts.alert_count | Number | The number of issues associated with the network artifact. Returned when extra_data is set to true. |
| PaloAltoNetworksXDR.Case.NetworkArtifacts.is_manual | Boolean | Whether the network artifact was added manually. Returned when extra_data is set to true. |
xdr-case-update
Updates an existing case with the specified details.
Base Command
xdr-case-update
Input
| Argument Name | Description | Required |
|---|---|---|
| case_id | The ID of the case to update. | Required |
| status | The status to set for the case. When set to “resolved”, the resolve_reason argument is required. Possible values are: new, under_investigation, resolved. | Optional |
| resolve_reason | The reason for resolving the case. Can only be provided when the status is set to “resolved”, and is required when resolving. Possible values are: resolved_known_issue, resolved_duplicate, resolved_false_positive, resolved_true_positive, resolved_security_testing, resolved_other. | Optional |
| resolve_comment | A free-text comment explaining the resolution. Can only be provided when the status is set to “resolved”. | Optional |
| user_severity | The user-defined severity to set for the case. Provide an empty string to clear the severity. Possible values are: low, medium, high, critical. | Optional |
| assigned_user | A valid Cortex XDR user email address to assign the case to. | Optional |
| notes | A free-text note for the case, used for operational or intermediate comments (e.g., a ServiceNow Ticket ID). | Optional |
| custom_fields | A JSON object string of tenant-defined custom fields to update on the case. The keys must be the exact custom field names as configured in your Cortex XDR tenant, and the values must match each field’s configuration. Ensure the custom field names are valid for the tenant; the integration only validates that the input is valid JSON. Example: {"my_custom_field": "value", "another_field": 42}. |
Optional |
Context Output
There is no context output for this command.
xdr-case-artifact-list
Retrieves a list of artifacts for a specific case.
Base Command
xdr-case-artifact-list
Input
| Argument Name | Description | Required |
|---|---|---|
| case_id | The ID of the case for which to retrieve artifacts. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.CaseNetworkArtifact.case_id | String | The ID of the case associated with the network artifact. |
| PaloAltoNetworksXDR.CaseNetworkArtifact.network_remote_ip | String | The remote IP address associated with the artifact. |
| PaloAltoNetworksXDR.CaseNetworkArtifact.network_remote_port | Number | The remote port used in the network connection. |
| PaloAltoNetworksXDR.CaseNetworkArtifact.alert_count | Number | Number of alerts associated with this network artifact. |
| PaloAltoNetworksXDR.CaseNetworkArtifact.type | String | The type of network artifact (e.g., IP). |
| PaloAltoNetworksXDR.CaseNetworkArtifact.is_manual | Boolean | Indicates if the artifact was added manually. |
| PaloAltoNetworksXDR.CaseFileArtifact.case_id | String | The ID of the case associated with the file artifact. |
| PaloAltoNetworksXDR.CaseFileArtifact.file_name | String | The name of the file. |
| PaloAltoNetworksXDR.CaseFileArtifact.file_sha256 | String | The SHA256 hash of the file. |
| PaloAltoNetworksXDR.CaseFileArtifact.file_wildfire_verdict | String | The verdict from WildFire (e.g., MALWARE, BENIGN). |
| PaloAltoNetworksXDR.CaseFileArtifact.is_malicious | Boolean | Whether the file has been identified as malicious. |
| PaloAltoNetworksXDR.CaseFileArtifact.is_process | Boolean | Indicates if the file was a running process. |
| PaloAltoNetworksXDR.CaseFileArtifact.file_signature_vendor_name | String | The vendor name from the file signature. |
| PaloAltoNetworksXDR.CaseFileArtifact.file_signature_status | String | The status of the digital signature (e.g., SIGNATURE_SIGNED). |
| PaloAltoNetworksXDR.CaseFileArtifact.alert_count | Number | Number of alerts associated with this file artifact. |
| PaloAltoNetworksXDR.CaseFileArtifact.low_confidence | Boolean | Indicates if the detection confidence is low. |
xdr-automation-playbook-create
Creates or updates an automation playbook.
Base Command
xdr-automation-playbook-create
Input
| Argument Name | Description | Required |
|---|---|---|
| entry_id | The entry ID of the file. The playbook should be a zipped YAML file. | Required |
Context Output
There is no context output for this command.
xdr-automation-playbook-get
Gets an automation playbook.
Base Command
xdr-automation-playbook-get
Input
| Argument Name | Description | Required |
|---|---|---|
| field | The field to search by. Possible values are: id, name. | Required |
| value | The field value to search for. | Required |
Context Output
There is no context output for this command.
xdr-automation-playbook-delete
Deletes an automation playbook.
Base Command
xdr-automation-playbook-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| field | The field to search by. Possible values are: id, name. | Required |
| value | The field value to search for. | Required |
Context Output
There is no context output for this command.
xdr-automation-script-delete
Deletes an automation script.
Base Command
xdr-automation-script-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| field | The field to search by. Possible values are: id, name. | Required |
| value | The field value to search for. | Required |
Context Output
There is no context output for this command.
xdr-automation-script-get
Gets an automation script.
Base Command
xdr-automation-script-get
Input
| Argument Name | Description | Required |
|---|---|---|
| field | The field to search by. Possible values are: id, name. | Required |
| value | The field value to search for. | Required |
Context Output
There is no context output for this command.
xdr-automation-script-create
Creates or updates an automation script.
Base Command
xdr-automation-script-create
Input
| Argument Name | Description | Required |
|---|---|---|
| entry_id | The entry ID of the file. The script should be a zipped YAML file. | Required |
Context Output
There is no context output for this command.
xdr-vulnerability-details-get
Gets vulnerability details by ID.
Base Command
xdr-vulnerability-details-get
Input
| Argument Name | Description | Required |
|---|---|---|
| vulnerability_id | The vulnerability ID to retrieve details for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Vulnerability.vulnerabilityID | String | The unique identifier (CVE ID). |
| PaloAltoNetworksXDR.Vulnerability.description | String | Detailed description of the vulnerability. |
| PaloAltoNetworksXDR.Vulnerability.publishedDate | Number | The date the vulnerability was first published. |
| PaloAltoNetworksXDR.Vulnerability.epss_score | Number | The Probability of exploitability (0-1). |
| PaloAltoNetworksXDR.Vulnerability.exploitDetails.exploitMaturity | String | Current state of exploit availability (e.g., weaponized). |
| PaloAltoNetworksXDR.Vulnerability.exploitDetails.weaponizedExploitFound | Boolean | Whether a functional exploit exists in the wild. |
| PaloAltoNetworksXDR.Vulnerability.exploitDetails.reportedExploited | Boolean | Whether the vulnerability has been actively exploited. |
| PaloAltoNetworksXDR.Vulnerability.exploitDetails.reportedExploitedByThreatActors | Boolean | Whether known threat actors are exploiting this vulnerability. |
| PaloAltoNetworksXDR.Vulnerability.exploitDetails.reportedExploitedByRansomware | Boolean | Whether the vulnerability is used in ransomware campaigns. |
| PaloAltoNetworksXDR.Vulnerability.exploitDetails.reportedExploitedByBotnets | Boolean | Whether the vulnerability is being leveraged by botnet clusters. |
| PaloAltoNetworksXDR.Vulnerability.exploitDetails.firstReportedThreatActor | Number | The timestamp of the first recorded threat actor activity. |
| PaloAltoNetworksXDR.Vulnerability.exploitDetails.mostRecentReportedThreatActor | Number | The timestamp of the last recorded threat actor activity. |
| PaloAltoNetworksXDR.Vulnerability.cisaKevDateDue | Number | The deadline set by CISA for federal agency remediation. |
| PaloAltoNetworksXDR.Vulnerability.weaknesses.cweId | String | The Common Weakness Enumeration ID. |
| PaloAltoNetworksXDR.Vulnerability.vulncheck-threat-actors | String | A list of specific threat actor groups associated with the vulnerability. |
xdr-healthcheck-run
Runs a system health check on the Cortex XDR environment.
Base Command
xdr-healthcheck-run
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.HealthStatus.status | String | The health status of the Cortex XDR system. |
xdr-endpoint-triage-preset-list
Gets a list of available triage presets.
Base Command
xdr-endpoint-triage-preset-list
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.EndpointTriagePreset.created_by | String | The user or system entity that created the triage preset. |
| PaloAltoNetworksXDR.EndpointTriagePreset.description | String | A brief explanation of the preset’s purpose or contents. |
| PaloAltoNetworksXDR.EndpointTriagePreset.name | String | The unique display name of the triage preset. |
| PaloAltoNetworksXDR.EndpointTriagePreset.os | String | The operating system platform the preset targets (e.g., windows, linux, macos). |
| PaloAltoNetworksXDR.EndpointTriagePreset.type | String | The category or classification of the preset (e.g., standard, custom). |
| PaloAltoNetworksXDR.EndpointTriagePreset.uuid | String | The unique universal identifier (UUID) assigned to this specific preset. |
xdr-endpoint-triage
Initiates a forensics triage on the specified endpoints. You must have Cortex XDR with the Forensics add-on. The agent also must have the Forensics License enabled.
Base Command
xdr-endpoint-triage
Input
| Argument Name | Description | Required |
|---|---|---|
| endpoint_id | A comma-separated list of endpoint IDs to initiate triage on. You can find the endpoint ID under the “Inventory” section, under “All Endpoints”. | Required |
| collector_uuid | The collector UUID to use for the triage. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.EndpointTriage.TRIAGE_ID | String | The unique identifier assigned to the created triage action. |
| PaloAltoNetworksXDR.EndpointTriage.SUCCESSFUL_AGENT_IDS | Array | A list of agent IDs where the triage action was successfully initiated. |
| PaloAltoNetworksXDR.EndpointTriage.UNSUCCESSFUL_AGENT_IDS | Array | A list of agent IDs where the triage action failed to initiate. |
xdr-issue-list
Retrieve issues based on filters. Issues with an ‘INFO’ severity level are filtered out.
Base Command
xdr-issue-list
Input
| Argument Name | Description | Required |
|---|---|---|
| issue_id | A comma-separated list of issue IDs. | Optional |
| external_id | A comma-separated list of external IDs. | Optional |
| detection_method | A comma-separated list of methods used to detect the activity. Possible values: ‘BIOC’, ‘Correlation’, ‘Analytics’, ‘System’, ‘IOC’. Possible values are: BIOC, Correlation, Analytics, System, IOC. | Optional |
| domain | A comma-separated list of domains. | Optional |
| severity | A comma-separated list of severities. Possible values: ‘critical’, ‘high’, ‘medium’, ‘low’, ‘info’. Possible values are: info, low, medium, high, critical. | Optional |
| insert_time | Filter by issues inserted after this time. | Optional |
| status | A comma-separated list of statuses. Possible values: ‘New’, ‘In Progress’, ‘Resolved’. Possible values are: New, In Progress, Resolved. | Optional |
| sort_field | The field to sort by. Possible values are: issue_id, severity, observation_time. | Optional |
| sort_order | The sort order. Possible values are: asc, desc. | Optional |
| limit | The maximum number of results to return. | Optional |
| page_size | The page size. | Optional |
| page | The page number. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Issue.observation_time | Number | The timestamp when the observation occurred. |
| PaloAltoNetworksXDR.Issue.domain | String | The security domain associated with the observation. |
| PaloAltoNetworksXDR.Issue.remediation | String | Suggested remediation steps. |
| PaloAltoNetworksXDR.Issue.impact | String | The potential impact of the observed activity. |
| PaloAltoNetworksXDR.Issue.status | String | The current progress status (e.g., New). |
| PaloAltoNetworksXDR.Issue.status_resolution_comment | String | Comments regarding the resolution of the status. |
| PaloAltoNetworksXDR.Issue.status_progress | String | The current progress status (e.g., New). |
| PaloAltoNetworksXDR.Issue.asset_ids | String | List of asset IDs involved. |
| PaloAltoNetworksXDR.Issue.assigned_to_pretty | String | The display name of the user assigned to this item. |
| PaloAltoNetworksXDR.Issue.last_update_timestamp | Number | The last time this record was updated. |
| PaloAltoNetworksXDR.Issue.detection_method | String | The method used to detect the activity (e.g., BIOC). |
| PaloAltoNetworksXDR.Issue.is_starred | Boolean | Whether the item has been starred/flagged. |
| PaloAltoNetworksXDR.Issue.name | String | The name of the observation or alert. |
| PaloAltoNetworksXDR.Issue.external_id | String | The unique UUID for external reference. |
| PaloAltoNetworksXDR.Issue.insert_time | Number | The time the record was inserted into the database. |
| PaloAltoNetworksXDR.Issue.detection_rule_id | String | The ID of the specific detection rule triggered. |
| PaloAltoNetworksXDR.Issue.tags | String | A list of tags associated with the observation. |
| PaloAltoNetworksXDR.Issue.type | String | The classification type of the observation. |
| PaloAltoNetworksXDR.Issue.id | Number | The numeric ID of the observation. |
| PaloAltoNetworksXDR.Issue.description | String | Detailed description of the observed activity. |
| PaloAltoNetworksXDR.Issue.severity | String | The severity level (e.g., LOW). |
| PaloAltoNetworksXDR.Issue.category | String | The category classification. |
| PaloAltoNetworksXDR.Issue.is_excluded | Boolean | Whether this observation is excluded from standard views. |
xdr-issue-create
Creates a new issue. Issues with an ‘INFO’ severity level are not displayed in the UI.
Base Command
xdr-issue-create
Input
| Argument Name | Description | Required |
|---|---|---|
| name | The issue name. | Required |
| description | The issue description. | Required |
| observation_time | The observation time. Should support english expressions like “one year”. | Required |
| domain | The domain. | Required |
| category | The category. | Required |
| asset_id | A comma-separated list of asset IDs. | Optional |
| mitre_tactic | A comma-separated list of MITRE tactics. | Optional |
| mitre_technique | A comma-separated list of MITRE techniques. | Optional |
| type | The issue type. | Optional |
| extended_description | The extended description. | Optional |
| impact | The impact. | Optional |
| tags | A comma-separated list of tags. | Optional |
| is_excluded | Whether the issue is excluded. Possible values are: true, false. | Optional |
| is_starred | Whether the issue is starred. Possible values are: true, false. | Optional |
| assigned_to | The user assigned to the issue. | Optional |
| assigned_to_pretty | The pretty name of the user assigned to the issue. | Optional |
| severity | The severity. Possible values are: critical, info, low, medium, high. | Required |
| normalized_fields_json | The JSON to add to the “normalized_fields” field in the API. | Optional |
| custom_fields_json | The JSON to add to the “custom_fields” field in the API. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PaloAltoNetworksXDR.Issue.external_id | String | The issue external ID. |
| PaloAltoNetworksXDR.Issue.detection_method | String | The issue detection method. |
xdr-issue-update
Updates an existing issue.
Base Command
xdr-issue-update
Input
| Argument Name | Description | Required |
|---|---|---|
| issue_id | The issue ID. | Required |
| severity | The severity. Possible values are: critical, info, low, medium, high. | Optional |
| status | The status. Possible values are: new, in_progress, resolved. | Optional |
| resolve_reason | The resolve reason. Possible values are: resolved_threat_handled, resolved_known_issue, resolved_duplicate, resolved_false_positive, resolved_other, resolved_true_positive, resolved_security_testing. | Optional |
| resolve_comment | The resolve comment. | Optional |
Context Output
There is no context output for this command.
Configuration parameters
isFetch— Fetch incidentsincidentFetchInterval— Incidents Fetch IntervalincidentType— Incident typeurl— Server URL (copy URL from XDR) (required)apikey_id_creds—apikey_creds—dont_format_sublists— Remove legacy incident fieldsmirror_direction— Incident Mirroring Directionclose_xsoar_incident— Close Mirrored XSOAR Incidentclose_xdr_incident— Close Mirrored Cortex XDR Incidentxdr_delay— XDR mirroring delay in minutescustom_xsoar_to_xdr_close_reason_mapping— Custom close-reason mapping (XSOAR -> XDR mirrored incident. Overwrites default close-reason mapping defined by Cortex XSOAR)custom_xdr_to_xsoar_close_reason_mapping— Custom close-reason mapping (XDR -> XSOAR mirrored incident. Overwrites default close-reason mapping defined by Cortex XSOAR)apikey_id— API Key IDapikey— API Keytimeout— HTTP Timeoutmax_fetch— Maximum number of incidents per fetchstarred— Only fetch starred incidentsstarred_incidents_fetch_window— Starred incidents fetch windowfetch_time— First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days)sync_owners— Sync Incident Ownersinsecure— Trust any certificate (not secure)proxy— Use system proxy settingsprevent_only— Prevent Only Modestatus— Incident Statuses to Fetchexclude_fields— Minimize Incident Informationexcluded_alert_fields— Minimize Alert Informationclose_alerts_in_xdr— Close all related alerts in XDR
Commands (109)
-
endpointReturns information about an endpoint.
-
get-mapping-fieldsGets mapping fields from remote incident. Note: This method will not update the current incident. It's here for debugging purposes.
-
get-modified-remote-dataGets the list of incidents that were modified since the last update. Note: This method is here for debugging purposes. get-modified-remote-data is used as part of a Mirroring feature, which is available since version 6.1.
-
get-remote-dataGets remote data from a remote incident. Note: This method will not update the current incident. It's here for debugging purposes.
-
xdr-action-status-getRetrieves the status of the requested actions according to the action ID.
-
xdr-allowlist-filesAdds requested files to the allow list if they are not already on the block list or allow list.
-
xdr-api-key-deleteDeletes the specified API keys.
-
xdr-api-key-listGets a list of existing API keys.
-
xdr-asset-group-createCreates an asset group.
-
xdr-asset-group-deleteDeletes an asset group.
-
xdr-asset-group-listReturns a list of asset groups.
-
xdr-asset-group-updateUpdates an asset group.
-
xdr-asset-listReturns a list of assets.
-
xdr-asset-schema-field-options-getGets the enum values of a specified field in the asset schema.
-
xdr-asset-schema-getGets the schema of the asset inventory.
-
xdr-automation-playbook-createCreates or updates an automation playbook.
-
xdr-automation-playbook-deleteDeletes an automation playbook.
-
xdr-automation-playbook-getGets an automation playbook.
-
xdr-automation-script-createCreates or updates an automation script.
-
xdr-automation-script-deleteDeletes an automation script.
-
xdr-automation-script-getGets an automation script.
-
xdr-bioc-createCreates a new BIOC.
-
xdr-bioc-deleteDeletes a BIOC.
-
xdr-bioc-listReturns a list of BIOCs.
-
xdr-bioc-updateUpdates an existing BIOC.
-
xdr-blacklist-filesDeprecatedDeprecated. Use `xdr-blocklist-files` instead.
-
xdr-blocklist-filesBlock lists requested files which have not already been block listed or added to allow lists.
-
xdr-case-artifact-listRetrieves a list of artifacts for a specific case.
-
xdr-case-listReturns a list of cases based on the specified filters.
-
xdr-case-updateUpdates an existing case with the specified details.
-
xdr-correlation-rule-createCreates a new correlation rule.
-
xdr-correlation-rule-deleteDeletes correlation rules.
-
xdr-correlation-rule-listReturns a list of correlation rules.
-
xdr-correlation-rule-updateUpdates an existing correlation rule.
-
xdr-create-distributionCreates an installation package. This is an asynchronous call that returns the distribution ID. This does not mean that the creation succeeded. To confirm that the package has been created, check the status of the distribution by running the Get Distribution Status API.
-
xdr-delete-endpointsDeletes selected endpoints in the Cortex XDR app. You can delete up to 1000 endpoints.
-
xdr-endpoint-alias-changeGets a list of endpoints according to the passed filters, and changes their alias name. Filtering by multiple fields will be concatenated using the AND condition (OR is not supported).
-
xdr-endpoint-isolateIsolates the specified endpoint.
-
xdr-endpoint-scanDeprecatedDeprecated. Use `xdr-endpoint-scan-execute` instead.
-
xdr-endpoint-scan-abortCancels the scan of selected endpoints. A scan can only be aborted if the selected endpoints are Pending or In Progress. To scan all endpoints, run the command with the argument all=true. Note that scanning all of the endpoints may cause performance issues and latency.
-
xdr-endpoint-scan-executeRuns a scan on a selected endpoint. To scan all endpoints, run this command with argument all=true. Note: Scanning all the endpoints may cause performance issues and latency.
-
xdr-endpoint-tag-addAdds a tag to specified endpoint_ids.
-
xdr-endpoint-tag-removeRemoves a tag from specified endpoint_ids.
-
xdr-endpoint-triageInitiates a forensics triage on the specified endpoints. You must have Cortex XDR with the Forensics add-on. The agent also must have the Forensics License enabled.
-
xdr-endpoint-triage-preset-listGets a list of available triage presets.
-
xdr-endpoint-unisolateReverses the isolation of an endpoint.
-
xdr-file-delete-script-executeInitiates a new endpoint script execution to delete the specified file.
-
xdr-file-exist-script-executeInitiates a new endpoint script execution to check if the file exists.
-
xdr-file-quarantineQuarantines a file on selected endpoints. You can select up to 1000 endpoints.
-
xdr-file-restoreRestores a quarantined file on requested endpoints.
-
xdr-file-retrieveRetrieves files from selected endpoints. You can retrieve up to 20 files, from no more than 10 endpoints. At least one endpoint ID and one file path are necessary in order to run the command. After running this command, you can use the xdr-action-status-get command with returned action_id, to check the action status.
-
xdr-get-alertsDeprecatedThis command is deprecated, please use xdr-issue-list instead. Returns a list of alerts and their metadata, which you can filter by built-in arguments or use the custom_filter to input a JSON filter object. Multiple filter arguments will be concatenated using the AND operator, while arguments that support a comma-separated list of values will use an OR operator between each value.
-
xdr-get-audit-agent-reportsGets agent event reports. You can filter by multiple fields, which will be concatenated using the AND condition (OR is not supported). Maximum result set size is 100. Offset is the zero-based number of reports from the start of the result set (start by counting from 0).
-
xdr-get-audit-management-logsGets management logs. You can filter by multiple fields, which will be concatenated using the AND condition (OR is not supported). Maximum result set size is 100. Offset is the zero-based number of management logs from the start of the result set (start by counting from 0).
-
xdr-get-cloud-original-alertsDeprecatedThis command is deprecated. Returns information about each alert ID.
-
xdr-get-contributing-eventRetrieves contributing events for a specific correlation alert.
-
xdr-get-create-distribution-statusGets the status of the installation package.
-
xdr-get-distribution-urlGets the distribution URL for downloading the installation package.
-
xdr-get-distribution-versionsGets a list of all the agent versions to use for creating a distribution list.
-
xdr-get-endpoint-device-control-violationsGets a list of device control violations filtered by selected fields. You can retrieve up to 100 violations.
-
xdr-get-endpointsGets a list of endpoints, according to the passed filters. If there are no filters, all endpoints are returned. Filtering by multiple fields will be concatenated using AND condition (OR is not supported). Maximum result set size is 100. Offset is the zero-based number of endpoint from the start of the result set. (Start by counting from 0).
-
xdr-get-endpoints-by-statusReturns the number of the connected\disconnected endpoints.
-
xdr-get-incident-extra-dataDeprecatedThis command is deprecated. Use "xdr-case-list extra_data=true" instead. Returns additional data for the specified incident, for example, related alerts, file artifacts, network artifacts, and so on.
-
xdr-get-incidentsDeprecatedThis command is deprecated please use xdr-case-list instead. Returns a list of incidents, which you can filter by a list of incident IDs (max. 100), the time the incident was last modified, and the time the incident was created. If you pass multiple filtering arguments, they will be concatenated using the AND condition. The OR condition is not supported.
-
xdr-get-policyGets the policy name for a specific endpoint.
-
xdr-get-quarantine-statusRetrieves the quarantine status for a selected file.
-
xdr-get-script-codeGets the code of a specific script in the script library.
-
xdr-get-script-execution-result-filesGets the files retrieved from a specific endpoint during a script execution.
-
xdr-get-script-execution-resultsRetrieve the results of a script execution action.
-
xdr-get-script-execution-statusRetrieves the status of a script execution action.
-
xdr-get-script-metadataGets the full definition of a specific script in the scripts library.
-
xdr-get-scriptsGets a list of scripts available in the scripts library.
-
xdr-get-tenant-infoProvides information about the tenant.
-
xdr-healthcheck-runRuns a system health check on the Cortex XDR environment.
-
xdr-insert-cef-alertsDeprecatedThis command is deprecated. Upload alerts in CEF format from external alert sources. After you map CEF alert fields to Cortex XDR fields, Cortex XDR displays the alerts in related incidents and views. You can send 600 requests per minute. Each request can contain a maximum of 60 alerts.
-
xdr-insert-parsed-alertDeprecatedThis command is deprecated. Uploads an alert from external alert sources in Cortex XDR format. Cortex XDR displays alerts that are parsed successfully in related incidents and views. You can send 600 alerts per minute. Each request can contain a maximum of 60 alerts.
-
xdr-isolate-endpointDeprecatedDeprecated. Use `xdr-endpoint-isolate` instead.
-
xdr-issue-createCreates a new issue. Issues with an 'INFO' severity level are not displayed in the UI.
-
xdr-issue-listRetrieve issues based on filters. Issues with an 'INFO' severity level are filtered out.
-
xdr-issue-updateUpdates an existing issue.
-
xdr-kill-process-script-executeInitiates a new endpoint script execution kill process.
-
xdr-list-risky-hostsRetrieve the risk score of a specific host or list of hosts with the highest risk score in the environment along with the reason affecting each score.
-
xdr-list-risky-usersRetrieve the risk score of a specific user or list of users with the highest risk score in the environment along with the reason affecting each score.
-
xdr-list-rolesRetrieve information about one or more roles created in the environment.
-
xdr-list-user-groupsRetrieve a list of the current user emails associated with one or more user groups in the environment.
-
xdr-list-usersRetrieve a list of the current users in the environment.
-
xdr-quarantine-filesDeprecatedDeprecated. Use `xdr-file-quarantine` instead.
-
xdr-remove-allowlist-filesRemoves requested files from allow list.
-
xdr-remove-blocklist-filesRemoves requested files from the block list.
-
xdr-remove-user-roleRemove one or more users from a role.
-
xdr-replace-featured-fieldReplace the featured hosts\users\IP addresses\active directory groups listed in your environment.
-
xdr-restore-fileDeprecatedDeprecated. Use `xdr-file-restore` instead.
-
xdr-retrieve-file-detailsView the file retrieved by the xdr-retrieve-files command according to the action ID. Before running this command, you can use the xdr-action-status-get command to check if this action completed successfully.
-
xdr-retrieve-filesDeprecatedDeprecated. Use `xdr-file-retrieve` instead.
-
xdr-run-scriptDeprecatedDeprecated. Run xdr-script-run instead.
-
xdr-run-script-delete-fileDeprecatedDeprecated. Use `xdr-file-delete-script-execute` instead.
-
xdr-run-script-execute-commandsDeprecatedDeprecated. Use `xdr-script-commands-execute` instead.
-
xdr-run-script-file-existsDeprecatedDeprecated. Use `xdr-file-exist-script-execute` instead.
-
xdr-run-script-kill-processDeprecatedDeprecated. Use `xdr-kill-process-script-execute` instead.
-
xdr-run-snippet-code-scriptDeprecatedDeprecated. Use `xdr-snippet-code-script-execute` instead.
-
xdr-script-commands-executeInitiates a new endpoint script execution of shell commands.
-
xdr-script-runInitiates a new endpoint script execution action using a script from the script library and returns the results.
-
xdr-set-user-roleAdd one or more users to a role.
-
xdr-snippet-code-script-executeInitiates a new endpoint script execution action using the provided snippet code.
-
xdr-unisolate-endpointDeprecatedDeprecated. Use `xdr-endpoint-unisolate` instead.
-
xdr-update-alertDeprecatedThis command is deprecated, please use xdr-issue-update instead. Update one or more alerts with the provided arguments. Required license: Cortex XDR Prevent, Cortex XDR Pro per Endpoint, or Cortex XDR Pro per GB.
-
xdr-update-incidentDeprecatedThis command is deprecated please use xdr-case-update instead. Updates one or more fields of a specified incident. Missing fields will be ignored. To remove the assignment for an incident, pass a null value in the assignee email argument.
-
xdr-vulnerability-details-getGets vulnerability details by ID.
-
xdr-whitelist-filesDeprecatedDeprecated. Use `xdr-allowlist-files` instead.
import copy import json from unittest.mock import MagicMock, patch import demistomock as demisto import pytest from CommonServerPython import CommandResults, DemistoException, urljoin from CoreIRApiModule import XDR_RESOLVED_STATUS_TO_XSOAR, XSOAR_RESOLVED_STATUS_TO_XDR from CortexXDRIR import XDR_OPEN_STATUS_TO_XSOAR, XDR_TO_XSOAR, XSOAR_TO_XDR, get_xsoar_close_reasons from freezegun import freeze_time XDR_URL = "https://api.xdrurl.com" """ HELPER FUNCTIONS """ def load_test_data(json_path): with open(json_path) as f: return json.load(f) def get_incident_by_status( incident_id_list=None, lte_modification_time=None, gte_modification_time=None, lte_creation_time=None, gte_creation_time=None, starred=None, starred_incidents_fetch_window=None, statuses=None, sort_by_modification_time=None, sort_by_creation_time=None, page_number=0, limit=100, gte_creation_time_milliseconds=0, ): """ The function simulate the client.get_incidents method for the test_fetch_incidents_filtered_by_status and for the test_get_incident_list_by_status. The function got the status as a string, and return from the json file only the incidents that are in the given status. """ incidents_list = load_test_data("./test_data/get_incidents_list.json")["reply"]["incidents"] return [incident for incident in incidents_list if incident["status"] in statuses] def get_incident_extra_data_by_status(incident_id, alerts_limit): """ The function simulate the client.get_incident_extra_data method for the test_fetch_incidents_filtered_by_status. The function got the incident_id, and return the json file by the incident id. """ if incident_id == "1": incident_extra_data = load_test_data("./test_data/get_incident_extra_data.json") else: incident_extra_data = load_test_data("./test_data/get_incident_extra_data_new_status.json") return incident_extra_data["reply"] """ TESTS FUNCTIONS """ @freeze_time("1993-06-17 11:00:00 GMT") def test_fetch_incidents(requests_mock, mocker): from CortexXDRIR import Client, fetch_incidents, sort_all_list_incident_fields raw_incident = load_test_data("./test_data/get_multiple_incidents_extra_data.json").get("reply", {}).get("incidents")[0] modified_raw_incident = raw_incident["incident"] modified_raw_incident["alerts"] = raw_incident.get("alerts").get("data") modified_raw_incident["file_artifacts"] = raw_incident.get("file_artifacts").get("data") modified_raw_incident["network_artifacts"] = raw_incident.get("network_artifacts").get("data") modified_raw_incident["mirror_direction"] = "In" modified_raw_incident["mirror_instance"] = "MyInstance" modified_raw_incident["last_mirrored_in"] = 740314800000 mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=[raw_incident]) mocker.patch.object(demisto, "params", return_value={"exclude_fields": False, "mirror_direction": "Incoming"}) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) modified_raw_incident.get("alerts")[0]["host_ip_list"] = modified_raw_incident.get("alerts")[0].get("host_ip").split(",") mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") next_run, incidents = fetch_incidents(client, "3 month", "MyInstance", exclude_artifacts=False, last_run={}) sort_all_list_incident_fields(modified_raw_incident) assert len(incidents) == 1 assert incidents[0]["name"] == "XDR Incident 1 - desc1" assert "network_artifacts" in json.loads(incidents[0]["rawJSON"]) assert json.loads(incidents[0]["rawJSON"]).pop("last_mirrored_in") assert incidents[0]["rawJSON"] == json.dumps(modified_raw_incident) @freeze_time("1993-06-17 11:00:00 GMT") def test_fetch_incidents_filtered_by_status(requests_mock, mocker): """ Given: - List of fetched incidents When - Running fetch_incident with a given list of statuses to fetch Then - Verify the returned result is as we expected """ from CortexXDRIR import Client, fetch_incidents client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) incident_extra_data_under_investigation = load_test_data("./test_data/get_incident_extra_data_host_id_array.json")["reply"][ "incidents" ] incident_extra_data_new = load_test_data("./test_data/get_incident_extra_data_new_status.json")["reply"]["incidents"] mocker.patch.object( Client, "get_multiple_incidents_extra_data", return_value=(incident_extra_data_under_investigation + incident_extra_data_new), ) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") statuses_to_fetch = ["under_investigation", "new"] next_run, incidents = fetch_incidents( client, "3 month", "MyInstance", exclude_artifacts=False, statuses=statuses_to_fetch, last_run={} ) assert len(incidents) == 2 assert ( incidents[0]["name"] == "XDR Incident 1 - 'Local Analysis Malware' generated by XDR Agent detected on host AAAAAA " "involving user Administrator" ) assert ( incidents[1]["name"] == "XDR Incident 2 - 'Local Analysis Malware' generated by XDR Agent detected on host " "BBBBB involving user Administrator" ) raw_json = json.loads(incidents[0]["rawJSON"]) assert raw_json["status"] == "under_investigation" raw_json = json.loads(incidents[1]["rawJSON"]) assert raw_json["status"] == "new" def return_extra_data_result(*args, **kwargs): raise Exception("Rate limit exceeded") @freeze_time("1993-06-17 11:00:00 GMT") def test_fetch_incidents_with_rate_limit_error(requests_mock, mocker): """ Given: - a Rate limit error occurs in the second call for 'get_extra_data_command' When - running fetch_incidents command Then - the first successful incident is being created - the second incident is saved for the next run """ from CortexXDRIR import Client, fetch_incidents mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch.object(Client, "get_multiple_incidents_extra_data", side_effect=return_extra_data_result) mocker.patch.object(demisto, "params", return_value={"extra_data": True, "mirror_direction": "Incoming"}) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with pytest.raises(Exception) as e: next_run, incidents = fetch_incidents(client, "3 month", "MyInstance", exclude_artifacts=False, last_run={}) assert str(e.value) == "Rate limit exceeded" class TestFetchStarredIncident: def test_get_starred_incident_list_with_limit(self, mocker): """ Given: - List of two starred incidents to fetch When - Running starred fetch_incident with limit of 1 Then - Verify the returned result is as we expected and the fetch incident is getting new incident in each call. """ from CortexXDRIR import Client, get_incidents_command get_incidents_list_response = load_test_data("./test_data/get_starred_incidents_list.json") request_side_effect = [ {"reply": {"incidents": [get_incidents_list_response["reply"]["incidents"][0]]}}, { "reply": { "incidents": [ get_incidents_list_response["reply"]["incidents"][0], get_incidents_list_response["reply"]["incidents"][1], ] } }, ] mocker.patch.object(Client, "_http_request", side_effect=request_side_effect) mocker.patch.object(demisto, "command", return_value="fetch-incidents") getLastRun_side_effect = [{"fetched_starred_incidents": {}}, {"fetched_starred_incidents": {"3": True}}] mocker.patch.object(demisto, "getLastRun", side_effect=getLastRun_side_effect) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "incident_id_list": "1 day", "starred": True, "limit": 1, "starred_incidents_fetch_window": "3 days", "integration_context_brand": "PaloAltoNetworksXDR", } _, outputs, _ = get_incidents_command(client, args) res = outputs["PaloAltoNetworksXDR.Incident(val.incident_id==obj.incident_id)"] assert len(res) == 1 assert res[0]["incident_id"] == "3" _, outputs, _ = get_incidents_command(client, args) res = outputs["PaloAltoNetworksXDR.Incident(val.incident_id==obj.incident_id)"] assert len(res) == 1 assert res[0]["incident_id"] == "4" def test_fetch_only_starred_incidents(self, mocker): """ Given: - List of fetched incidents When - Running fetch_incident with "only fetch starred incidents" flag Then - Verify the returned result is as we expected. First fetch two starred incidents are fetched and on second fetch, (same fetch window) incidents are filtered out since they have been fetched already. """ from CortexXDRIR import Client, fetch_incidents get_incidents_list_response = load_test_data("./test_data/get_starred_incidents_list.json")["reply"]["incidents"] last_run_obj = {} mocker.patch.object(demisto, "params", return_value={"extra_data": True, "mirror_direction": "Incoming"}) mocker.patch.object(demisto, "command", return_value="fetch-incidents") mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=get_incidents_list_response) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) next_run, incidents = fetch_incidents( client, "3 month", "MyInstance", exclude_artifacts=False, last_run=last_run_obj.get("next_run", {}), starred=True, starred_incidents_fetch_window="3 days", ) assert len(incidents) == 2 assert ( incidents[0]["name"] == "XDR Incident 3 - 'Local Analysis Malware' generated by XDR Agent detected" " on host AAAAA involving user Administrator" ) last_run_obj = {"next_run": next_run, "fetched_starred_incidents": {"3": True, "4": True}} mocker.patch.object(demisto, "getLastRun", return_value=last_run_obj) def test_get_tenant_info(requests_mock): from CortexXDRIR import Client, get_tenant_info_command tenant_info_response = load_test_data("./test_data/get_tenant_info.json") requests_mock.post(f"{XDR_URL}/public_api/v1/system/get_tenant_info/", json=tenant_info_response) client = Client(base_url=f"{XDR_URL}/public_api/v1/", verify=False, timeout=120, proxy=False) expected_output = tenant_info_response.get("reply") response = get_tenant_info_command(client) assert response.outputs == expected_output def test_insert_parsed_alert(requests_mock): from CortexXDRIR import Client, insert_parsed_alert_command insert_alerts_response = load_test_data("./test_data/create_alerts.json") requests_mock.post(f"{XDR_URL}/public_api/v1/alerts/insert_parsed_alerts/", json=insert_alerts_response) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "product": "VPN & Firewall-1", "vendor": "Check Point", "local_ip": "192.168.1.254", "local_port": "35398", "remote_ip": "0.0.0.0", "remote_port": "0", "event_timestamp": "1543270652000", "severity": "Low", "alert_name": "Alert Name Example", "alert_description": "Alert Description", } readable_output, outputs, _ = insert_parsed_alert_command(client, args) assert outputs is None assert readable_output == "Alert inserted successfully" def test_insert_cef_alerts(requests_mock): from CortexXDRIR import Client, insert_cef_alerts_command insert_cef_alerts_response = load_test_data("./test_data/insert_cef_alerts.json") requests_mock.post(f"{XDR_URL}/public_api/v1/alerts/insert_cef_alerts/", json=insert_cef_alerts_response) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "cef_alerts": [ "CEF:0|Check Point|VPN-1 & FireWall-1|Check Point|Log|microsoft-ds|Unknown|act=AcceptdeviceDirection=0 " "rt=1569477512000 spt=56957 dpt=445 cs2Label=Rule Name cs2=ADPrimery " "layer_name=FW_Device_blackened Securitylayer_uuid=07693fc7-1a5c-4f31-8afe-77ae96c71b8c match_id=1806 " "parent_rule=0rule_action=Accept rule_uid=8e45f36b-d106-4d81-a1f0-9d1ed9a6be5c ifname=bond2logid=0 " "loguid={0x5d8c5388,0x61,0x29321fac,0xc0000022} origin=1.1.1.1originsicname=CN=DWdeviceBlackend," "O=Blackend sequencenum=363 version=5dst=1.1.1.1 inzone=External outzone=Internal product=VPN-1 & " "FireWall-1 proto=6service_id=microsoft-ds src=1.1.1.1", "CEF:0|Check Point|VPN-1 & FireWall-1|Check Point|Log|Log|Unknown|act=AcceptdeviceDirection=0 " "rt=1569477501000 spt=63088 dpt=5985 cs2Label=Rule Namelayer_name=FW_Device_blackened Securitylayer_" "uuid=07693fc7-1a5c-4f31-8afe-77ae96c71b8c match_id=8899 parent_rule=0rule_action=Accept rule_" "uid=ae987933-82c0-470f-ab1c-1ad552c82369conn_direction=Internal ifname=bond1.12 " "logid=0loguid={0x5d8c537d,0xbb,0x29321fac,0xc0000014} origin=1.1.1.1originsicname=CN=DWdeviceBlackend," "O=Blackend sequencenum=899 version=5dst=1.1.1.1 product=VPN-1 & FireWall-1 proto=6 src=1.1.1.1", ] } readable_output, _, _ = insert_cef_alerts_command(client, args) assert readable_output == "Alerts inserted successfully" def test_sort_all_list_incident_fields(): """ Given: - A raw incident When - running sort_all_list_incident_fields on it Then - the list fields (alerts for example) are sorted """ from CortexXDRIR import sort_all_list_incident_fields raw_incident = load_test_data("test_data/raw_fetched_incident.json") sort_all_list_incident_fields(raw_incident) assert raw_incident.get("alerts")[0].get("alertid") == "42" assert raw_incident.get("alerts")[1].get("alertid") == "55" assert raw_incident.get("alerts")[2].get("alertid") == "60" assert raw_incident.get("hosts")[0] == "HOST1" assert raw_incident.get("hosts")[1] == "HOST2" assert raw_incident.get("file_artifacts")[0].get("filename") == "file.exe" assert raw_incident.get("file_artifacts")[1].get("filename") == "file2.exe" @pytest.mark.parametrize("dont_format_sublists", [False, True]) def test_format_sublists_param(dont_format_sublists, mocker): """ Given: - A raw incident When - running sort_all_list_incident_fields on it with dont_format_sublists Then - if dont_format_sublists is False, should be formatted, so should have underscore - if dont_format_sublists is True, should not be formatted, so should not have underscore - Underscre value should always be present """ from CortexXDRIR import sort_all_list_incident_fields raw_incident = load_test_data("test_data/raw_fetched_incident.json") mocker.patch.object(demisto, "params", return_value={"dont_format_sublists": dont_format_sublists}) sort_all_list_incident_fields(raw_incident) assert bool(raw_incident.get("alerts")[0].get("alertid")) == (not dont_format_sublists) assert raw_incident.get("alerts")[0].get("alert_id") def test_get_mapping_fields_command(): """ Given: - nothing When - running get_mapping_fields_command Then - the result fits the expected mapping. """ from CortexXDRIR import get_mapping_fields_command expected_mapping = { "Cortex XDR Incident Schema": { "status": 'Current status of the incident: "new","under_' 'investigation","resolved_known_issue",' '"resolved_duplicate","resolved_false_positive",' '"resolved_true_positive","resolved_security_testing","resolved_other"', "assigned_user_mail": "Email address of the assigned user.", "assigned_user_pretty_name": "Full name of the user assigned to the incident.", "resolve_comment": "Comments entered by the user when the incident was resolved.", "manual_severity": "Incident severity assigned by the user. This does not " "affect the calculated severity low medium high", "close_reason": "The close reason of the XSOAR incident", } } res = get_mapping_fields_command() assert expected_mapping == res.extract_mapping() def test_get_remote_data_command_should_update(requests_mock, mocker): """ Given: - an XDR client - arguments (id and lastUpdate time set to a lower than incident modification time) - a raw incident (get-extra-data results) When - running get_remote_data_command Then - the mirrored_object in the GetRemoteDataResponse is the same as the modified raw incident - the entries in the GetRemoteDataResponse in empty """ from CortexXDRIR import Client, get_remote_data_command, sort_all_list_incident_fields client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"id": 1, "lastUpdate": 0} raw_incident = load_test_data("./test_data/get_incident_extra_data.json") expected_modified_incident = raw_incident["reply"]["incident"].copy() expected_modified_incident["alerts"] = copy.deepcopy(raw_incident["reply"].get("alerts").get("data")) expected_modified_incident["network_artifacts"] = raw_incident["reply"].get("network_artifacts").get("data") expected_modified_incident["file_artifacts"] = raw_incident["reply"].get("file_artifacts").get("data") expected_modified_incident["id"] = expected_modified_incident.get("incident_id") expected_modified_incident["assigned_user_mail"] = "" expected_modified_incident["assigned_user_pretty_name"] = "" expected_modified_incident["in_mirror_error"] = "" del expected_modified_incident["creation_time"] expected_modified_incident.get("alerts")[0]["host_ip_list"] = ( expected_modified_incident.get("alerts")[0].get("host_ip").split(",") ) # make sure get-extra-data is returning an incident mocker.patch("CortexXDRIR.get_last_mirrored_in_time", return_value=0) mocker.patch("CortexXDRIR.check_if_incident_was_modified_in_xdr", return_value=True) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=raw_incident["reply"]) response = get_remote_data_command(client, args) sort_all_list_incident_fields(expected_modified_incident) assert response.mirrored_object == expected_modified_incident assert response.entries[0].get("Contents") == {"dbotIncidentReopen": True} def test_get_remote_data_command_with_rate_limit_exception(mocker): """ Given: - an XDR client - arguments (id and lastUpdate time set to a lower than incident modification time) - a Rate limit exception is raises from get_extra_data_command method When - running get_remote_data_command Then - an "API rate limit" error is thrown so that the server will stop the sync loop and will resume from the last incident. """ import sys from CortexXDRIR import Client, get_remote_data_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"id": 1, "lastUpdate": 0} mocker.patch("CortexXDRIR.return_error", side_effect=sys.exit) mocker.patch("CortexXDRIR.get_incident_extra_data_command", side_effect=Exception("Rate limit exceeded")) with pytest.raises(SystemExit): _ = get_remote_data_command(client, args) def test_get_remote_data_command_should_not_update(requests_mock, mocker): """ Given: - an XDR client - arguments (id and lastUpdate time set to a higher than incident modification time) - a raw incident (get-extra-data results) When - running get_remote_data_command Then - returns an empty dict """ from CortexXDRIR import Client, get_remote_data_command, sort_all_list_incident_fields client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"id": 1, "lastUpdate": "2020-07-31T00:00:00Z"} raw_incident = load_test_data("./test_data/get_incident_extra_data.json") expected_modified_incident = {"id": 1, "in_mirror_error": ""} sort_all_list_incident_fields(expected_modified_incident) # make sure get-extra-data is returning an incident mocker.patch("CortexXDRIR.get_last_mirrored_in_time", return_value=0) mocker.patch("CortexXDRIR.check_if_incident_was_modified_in_xdr", return_value=False) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") requests_mock.post(f"{XDR_URL}/public_api/v1/incidents/get_incident_extra_data/", json=raw_incident) response = get_remote_data_command(client, args) assert response.mirrored_object == expected_modified_incident assert response.entries == [] @pytest.mark.parametrize( argnames="incident_status, close_xsoar_incident", argvalues=[(status, close_flag) for status in XDR_RESOLVED_STATUS_TO_XSOAR for close_flag in [True, False]], ) def test_get_remote_data_command_should_close_issue(capfd, requests_mock, mocker, incident_status, close_xsoar_incident): """ Given: - an XDR client - arguments (id and lastUpdate time set to a lower than incident modification time) - a raw incident (get-extra-data results) indicating the incident was closed on XDR side When - running get_remote_data_command Then - If close_xsoar_incident is True, the mirrored_object in the GetRemoteDataResponse holds the closing entry. - If close_xsoar_incident is False, the mirrored_object in the GetRemoteDataResponse does not hold the closing entry. """ import copy from CortexXDRIR import Client, get_remote_data_command, sort_all_list_incident_fields client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) client._params["close_xsoar_incident"] = close_xsoar_incident args = {"id": 1, "lastUpdate": 0} raw_incident = load_test_data("./test_data/get_incident_extra_data.json") raw_incident["reply"]["incident"]["status"] = incident_status raw_incident["reply"]["incident"]["resolve_comment"] = "Handled" close_notes_prefix = "Known Issue.\n" if incident_status == "resolved_known_issue" else "" close_notes = f"{close_notes_prefix}Handled" expected_modified_incident = raw_incident["reply"]["incident"].copy() expected_modified_incident["alerts"] = copy.deepcopy(raw_incident["reply"].get("alerts").get("data")) expected_modified_incident["network_artifacts"] = raw_incident["reply"].get("network_artifacts").get("data") expected_modified_incident["file_artifacts"] = raw_incident["reply"].get("file_artifacts").get("data") expected_modified_incident["id"] = expected_modified_incident.get("incident_id") expected_modified_incident["assigned_user_mail"] = "" expected_modified_incident["assigned_user_pretty_name"] = "" expected_modified_incident["in_mirror_error"] = "" del expected_modified_incident["creation_time"] expected_modified_incident.get("alerts")[0]["host_ip_list"] = ( expected_modified_incident.get("alerts")[0].get("host_ip").split(",") ) expected_closing_entry = {} if close_xsoar_incident: expected_modified_incident["closeReason"] = XDR_RESOLVED_STATUS_TO_XSOAR[incident_status] expected_modified_incident["closeNotes"] = close_notes expected_closing_entry = { "Type": 1, "Contents": { "dbotIncidentClose": True, "closeReason": XDR_RESOLVED_STATUS_TO_XSOAR[incident_status], "closeNotes": close_notes, }, "ContentsFormat": "json", } mocker.patch("CortexXDRIR.get_last_mirrored_in_time", return_value=0) mocker.patch("CortexXDRIR.check_if_incident_was_modified_in_xdr", return_value=True) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=raw_incident["reply"]) with capfd.disabled(): response = get_remote_data_command(client, args) sort_all_list_incident_fields(expected_modified_incident) assert response.mirrored_object == expected_modified_incident if close_xsoar_incident: assert expected_closing_entry in response.entries else: assert expected_closing_entry not in response.entries def test_get_remote_data_command_sync_owners(requests_mock, mocker): """ Given: - an XDR client - arguments (id and lastUpdate time set to a lower than incident modification time) - a raw incident (get-extra-data results) with assigned mail moo@demisto.com When - running get_remote_data_command Then - the mirrored_object in the GetRemoteDataResponse is the same as the modified raw incident with the equivalent owner of the assigned mail - the entries in the GetRemoteDataResponse in empty """ import copy from CortexXDRIR import Client, get_remote_data_command, sort_all_list_incident_fields mocker.patch.object(demisto, "params", return_value={"sync_owners": True}) mocker.patch.object(demisto, "findUser", return_value={"email": "moo@demisto.com", "username": "username"}) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"id": 1, "lastUpdate": 0} raw_incident = load_test_data("./test_data/get_incident_extra_data.json") raw_incident["reply"]["incident"]["assigned_user_mail"] = "moo@demisto.com" expected_modified_incident = raw_incident["reply"]["incident"].copy() expected_modified_incident["alerts"] = copy.deepcopy(raw_incident["reply"].get("alerts").get("data")) expected_modified_incident["network_artifacts"] = raw_incident["reply"].get("network_artifacts").get("data") expected_modified_incident["file_artifacts"] = raw_incident["reply"].get("file_artifacts").get("data") expected_modified_incident["id"] = expected_modified_incident.get("incident_id") expected_modified_incident["assigned_user_mail"] = "moo@demisto.com" expected_modified_incident["assigned_user_pretty_name"] = None expected_modified_incident["owner"] = "username" expected_modified_incident["in_mirror_error"] = "" del expected_modified_incident["creation_time"] expected_modified_incident.get("alerts")[0]["host_ip_list"] = ( expected_modified_incident.get("alerts")[0].get("host_ip").split(",") ) # make sure get-extra-data is returning an incident mocker.patch("CortexXDRIR.get_last_mirrored_in_time", return_value=0) mocker.patch("CortexXDRIR.check_if_incident_was_modified_in_xdr", return_value=True) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=raw_incident["reply"]) response = get_remote_data_command(client, args) sort_all_list_incident_fields(expected_modified_incident) assert response.mirrored_object == expected_modified_incident assert response.entries[0].get("Contents") == {"dbotIncidentReopen": True} @pytest.mark.parametrize("last_update", ["2020-11-18T13:16:52.005381+02:00", "2024-03-21T17:02:02.000000645Z"]) def test_get_modified_remote_data_command(requests_mock, last_update): """ Given: - an XDR client - arguments - lastUpdate time - raw incidents (result of client.get_incidents) When - running get_modified_remote_data_command Then - the method is returning a list of incidents IDs that were modified """ from CortexXDRIR import Client, get_modified_remote_data_command get_incidents_list_response = load_test_data("./test_data/get_incidents_list.json") requests_mock.post(f"{XDR_URL}/public_api/v1/incidents/get_incidents/", json=get_incidents_list_response) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"lastUpdate": last_update} response, _ = get_modified_remote_data_command(client, args) assert response.modified_incident_ids == ["1", "2"] def test_get_contributing_event_command(requests_mock): from CortexXDRIR import Client, get_contributing_event_command contributing_events = load_test_data("./test_data/contributing_events.json") requests_mock.post(f"{XDR_URL}/public_api/v1/alerts/get_correlation_alert_data/", json=contributing_events) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "alert_ids": "[1111]", } response = get_contributing_event_command(client, args) assert response.outputs[0].get("alertID") == args.get("alert_ids").strip("[]") assert len(response.outputs[0].get("events")) == 1 def test_replace_featured_field_command(requests_mock): from CortexXDRIR import Client, replace_featured_field_command replace_featured_field = load_test_data("./test_data/replace_featured_field.json") requests_mock.post(f"{XDR_URL}/public_api/v1/featured_fields/replace_ad_groups", json=replace_featured_field) expected_response = { "fieldType": "ad_groups", "fields": [ {"value": "new value", "comment": "this is a comment", "type": "ou"}, {"value": "one new value", "comment": "", "type": ""}, ], } client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "ad_type": '["ou"]', "comments": '["this is a comment"]', "field_type": "ad_groups", "values": '["new value", "one new value"]', } response = replace_featured_field_command(client, args) assert response.outputs == expected_response assert len(response.outputs.get("fields")) == 2 def test_failure_to_update_incident(): from CortexXDRIR import Client, update_incident_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with pytest.raises(ValueError, match="Can't provide both assignee_email/assignee_name and unassign_user"): update_incident_command(client=client, args={"unassign_user": "true", "assigned_user_mail": "user", "status": "new"}) def test_update_incident(requests_mock): from CortexXDRIR import Client, update_incident_command update_incident_response = load_test_data("./test_data/update_incident.json") requests_mock.post(f"{XDR_URL}/public_api/v1/incidents/update_incident/", json=update_incident_response) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "incident_id": "1", "status": "new", "add_comment": "new comment", } readable_output, outputs, _ = update_incident_command(client, args) assert outputs is None assert readable_output == "Incident 1 has been updated" @pytest.mark.parametrize("incident_changed, delta", [(True, {"CortexXDRIRstatus": "investigating"}), (False, {})]) def test_update_remote_system_command(incident_changed, delta): from CortexXDRIR import Client, update_remote_system_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) data = {"CortexXDRIRstatus": "uninvestigated"} expected_remote_id = "remote_id" args = { "remoteId": expected_remote_id, "data": data, "entries": [], "incidentChanged": incident_changed, "delta": delta, "status": 2, } actual_remote_id = update_remote_system_command(client, args) assert actual_remote_id == expected_remote_id @pytest.mark.parametrize( "data", [ {"close_reason": "Resolved", "status": "Other"}, {"CortexXDRIRstatus": "resolved", "close_reason": "Resolved", "status": "False Positive"}, {"status": "under_investigation"}, {"status": "Resolved", "resolve_comment": "comment"}, {"status": "False Positive", "resolve_comment": "comment"}, ], ) def test_update_remote_system_command_should_not_close_xdr_incident(mocker, data): """ Given: - an XDR client with 'close_xdr_incident' set to False. - arguments indicating the incident was closed in XSOAR. When: - running update_remote_system_command with 'close_xdr_incident' set to False. Then: - the incident in XDR should not be closed. - other updates to the incident should still be applied. """ from CortexXDRIR import Client, update_remote_system_command client = Client( base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False, params={"close_xdr_incident": False} ) delta = copy.deepcopy(data) expected_remote_id = "remote_id" args = { "remoteId": expected_remote_id, "data": data, "incidentChanged": True, "delta": delta, "status": 2, } mock_update_incident_command = mocker.patch("CortexXDRIR.update_incident_command") update_remote_system_command(client, args) update_args = mock_update_incident_command.call_args[0][1] if data.get("status") in XSOAR_RESOLVED_STATUS_TO_XDR: assert "status" not in update_args assert "resolve_comment" not in update_args else: assert "status" in update_args if data.get("resolve_comment"): assert "resolve_comment" in update_args # checks when close_all_alerts is true -> should update only the alerts status client._params["close_alerts_in_xdr"] = True mock_update_related_alerts = mocker.patch("CortexXDRIR.update_related_alerts") update_remote_system_command(client, args) if mock_update_related_alerts.called: update_args = mock_update_related_alerts.call_args[0][1] assert "status" in update_args def test_update_remote_system_command_incident_changed_but_no_delta(mocker): """ Given: - an XDR client - arguments indicating the incident was changed in XSOAR but no delta found When: - running update_remote_system_command Then: - no update will happen when incident was changed in XSOAR but no delta found """ from CortexXDRIR import Client, update_remote_system_command client = Client( base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False, params={"close_xdr_incident": False} ) expected_remote_id = "remote_id" args = { "remoteId": expected_remote_id, "data": {}, "entries": [], "incidentChanged": True, "delta": {}, "status": 2, } mock_get_update_args = mocker.patch("CoreIRApiModule.get_update_args") incident_id = update_remote_system_command(client, args) assert mock_get_update_args.call_count == 0 assert incident_id == expected_remote_id def test_update_remote_system_command_closing_alerts_and_including_resolve_comment(mocker): """ Given: - An XDR client configured with parameters for closing alerts in XDR. - Expected remote incident ID and arguments representing a resolved XSOAR incident with a delta containing close reason and resolve comment. When: - Calling update_remote_system_command with the provided client and arguments. Then: - The get_update_args function should be called once to prepare the update arguments. - The update_related_alerts function should be called once to handle the closure of related alerts. - The returned incident ID should match the expected remote incident ID. """ from CortexXDRIR import Client, update_remote_system_command client = Client( base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False, params={"close_alerts_in_xdr": True} ) expected_remote_id = "remote_id" args = { "remoteId": expected_remote_id, "data": {"CortexXDRIRstatus": "resolved", "close_reason": "Resolved", "status": "test"}, "entries": [], "incidentChanged": True, "delta": {"close_reason": "resolved", "resolve_comment": "", "status": "resolved_true_positive"}, "status": 2, } mocker.patch("CortexXDRIR.update_incident_command") mock_get_update_args = mocker.patch("CortexXDRIR.get_update_args", return_value=args.get("delta")) mock_update_related_alerts = mocker.patch("CortexXDRIR.update_related_alerts") incident_id = update_remote_system_command(client, args) assert mock_get_update_args.call_count == 1 assert mock_update_related_alerts.call_count == 1 assert incident_id == expected_remote_id def test_get_update_args_close_incident_without_status_handler(mocker): """ Given: - Arguments indicating that the incident was changed in XSOAR but closed without providing a reason. When: - Running the 'get_update_args.handle_outgoing_issue_closure' function with the provided arguments. Then: - The 'get_update_args.handle_outgoing_issue_closure' function should append the 'status' field in the delta with the value 'resolved_other'. """ from CommonServerPython import UpdateRemoteSystemArgs from CoreIRApiModule import get_update_args args = { "remoteId": "remote_id", "data": {"closeNotes": "ancd", "status": "test"}, "entries": [], "incidentChanged": True, "delta": {"runStatus": "1", "incident_id": "remote_id"}, "status": 2, } parsed_args = UpdateRemoteSystemArgs(args) mocker.patch("CoreIRApiModule.handle_outgoing_incident_owner_sync") mocker.patch("CoreIRApiModule.handle_user_unassignment") parsed_args_delta = get_update_args(parsed_args) assert parsed_args_delta.get("status") == "resolved_other" @freeze_time("1997-10-05 15:00:00 GMT") def test_fetch_incidents_extra_data(requests_mock, mocker): """ Given: - List of fetched incidents. - List of multiple extra of incidents data response When - Running fetch_incident Then - Verify the returned result is as we expected """ from CortexXDRIR import Client, fetch_incidents raw_multiple_extra_data = load_test_data("./test_data/get_multiple_incidents_extra_data.json") raw_all_alerts_incident_2 = load_test_data("./test_data/get_extra_data_all_alerts.json").get("reply", {}) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=10, proxy=False) mocker.patch.object(demisto, "params", return_value={"extra_data": True, "mirror_direction": "Incoming"}) mocker.patch.object(Client, "get_incident_extra_data", return_value=raw_all_alerts_incident_2) mocker.patch.object( Client, "get_multiple_incidents_extra_data", return_value=raw_multiple_extra_data.get("reply", {}).get("incidents", []) ) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=2) next_run, incidents = fetch_incidents(client, "3 month", "MyInstance", exclude_artifacts=False, last_run={}) assert len(incidents) == 2 assert incidents[0]["name"] == "XDR Incident 1 - desc1" assert json.loads(incidents[0]["rawJSON"]).get("incident_id") == "1" assert json.loads(incidents[1]["rawJSON"]).get("incident_id") == "2" def test_get_incident_extra_data(mocker): """ Given: - an XDR client - arguments (id) When - Running get_incident_extra_data_command Then - Verify the returned result is as we expected """ from CortexXDRIR import Client, get_incident_extra_data_command get_incident_extra_data_response = ( load_test_data("./test_data/get_incident_extra_data_host_id_array.json").get("reply", {}).get("incidents", []) ) mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=get_incident_extra_data_response) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=2) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"incident_id": "1"} _, outputs, raw_incident = get_incident_extra_data_command(client, args) expected_output = { "Process(val.Name && val.Name == obj.Name)": [ { "Name": "wildfire-test-pe-file.exe", "CommandLine": '"C:\\Users\\Administrator\\Downloads\\wildfire-test-pe-file.exe"', "Hostname": "AAAAAA", } ], "Endpoint(val.Hostname==obj.Hostname)": [{"Hostname": "AAAAAA", "ID": "1234"}], } assert raw_incident == get_incident_extra_data_response[0] assert expected_output["Process(val.Name && val.Name == obj.Name)"] == outputs["Process(val.Name && val.Name == obj.Name)"] assert expected_output["Endpoint(val.Hostname==obj.Hostname)"] == outputs["Endpoint(val.Hostname==obj.Hostname)"] @pytest.mark.parametrize( "custom_mapping, expected_resolved_status", [ ( "Known Issue=Other,Duplicate Incident=Duplicate,False Positive=False Positive," "True Positive=Resolved,Security Testing=Other,Other=Other", ["Other", "Duplicate", "Duplicate", "False Positive", "Resolved", "Other", "Other", "Resolved", "Resolved"], ), ( "Known Issue=Other,Duplicate Incident=Other,False Positive=False Positive," "True Positive=Resolved,Security Testing=Other,Other=Other", ["Other", "Other", "Duplicate", "False Positive", "Resolved", "Other", "Other", "Resolved", "Resolved"], ), ( "Duplicate Incident=Other,Security Testing=Other,Other=Other", ["Other", "Other", "Duplicate", "False Positive", "Resolved", "Other", "Other", "Resolved", "Resolved"], ), # Expecting default mapping to be used when no mapping provided. ("", list(XDR_RESOLVED_STATUS_TO_XSOAR.values())), # Expecting default mapping to be used when improper mapping is provided. ("Duplicate=RANDOM1, Other=Random2", list(XDR_RESOLVED_STATUS_TO_XSOAR.values())), ("Duplicate Incident=Random3", list(XDR_RESOLVED_STATUS_TO_XSOAR.values())), # Expecting default mapping to be used when improper mapping *format* is provided. ("Duplicate Incident=Other False Positive=Other", list(XDR_RESOLVED_STATUS_TO_XSOAR.values())), # Expecting default mapping to be used for when improper key-value pair *format* is provided. ( "Duplicate Incident=Other, False Positive=Other True Positive=Other", ["Other", "Other", "Duplicate", "False Positive", "Resolved", "Security Testing", "Other", "Resolved", "Resolved"], ), ], 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_xdr_to_xsoar_flexible_close_reason_mapping(capfd, mocker, custom_mapping, expected_resolved_status): """ Given: - A custom XDR->XSOAR close-reason mapping - Expected resolved XSOAR status according to the custom mapping. When - Handling incoming closing-incident (handle_incoming_closing_incident(...) executed). Then - The resolved XSOAR statuses match the expected statuses for all possible XDR close-reasons. """ from CortexXDRIR import handle_incoming_incident mocker.patch.object( demisto, "params", return_value={"mirror_direction": "Both", "custom_xdr_to_xsoar_close_reason_mapping": custom_mapping} ) all_xdr_close_reasons = XDR_RESOLVED_STATUS_TO_XSOAR.keys() for i, xdr_close_reason in enumerate(all_xdr_close_reasons): # Mock an xdr incident with "resolved" status. incident_data = load_test_data("./test_data/resolved_incident_data.json") # Set incident status to be tested close-reason. incident_data["status"] = xdr_close_reason # Overcoming expected non-empty stderr test failures (Errors are submitted to stderr when improper mapping is provided). with capfd.disabled(): close_entry = handle_incoming_incident(incident_data) assert close_entry["Contents"]["closeReason"] == expected_resolved_status[i] @pytest.mark.parametrize( "custom_mapping, direction, should_raise_error", [ ("Other=Other,Duplicate=Other,False Positive=False Positive,Resolved=True Positive", XSOAR_TO_XDR, False), ("Known Issue=Other,Duplicate Incident=Duplicate,False Positive=False Positive", XDR_TO_XSOAR, False), ("Duplicate Incident=Random", XSOAR_TO_XDR, True), ("Duplicate=RANDOM1, Other=Random2", XDR_TO_XSOAR, True), # Inverted map provided ("Duplicate=Duplicate Incident", XDR_TO_XSOAR, True), ("Duplicate Incident=Duplicate", XSOAR_TO_XDR, True), # Improper mapping ("Random1, Random2", XDR_TO_XSOAR, True), ("Random1, Random2", XSOAR_TO_XDR, True), ], ids=["case-1", "case-2", "case-3", "case-4", "case-5", "case-6", "case-7", "case-8"], ) def test_test_module(capfd, custom_mapping, direction, should_raise_error): """ Given: - mock client with username and api_key (basic auth) When: - run `test_module` function Then: - Ensure no error is raised, and return `ok` """ from CortexXDRIR import Client, validate_custom_close_reasons_mapping # using two different credentials object as they both fields need to be encrypted base_url = urljoin("dummy_url", "/public_api/v1") proxy = demisto.params().get("proxy") verify_cert = not demisto.params().get("insecure", False) Client(base_url=base_url, proxy=proxy, verify=verify_cert, timeout=120, params=demisto.params()) # Overcoming expected non-empty stderr test failures (Errors are submitted to stderr when improper mapping is provided). with capfd.disabled(): if should_raise_error: with pytest.raises(DemistoException): validate_custom_close_reasons_mapping(mapping=custom_mapping, direction=direction) else: try: validate_custom_close_reasons_mapping(mapping=custom_mapping, direction=direction) except DemistoException as e: pytest.fail(f"Unexpected exception raised for input {input}: {e}") @freeze_time("1997-10-05 15:00:00 GMT") def test_convert_datetime_to_epoch(): """ Given: - Datetime object When: - Calling convert_datetime_to_epoch() Then: - Returned epoch int matches expected """ from datetime import datetime from CortexXDRIR import convert_datetime_to_epoch input_datetime = datetime.now() assert convert_datetime_to_epoch(input_datetime) == 876063600 @freeze_time("1997-10-05 15:00:00 GMT") def test_convert_epoch_to_milli(): """ Given: - Epoch timestamp When: - Calling convert_epoch_to_milli() Then: - Returned timestamp matches expected milliseconds """ from CortexXDRIR import convert_epoch_to_milli input_epoch = 1577836800 assert convert_epoch_to_milli(input_epoch) == 1577836800000 @freeze_time("1997-10-05 15:00:00 GMT") def test_convert_datetime_to_epoch_millis(): """ Given: - Datetime object When: - Calling convert_datetime_to_epoch_millis() Then: - Returned epoch timestamp matches expected milliseconds """ from datetime import datetime from CortexXDRIR import convert_datetime_to_epoch_millis input_datetime = datetime.now() assert convert_datetime_to_epoch_millis(input_datetime) == 876063600 @freeze_time("1997-10-05 15:00:00 GMT") def test_generate_current_epoch_utc(): """ Given: Nothing When: - Calling generate_current_epoch_utc() Then: - Returned value is integer epoch timestamp """ from CortexXDRIR import generate_current_epoch_utc epoch = generate_current_epoch_utc() assert isinstance(epoch, int) assert epoch > 876000 def test_generate_key(): """ Given: None When: Calling generate_key() Then: Verify the returned result is as we expected """ from CortexXDRIR import generate_key key = generate_key() assert len(key) == 128 def test_create_auth(): """ Given: Client ID and client secret When: Calling create_auth() Then: Verify the returned result is as we expected """ from CortexXDRIR import create_auth auth = create_auth("client_id") assert len(auth) == 3 def test_clear_trailing_whitespace(): """ Given: - list of dictionary containing a value of String with trailing whitespace When: - Calling clear_trailing_whitespace() Then: - Trailing whitespace should be removed """ from CortexXDRIR import clear_trailing_whitespace alerts = [{"example": "value "}] actual = clear_trailing_whitespace(alerts) assert actual == [{"example": "value"}] def test_filter_and_save_unseen_incident_limit_test(): """ Given: - List of incidents with creation times - Last fetch time When: - Calling filter_and_save_unseen_incident multiple times Then: - Returns maximum number of incidents per run """ from CortexXDRIR import filter_and_save_unseen_incident incident = [{"id": "1", "creation_time": 1577836800000}, {"id": "2", "creation_time": 1577836800001}] assert filter_and_save_unseen_incident(incident, 1, 1) == [{"id": "1", "creation_time": 1577836800000}] @freeze_time("1997-10-05 15:00:00 GMT") def test_get_headers(mocker): """ Given: - A dictionary of parameters including 'apikey', 'apikey_id', and 'prevent_only' When: - Calling get_headers with the given parameters Then: - Returns a dictionary containing the expected headers """ from CortexXDRIR import get_headers mocker.patch("secrets.choice", return_value="test") # Define the parameters params = {"apikey": "test_api_key", "apikey_id": "test_api_key_id", "prevent_only": False} headers = get_headers(params) assert len(headers) == 4 assert headers["x-xdr-nonce"] == "test" * 64 @freeze_time("1997-10-05 15:00:00 GMT") def test_get_last_mirrored_in_time_old_incident(mocker): """ Given: - An old incident with a lastmirroredintime set When: - Calling get_last_mirrored_in_time Then: - Return the timestamp converted from the lastmirroredintime """ from CortexXDRIR import get_last_mirrored_in_time demisto_incidents = [{"CustomFields": {"lastmirroredintime": "2020-01-01"}}] mocker.patch.object(demisto, "get_incidents", return_value=demisto_incidents) args = {} assert get_last_mirrored_in_time(args) == 1577836800000 def test_get_last_mirrored_in_time_new_incident_6_0(mocker): """ Given: - A new 6.0 incident with a last_update set When: - Calling get_last_mirrored_in_time Then: - Return the timestamp converted from the last_update minus 120 seconds """ from CortexXDRIR import get_last_mirrored_in_time mocker.patch.object(demisto, "get_incidents", return_value=[]) args = {"last_update": "2020-01-01T00:02:00Z"} assert get_last_mirrored_in_time(args) == 1577836800000 def test_incident_modified(): """ Given: - incident_id - last_mirrored_time - last_modified_incidents When: - Calling check_if_incident_was_modified_in_xdr Then: - Verify the returned result is as we expected """ from CortexXDRIR import check_if_incident_was_modified_in_xdr incident_id = "2" last_mirrored_time = 1578901000 last_modified_incidents = {"1": 1578900000, "2": 1578905000} assert check_if_incident_was_modified_in_xdr(incident_id, last_mirrored_time, last_modified_incidents) def test_create_parsed_alert(mocker): """ Given: - product - vendor - local_ip - local_port - remote_ip - remote_port - event_timestamp - severity - alert_name - alert_description When: - Calling create_parsed_alert(). Then: - Verify the returned result is as we expected """ from CortexXDRIR import create_parsed_alert parsed_alert = create_parsed_alert( product="product", vendor="vendor", local_ip="1.1.1.1", local_port="1", remote_ip="2.2.2.2", remote_port="2", event_timestamp="", severity="high", alert_name="example", alert_description="Malicious File", ) assert parsed_alert.get("alert_description") == "Malicious File" assert parsed_alert.get("severity") == "high" def test_sync_incoming_incident_owners(mocker): """ Given: - incident_data dict with assigned_user_mail When: - Calling sync_incoming_incident_owners(). Then: - Verify the incident_data result is as we expected. """ from CortexXDRIR import sync_incoming_incident_owners incident_data = {"assigned_user_mail": "www.example@test.com"} mocker.patch.object(demisto, "params", return_value={"sync_owners": True}) mocker.patch.object(demisto, "findUser", return_value={"username": "tester"}) sync_incoming_incident_owners(incident_data) assert incident_data.get("owner") == "tester" def test_handle_incoming_user_unassignment(mocker): """ Given: - incident_data dict with incident_id, owner. When: - Calling handle_incoming_user_unassignment(). Then: - Verify the returned result is as we expected. """ from CortexXDRIR import handle_incoming_user_unassignment incident_data = {"incident_id": "1", "owner": "tester"} mocker.patch.object(demisto, "params", return_value={"sync_owners": True}) handle_incoming_user_unassignment(incident_data) assert not incident_data.get("owner") def test_get_endpoints_by_status_command(mocker): """ Given: - incident_data dict with incident_id, owner. When: - Calling get_endpoints_by_status_command(). Then: - Verify the returned result is as we expected. """ from CortexXDRIR import Client, get_endpoints_by_status_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"status": ["new", "in_progress"], "last_seen_gte": "11", "last_seen_lte": "1"} mocker.patch.object(Client, "get_endpoints_by_status", return_value=["1", {"endpoint_count": 2}]) res = get_endpoints_by_status_command(client, args) assert res.readable_output == "['new', 'in_progress'] endpoints count: 1" class TestGetIncidents: def test_get_multiple_incidents_extra_data(self, requests_mock, mocker): """ Given: Incidents returned from client. When: Running get_multiple_incidents_extra_data. Then: Ensure the outputs contain the incidents from the client. """ from CortexXDRIR import Client multiple_extra_data = load_test_data("./test_data/get_multiple_incidents_extra_data.json") alert_limit = multiple_extra_data["reply"]["alerts_limit_per_incident"] requests_mock.post(f"{XDR_URL}/incidents/get_multiple_incidents_extra_data/", json=multiple_extra_data) mocker.patch.object(demisto, "command", return_value="xdr-get-incident-extra-data") mocker.patch.object(Client, "_http_request", return_value=multiple_extra_data) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=10, proxy=False) len_incidents = len(multiple_extra_data["reply"]["incidents"]) outputs = Client.get_multiple_incidents_extra_data( client, statuses=["new"], starred=True, starred_incidents_fetch_window=1575806909185, incident_id_list=["1", "2"], exclude_artifacts=True, ) assert len(outputs) == len_incidents assert outputs[0]["alerts"]["total_count"] <= alert_limit assert outputs[1]["alerts"]["total_count"] <= alert_limit def test_get_incident_extra_data_incident_not_exist(mocker): """ Given: - an XDR client - arguments (id) When - Running get_incident_extra_data_command Then - Verify that if the incident id is not found, it returns an error. """ from CortexXDRIR import Client, get_incident_extra_data_command mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=[]) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=2) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"incident_id": "1"} with pytest.raises(DemistoException) as e: _, outputs, raw_incident = get_incident_extra_data_command(client, args) assert str(e.value) == "Incident 1 is not found" def test_sort_all_incident_data_fields_fetch_case_get_multiple_incidents_extra_data_format(mocker): """ Given: - raw incident in get_incident_extra_data format- alerts and artifacts not in incident data information When - Running sort_all_list_incident_fields Then - Verify that alerts and artifacts are found. """ from CortexXDRIR import sort_all_list_incident_fields, sort_incident_data incident_case_get_multiple_incidents_extra_data = ( load_test_data("./test_data/get_multiple_incidents_extra_data.json").get("reply").get("incidents")[0] ) incident_data = sort_incident_data(incident_case_get_multiple_incidents_extra_data) sort_all_list_incident_fields(incident_data) assert incident_data.get("alerts") assert incident_data.get("incident_sources") == ["XDR Agent"] assert incident_data.get("status") == "new" assert len(incident_data.get("file_artifacts")) == 1 def test_update_alerts_in_xdr_command_expected_result(mocker): """ Given: - an XDR client - arguments (incident_id) When - Running update_alerts_in_xdr_command Then - Verify update alerts """ from CortexXDRIR import Client, update_alerts_in_xdr_command xdrIr_client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=10, proxy=False) http_request = mocker.patch.object(xdrIr_client, "_http_request") http_request.return_value = {"reply": {"alerts_ids": ["1", "2", "3"]}} args = {"alert_ids": "1,2,3", "severity": "high", "status": "resolved_threat_handled", "comment": "fixed from test"} res = update_alerts_in_xdr_command(xdrIr_client, args) assert res.readable_output == "Alerts with IDs 1,2,3 have been updated successfully." def test_update_alerts_in_xdr_command_fail_to_update(mocker): """ Given: - an XDR client - arguments (incident_id) When - Running update_alerts_in_xdr_command Then - Did not find alerts to update - raise an error """ from CortexXDRIR import Client, update_alerts_in_xdr_command xdrIr_client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=10, proxy=False) http_request = mocker.patch.object(xdrIr_client, "_http_request") http_request.return_value = {"reply": {"alerts_ids": []}} args = {"alert_ids": "1,2,3", "severity": "high", "status": "resolved_threat_handled", "comment": "fixed from test"} with pytest.raises(DemistoException) as e: update_alerts_in_xdr_command(xdrIr_client, args) assert e.value.message == "Could not find alerts to update, please make sure you used valid alert IDs." def test_update_alerts_in_xdr_command_invalid_response_no_reply(mocker): """ Given: - an XDR client - arguments (incident_id) When - Running update_alerts_in_xdr_command Then - Verify that if the incident id is not found, it returns an error. """ from CortexXDRIR import Client, update_alerts_in_xdr_command xdrIr_client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=10, proxy=False) http_request = mocker.patch.object(xdrIr_client, "_http_request") http_request.return_value = {"alerts_ids": ["1", "2", "3"]} args = {"alert_ids": "1,2,3", "severity": "high", "status": "resolved_threat_handled", "comment": "fixed from test"} with pytest.raises(DemistoException) as e: update_alerts_in_xdr_command(xdrIr_client, args) assert e.value.message == ( "Parse Error. Response not in format, can't find reply key. The response {'alerts_ids': ['1', '2', '3']}." ) def test_update_alerts_in_xdr_command_invalid_response_no_alerts_ids(mocker): """ Given: - an XDR client - arguments (incident_id) When - Running update_alerts_in_xdr_command Then - Verify that if the incident id is not found, it returns an error. """ from CortexXDRIR import Client, update_alerts_in_xdr_command xdrIr_client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=10, proxy=False) http_request = mocker.patch.object(xdrIr_client, "_http_request") http_request.return_value = {"reply": {"alerts_ids": []}} args = {"alert_ids": "1,2,3", "severity": "high", "status": "resolved_threat_handled", "comment": "fixed from test"} with pytest.raises(DemistoException) as e: update_alerts_in_xdr_command(xdrIr_client, args) assert e.value.message == "Could not find alerts to update, please make sure you used valid alert IDs." @pytest.mark.parametrize( "incident_changed, delta", [(True, {"CortexXDRIRstatus": "resolved", "close_reason": "False Positive"}), (False, {})] ) def test_update_remote_system_command_update_alerts(mocker, incident_changed, delta): """ Given: - an XDR client - arguments (incident fields) When - update_remote_system_command which triggers Running update_alerts_in_xdr_command Then - Verify alerts related to incident have been changed when closing the incident """ from CortexXDRIR import Client, update_remote_system_command client = Client( base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False, params={"close_alerts_in_xdr": True} ) data = {"CortexXDRIRstatus": "resolved", "status": "test"} expected_remote_id = "remote_id" args = { "remoteId": expected_remote_id, "data": data, "entries": [], "incidentChanged": incident_changed, "delta": delta, "status": 2, } with patch("CortexXDRIR.update_incident_command") as mock_update_incident_command: get_incident_extra_data_mock = mocker.patch.object(client, "get_incident_extra_data") get_incident_extra_data_mock.return_value = {"alerts": {"data": [{"alert_id": "123"}]}} mock_update_incident_command.return_value = {} http_request_mock = mocker.patch.object(client, "update_alerts_in_xdr_request") http_request_mock.return_value = "1,2,3" update_remote_system_command(client, args) def test_update_alerts_in_xdr_request_called_with(): """ Given: - an XDR client - arguments (incident fields) When - update_alerts_in_xdr_request is called Then - the http request is called with the right args """ alerts_ids = "1,2,3" severity = "High" status = "resolved" comment = "i am a test" from CortexXDRIR import Client client = Client( base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False, params={"close_alerts_in_xdr": True} ) with patch.object(client, "_http_request") as mock_http_request, patch("CortexXDRIR.get_headers") as get_headers_mock: mock_http_request.return_value = {"reply": {"alerts_ids": alerts_ids}} get_headers_mock.return_value = { "x-xdr-timestamp": 123, "x-xdr-nonce": 456, "x-xdr-auth-id": str(678), "Authorization": 123, } client.update_alerts_in_xdr_request(alerts_ids, severity, status, comment) mock_http_request.assert_called_once_with( method="POST", url_suffix="/alerts/update_alerts", json_data={ "request_data": { "alert_id_list": "1,2,3", "update_data": {"severity": "High", "status": "resolved", "comment": "i am a test"}, } }, headers={"x-xdr-timestamp": 123, "x-xdr-nonce": 456, "x-xdr-auth-id": "678", "Authorization": 123}, timeout=120, ) def test_update_alerts_in_xdr_request_invalid_response(): """ Given: - an XDR client - arguments (incident fields) When - update_alerts_in_xdr_request is called Then - response is not in format- raise an error """ alerts_ids = "1,2,3" severity = "High" status = "resolved" comment = "i am a test" from CortexXDRIR import Client client = Client( base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False, params={"close_alerts_in_xdr": True} ) with ( patch.object(client, "_http_request") as mock_http_request, patch("CortexXDRIR.get_headers") as get_headers_mock, pytest.raises(DemistoException) as e, ): mock_http_request.return_value = {"replys": {"alerts_ids": alerts_ids}} get_headers_mock.return_value = { "x-xdr-timestamp": 123, "x-xdr-nonce": 456, "x-xdr-auth-id": str(678), "Authorization": 123, } client.update_alerts_in_xdr_request(alerts_ids, severity, status, comment) assert e.value.message == ( "Parse Error. Response not in format, can't find reply key. The response {'replys': {'alerts_ids': '1,2,3'}}." ) def test_update_alerts_in_xdr_command(): """ Given: - an XDR client - arguments (incident fields) When - test_update_alerts_in_xdr_command is called Then - raises an error since there is no field to update """ from CommonServerPython import DemistoException from CortexXDRIR import Client, update_alerts_in_xdr_command args = {"alert_ids": "1"} client = Client( base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False, params={"close_alerts_in_xdr": True} ) with pytest.raises(DemistoException) as e: update_alerts_in_xdr_command(client, args) assert e.value.message == "Can not find a field to update for alerts ['1'], please fill in severity/status/comment." def test_main(mocker): """ Given: - Only the required params in the configuration. When: - Running a command. Then: - Validate that the code executes gracefully. """ from CortexXDRIR import main mocker.patch.object(demisto, "params", return_value={"url": "test_url"}) mocker.patch.object(demisto, "command", return_value="test-module") mock_client = mocker.patch("CortexXDRIR.Client", autospec=True) mock_client.test_module.return_value = "ok" main() @freeze_time("1993-06-17 11:00:00 GMT") def test_core_http_request_xpanse_tenant(mocker): """ Unit test to verify behavior in Xpanse tenants on the Xsiam platform with XSOAR Marketplace. This test ensures that when working with Xpanse tenants on the Xsiam platform integrated with the XSOAR Marketplace, the http_request function from CommonServerPython is used instead of _apiCall, as required in Xsiam tenants (CIAC-10878). Given: - Only the required params in the configuration. When: - Running a get_incidents to test the http_request function in CoreIRApiModule. Then: - Should fail since command '_apiCall' is not available via engine. """ from CommonServerPython import BaseClient from CortexXDRIR import Client base_url = urljoin("dummy_url", "/public_api/v1") client = Client(base_url=base_url, proxy=False, verify=False, timeout=120, params=False) mocker.patch("CoreIRApiModule.FORWARD_USER_RUN_RBAC", new=False) mocker.patch.object(demisto, "_apiCall", return_value=Exception("command '_apiCall' is not available via engine (85)")) mocker.patch.object(BaseClient, "_http_request", return_value={"reply": {"incidents": [{"incident": {"incident_id": "1"}}]}}) res = client.get_incidents(incident_id_list=["1"]) assert res == [{"incident": {"incident_id": "1"}}] def test_get_xsoar_close_reasons(mocker): mock_response = { "body": '{"sysConf":{"incident.closereasons":"CustomReason1, CustomReason 2, Foo","versn":40},"defaultMap":{}}\n', "headers": { "Content-Length": ["104"], "X-Xss-Protection": ["1; mode=block"], "X-Content-Type-Options": ["nosniff"], "Strict-Transport-Security": ["max-age=10886400000000000; includeSubDomains"], "Vary": ["Accept-Encoding"], "Server-Timing": ["7"], "Date": ["Wed, 03 Jul 2010 09:11:35 GMT"], "X-Frame-Options": ["DENY"], "Content-Type": ["application/json"], }, "status": "200 OK", "statusCode": 200, } mocker.patch.object(demisto, "internalHttpRequest", return_value=mock_response) assert get_xsoar_close_reasons() == list(XSOAR_RESOLVED_STATUS_TO_XDR.keys()) + ["CustomReason1", "CustomReason 2", "Foo"] @freeze_time("1970-01-01 00:00:00.100") def test_fetch_incidents_dedup(): """ Unit test to verify that incidents that occur in the same instant are not not missed or duplicated. Given: - Two incidents occur in the same instant. When: - Fetching incidents. Then: - Assert no incidents are missed or duplicated. """ from CortexXDRIR import fetch_incidents last_run = {"time": 0} class MockClient: _incidents = load_test_data("./test_data/get_incidents_list_dedup.json") def save_modified_incidents_to_integration_context(self): ... def get_multiple_incidents_extra_data(self, gte_creation_time_milliseconds=0, limit=100, **_): return [inc for inc in self._incidents if inc["creation_time"] >= gte_creation_time_milliseconds][:limit] mock_client = MockClient() last_run, result_1 = fetch_incidents( client=mock_client, first_fetch_time="3 days", integration_instance={}, exclude_artifacts=True, last_run=last_run, max_fetch=2, ) assert len(result_1) == 2 assert "XDR Incident 1" in result_1[0]["name"] assert "XDR Incident 2" in result_1[1]["name"] assert last_run["time"] == 100000001 assert last_run["dedup_incidents"] == ["2"] last_run, result_2 = fetch_incidents( client=mock_client, first_fetch_time="3 days", integration_instance={}, exclude_artifacts=True, last_run=last_run, max_fetch=2, ) assert len(result_2) == 2 assert "XDR Incident 3" in result_2[0]["name"] assert "XDR Incident 4" in result_2[1]["name"] assert last_run["time"] == 100000001 assert last_run["dedup_incidents"] == ["2", "3", "4"] last_run, result_3 = fetch_incidents( client=mock_client, first_fetch_time="3 days", integration_instance={}, exclude_artifacts=True, last_run=last_run, max_fetch=2, ) assert len(result_3) == 2 assert "XDR Incident 5" in result_3[0]["name"] assert "XDR Incident 6" in result_3[1]["name"] assert last_run["time"] == 100000002 assert last_run["dedup_incidents"] == ["6"] # run empty test and assert last_run stays the same old_last_run = last_run.copy() last_run, empty_result = fetch_incidents( client=mock_client, first_fetch_time="3 days", integration_instance={}, exclude_artifacts=True, last_run=last_run, max_fetch=2, ) assert empty_result == [] assert last_run == old_last_run @freeze_time("2020-11-18T13:20:00.00000", tz_offset=0) def test_get_modified_remote_data_default_xdr_delay(mocker): """ Given: - an XDR client - arguments - lastUpdate time - raw incidents (result of client.get_incidents) - xdr_delay = None When - running get_modified_remote_data_command Then - the method is returning a list of incidents IDs that were modified after adding xdr_delay """ from CommonServerPython import BaseClient from CortexXDRIR import Client, get_modified_remote_data_command mocker.patch.object(demisto, "getIntegrationContext") mocker.patch.object( BaseClient, "_http_request", return_value={"reply": {"total_count": 0, "result_count": 0, "incidents": [], "restricted_incident_ids": []}}, ) previous_last_update_time = "2020-11-18T13:15:00.000" client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) modified_incidents_empty, new_last_run_time_empty = get_modified_remote_data_command( client, { "lastUpdate": previous_last_update_time, }, previous_last_update_time, ) assert not modified_incidents_empty.modified_incident_ids assert new_last_run_time_empty == "2020-11-18 13:19:00.001" @freeze_time("2020-11-18T13:20:00.00000", tz_offset=0) def test_get_modified_remote_data_two_minutes_xdr_delay(mocker): """ Given: - an XDR client - arguments - lastUpdate time - raw incidents (result of client.get_incidents) - xdr_delay = 2 minutes When - running get_modified_remote_data_command Then - the method is returning a list of incidents IDs that were modified after adding xdr_delay """ from CommonServerPython import BaseClient from CortexXDRIR import Client, get_modified_remote_data_command mocker.patch.object(demisto, "getIntegrationContext") mocker.patch.object(BaseClient, "_http_request", return_value=load_test_data("./test_data/get_incidents_list.json")) previous_last_update_time = "2020-11-18T13:15:00.000" client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) incidents_response, new_last_time_stamp = get_modified_remote_data_command( client, {"lastUpdate": previous_last_update_time}, previous_last_update_time, xdr_delay=2 ) assert new_last_time_stamp == "2020-11-18 13:18:00.001" assert incidents_response.modified_incident_ids == ["1", "2"] @freeze_time("2020-11-18T13:20:00.00000", tz_offset=0) def test_mirror_in_empty_last_update(mocker): """ Given: - an XDR client - Empty mirror-in args - lastUpdate time = '' (e.g. {'lastUpdate': ''}) may happen the first mirror-in iteration - raw incidents (result of client.get_incidents) When - Running get_modified_remote_data_command function Then - Make sure we set a default last_update time. """ from CommonServerPython import BaseClient from CortexXDRIR import Client, get_modified_remote_data_command mocker.patch.object(demisto, "getIntegrationContext") mocker.patch.object(BaseClient, "_http_request", return_value=load_test_data("./test_data/get_incidents_list.json")) mock_debug = mocker.patch.object(demisto, "debug") client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) _, _ = get_modified_remote_data_command(client, {"lastUpdate": ""}) expected_log = "Mirror last update is: last_update='' will set it to default_last_update='2020-11-18 13:18:00'" assert mock_debug.call_args_list[1].args[0] == expected_log assert "last_update='2020-11-18 13:18:00'" in mock_debug.call_args_list[2].args[0] def test_mirror_in_wrong_last_update(mocker): """ Given: - an XDR client - Wrong mirror-in args - lastUpdate time = 'abcdefg' (e.g. {'lastUpdate': 'abcdefg'}) - raw incidents (result of client.get_incidents) When - Running get_modified_remote_data_command function Then - Make sure we raise an exception with the expected message. """ from CommonServerPython import BaseClient from CortexXDRIR import Client, get_modified_remote_data_command mocker.patch.object(demisto, "getIntegrationContext") mocker.patch.object(BaseClient, "_http_request", return_value=load_test_data("./test_data/get_incidents_list.json")) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with pytest.raises(DemistoException) as e: _, _ = get_modified_remote_data_command(client, {"lastUpdate": "abcdefg"}) assert e.value.message == "Failed to parse last_update='abcdefg' got last_update_utc=None" def test_get_distribution_url_command_without_download(): """ Given: - `download_package` argument set to False. When: - Calling `get_distribution_url_command` without downloading the package. Then: - Should return a CommandResults object with the distribution URL and no file download. """ from CoreIRApiModule import get_distribution_url_command client = MagicMock() client.get_distribution_url = MagicMock(return_value="https://example.com/distribution") args = { "distribution_id": "12345", "package_type": "x64", "download_package": "false", "integration_context_brand": "PaloAltoNetworksXDR", } result = get_distribution_url_command(client, args) client.get_distribution_url.assert_called_once_with("12345", "x64") assert isinstance(result, CommandResults) assert result.outputs == {"id": "12345", "url": "https://example.com/distribution"} assert result.outputs_prefix == "PaloAltoNetworksXDR.Distribution" assert result.outputs_key_field == "id" assert "[Distribution URL](https://example.com/distribution)" in result.readable_output def test_get_distribution_url_command_with_download(mocker): """ Given: - `download_package` set to True. When: - Calling `get_distribution_url_command` with downloading the package. Then: - Should return a list with CommandResults for the distribution URL and the downloaded file information. """ from CoreIRApiModule import get_distribution_url_command client = MagicMock() client.get_distribution_url = MagicMock(return_value="https://example.com/distribution") client._http_request = MagicMock(return_value=b"mock_binary_data") args = { "distribution_id": "12345", "package_type": "x64", "download_package": "true", "integration_context_brand": "PaloAltoNetworksXDR", } mocker.patch( "CortexXDRIR.fileResult", return_value={ "Contents": "", "ContentsFormat": "text", "Type": 3, "File": "xdr-agent-install-package.msi", "FileID": "11111", }, ) result = get_distribution_url_command(client, args) client.get_distribution_url.assert_called_once_with("12345", "x64") client._http_request.assert_called_once_with(method="GET", full_url="https://example.com/distribution", resp_type="content") assert isinstance(result, list) assert len(result) == 2 command_result = result[1] assert isinstance(command_result, CommandResults) assert command_result.outputs == {"id": "12345", "url": "https://example.com/distribution"} assert command_result.outputs_prefix == "PaloAltoNetworksXDR.Distribution" assert command_result.outputs_key_field == "id" assert "Installation package downloaded successfully." in command_result.readable_output def test_get_distribution_url_command_without_download_not_supported_type(): """ Given: - `download_package` argument set to True but package_type is not x64 or x86. When: - Calling `get_distribution_url_command` without downloading the package. Then: - Should raise a demisto error. """ from CoreIRApiModule import get_distribution_url_command client = MagicMock() client.get_distribution_url = MagicMock(return_value="https://example.com/distribution") args = { "distribution_id": "12345", "package_type": "sh", "download_package": "true", "integration_context_brand": "PaloAltoNetworksXDR", } with pytest.raises(DemistoException) as e: get_distribution_url_command(client, args) client.get_distribution_url.assert_called_once_with("12345", "sh") assert e.value.message == "`download_package` argument can be used only for package_type 'x64' or 'x86'." def test_handle_incoming_incident(capfd, mocker): """ Given: - incident data of resolved incident When - Handling incoming closing-incident (handle_incoming_closing_incident(...) executed). Then - a resolved entry is being added """ from CommonServerPython import EntryFormat, EntryType from CortexXDRIR import handle_incoming_incident custom_mapping = ( "Known Issue=Other,Duplicate Incident=Duplicate,False Positive=False Positive," "True Positive=Resolved,Security Testing=Other,Other=Other" ) mocker.patch.object( demisto, "params", return_value={"mirror_direction": "Both", "custom_xdr_to_xsoar_close_reason_mapping": custom_mapping} ) for xdr_reopen_reason in XDR_OPEN_STATUS_TO_XSOAR: incident_data = load_test_data("./test_data/resolved_incident_data.json") # Set incident status to be tested reopen-reason. incident_data["status"] = xdr_reopen_reason # Overcoming expected non-empty stderr test failures (Errors are submitted to stderr when improper mapping is provided). with capfd.disabled(): reopen_entry = handle_incoming_incident(incident_data) assert reopen_entry == { "Type": EntryType.NOTE, "Contents": {"dbotIncidentReopen": True}, "ContentsFormat": EntryFormat.JSON, } def test_get_remote_data_command_exclude_fields(mocker): """ Given: - An XDR client with base URL, headers, and mock HTTP requests - Arguments (`id` set to 1 and `lastUpdate` set to 0, which is lower than incident modification time) When: - Running `get_remote_data_command` with different combinations of `exclude_artifacts`, `excluded_alert_fields`, and `remove_nulls_from_alerts` arguments Then: - The correct `POST` request is made to the `/incidents/get_multiple_incidents_extra_data/` endpoint with the appropriate parameters - The request data contains correct filters, exclusions, and sorting options based on the provided arguments """ from CortexXDRIR import Client, get_remote_data_command client = Client(base_url=f"{XDR_URL}/public_api/v2", verify=False, timeout=120, proxy=False) args = {"id": 1, "lastUpdate": 0} mocker.patch.object(Client, "headers", return_value={"Authorization": "Bearer test_token"}) # make sure get-extra-data is returning an incident mocker.patch("CortexXDRIR.get_last_mirrored_in_time", return_value=0) mocker.patch("CortexXDRIR.check_if_incident_was_modified_in_xdr", return_value=True) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") client._http_request = MagicMock() # Test case 1: no excluded data get_remote_data_command(client, args) client._http_request.assert_called_with( method="POST", url_suffix="/incidents/get_multiple_incidents_extra_data/", json_data={ "request_data": { "search_to": 100, "sort": {"field": "creation_time", "keyword": "asc"}, "full_alert_fields": True, "search_from": 0, "filters": [{"field": "incident_id_list", "operator": "in", "value": ["1"]}], } }, headers=client.headers, timeout=120, ) # Test case 2: With excluded_alert_fields excluded_alert_fields = ["fieldA", "fieldB"] get_remote_data_command(client, args, excluded_alert_fields=excluded_alert_fields) client._http_request.assert_called_with( method="POST", url_suffix="/incidents/get_multiple_incidents_extra_data/", json_data={ "request_data": { "search_to": 100, "sort": {"field": "creation_time", "keyword": "asc"}, "full_alert_fields": True, "search_from": 0, "alert_fields_to_exclude": ["fieldA", "fieldB"], "filters": [{"field": "incident_id_list", "operator": "in", "value": ["1"]}], } }, headers=client.headers, timeout=120, ) # Test case 3: With remove_nulls_from_alerts get_remote_data_command(client, args, remove_nulls_from_alerts=True) client._http_request.assert_called_with( method="POST", url_suffix="/incidents/get_multiple_incidents_extra_data/", json_data={ "request_data": { "search_to": 100, "sort": {"field": "creation_time", "keyword": "asc"}, "full_alert_fields": True, "search_from": 0, "drop_nulls": True, "filters": [{"field": "incident_id_list", "operator": "in", "value": ["1"]}], } }, headers=client.headers, timeout=120, ) # Test case 5: With remove_nulls_from_alerts, excluded_alert_fields get_remote_data_command(client, args, remove_nulls_from_alerts=True, excluded_alert_fields=excluded_alert_fields) client._http_request.assert_called_with( method="POST", url_suffix="/incidents/get_multiple_incidents_extra_data/", json_data={ "request_data": { "search_to": 100, "sort": {"field": "creation_time", "keyword": "asc"}, "full_alert_fields": True, "search_from": 0, "alert_fields_to_exclude": ["fieldA", "fieldB"], "drop_nulls": True, "filters": [{"field": "incident_id_list", "operator": "in", "value": ["1"]}], } }, headers=client.headers, timeout=120, ) @pytest.fixture def mock_client(): from CortexXDRIR import Client mock = MagicMock(Client) mock.get_multiple_incidents_extra_data = MagicMock() return mock def test_fetch_incidents_multiple_incidents_extra_data_with_excluded_fields(mock_client): """ Given: - An XDR client. - Parameters for fetching incidents including `exclude_artifacts`, `excluded_alert_fields`, and `remove_nulls_from_alerts`. When: - Running `fetch_incidents` to fetch multiple incidents with provided parameters. Then: - The correct call is made to `get_multiple_incidents_extra_data` with expected arguments. - The call parameters correctly reflect the input values, such as filters, exclusions, and sorting options. """ from CortexXDRIR import fetch_incidents # Prepare test inputs first_fetch_time = "2023-01-01T00:00:00Z" integration_instance = "test_integration" last_run = {"time": 0, "incidents_from_previous_run": [], "dedup_incidents": []} statuses = ["open"] starred = False starred_incidents_fetch_window = None excluded_alert_fields = ["fieldA", "fieldB"] remove_nulls_from_alerts = True max_fetch = 10 fetch_incidents( mock_client, first_fetch_time=first_fetch_time, integration_instance=integration_instance, last_run=last_run, exclude_artifacts=False, max_fetch=max_fetch, statuses=statuses, starred=starred, starred_incidents_fetch_window=starred_incidents_fetch_window, excluded_alert_fields=excluded_alert_fields, remove_nulls_from_alerts=remove_nulls_from_alerts, ) mock_client.get_multiple_incidents_extra_data.assert_called_with( gte_creation_time_milliseconds=0, statuses=statuses, limit=max_fetch + len(last_run["dedup_incidents"]), starred=starred, starred_incidents_fetch_window=None, exclude_artifacts=False, excluded_alert_fields=excluded_alert_fields, remove_nulls_from_alerts=remove_nulls_from_alerts, ) def test_fetch_incidents_incidents_extra_datat_with_excluded_fields(mocker): """ Given: - An XDR client. - Parameters for fetching incidents including `exclude_artifacts`, `excluded_alert_fields`, and `remove_nulls_from_alerts`. When: - Running `fetch_incidents` to fetch multiple incidents with provided parameters. Then: - The correct call is made to `get_multiple_incidents_extra_data` with expected arguments. - The call parameters correctly reflect the input values, such as filters, exclusions, and sorting options. """ from CortexXDRIR import Client, fetch_incidents mocker.patch.object(Client, "save_modified_incidents_to_integration_context") client = Client(base_url=f"{XDR_URL}/public_api/v2", verify=False, timeout=120, proxy=False) first_fetch_time = "2023-01-01T00:00:00Z" integration_instance = "test_integration" last_run = {"time": 0, "incidents_from_previous_run": [], "dedup_incidents": []} statuses = ["open"] starred = False starred_incidents_fetch_window = None excluded_alert_fields = ["fieldA", "fieldB"] remove_nulls_from_alerts = True max_fetch = 10 raw_incident = load_test_data("./test_data/get_multiple_incidents_extra_data.json").get("reply", {}).get("incidents")[0] raw_incident["incident"]["alert_count"] = 10000 raw_incident["incident"]["incident_id"] = 11 mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=[raw_incident]) mock_get_incident_extra_data = mocker.patch.object(Client, "get_incident_extra_data", return_value=raw_incident) fetch_incidents( client, first_fetch_time=first_fetch_time, integration_instance=integration_instance, last_run=last_run, exclude_artifacts=False, max_fetch=max_fetch, statuses=statuses, starred=starred, starred_incidents_fetch_window=starred_incidents_fetch_window, excluded_alert_fields=excluded_alert_fields, remove_nulls_from_alerts=remove_nulls_from_alerts, ) # Assume the alert count is above ALERTS_LIMIT_PER_INCIDENTS mock_get_incident_extra_data.assert_called_with( incident_id=11, exclude_artifacts=False, excluded_alert_fields=excluded_alert_fields, remove_nulls_from_alerts=remove_nulls_from_alerts, ) def test_handle_excluded_data_param_old_param(): """ Given: - The `excluded_data_from_alerts` parameter with various combinations of fields to exclude. When: - Calling the `handle_excluded_data_from_alerts_param` function. Then: - Ensure that the function correctly separates `null_values` from the rest of the exclusions. - Verify that the returned tuple matches the expected exclusions list and boolean value for `null_values`. """ from CortexXDRIR import handle_excluded_data_from_alerts_param excluded_data_from_alerts = ["a", "b"] assert handle_excluded_data_from_alerts_param(excluded_data_from_alerts) == (["a", "b"], False) excluded_data_from_alerts = ["null_values", "b"] assert handle_excluded_data_from_alerts_param(excluded_data_from_alerts) == (["b"], True) def test_extract_paths_and_names_valid_mapping(): """ Given: - Dictionary mapping file paths to file names When: - Calling extract_paths_and_names Then: - Returns tuple with separate lists of paths and names """ from CortexXDRIR import extract_paths_and_names paths = ["C:\\folder\\file.exe", "/home/user/script.py", "document.txt"] file_paths, file_names = extract_paths_and_names(paths) assert set(file_paths) == {"C:\\folder\\file.exe", "/home/user/script.py", "document.txt"} assert set(file_names) == {"file.exe", "script.py", "document.txt"} assert len(file_paths) == len(file_names) == 3 def test_extract_paths_and_names_empty_mapping(): """ Given: - Empty dictionary When: - Calling extract_paths_and_names Then: - Returns tuple with empty lists """ from CortexXDRIR import extract_paths_and_names paths = [] file_paths, file_names = extract_paths_and_names(paths) assert file_paths == [] assert file_names == [] def test_extract_paths_and_names_single_item(): """ Given: - Dictionary with single mapping When: - Calling extract_paths_and_names Then: - Returns tuple with single item lists """ from CortexXDRIR import extract_paths_and_names paths = ["C:\\test\\file.exe"] file_paths, file_names = extract_paths_and_names(paths) assert file_paths == ["C:\\test\\file.exe"] assert file_names == ["file.exe"] def test_api_key_list_command(requests_mock): """ Given: - an XDR client - arguments (api_id, role, expires_before, expires_after) When - Running api_key_list_command Then - Verify the returned result is as we expected """ from CortexXDRIR import Client, api_key_list_command api_keys_response = load_test_data("./test_data/get_api_keys.json") requests_mock.post(f"{XDR_URL}/public_api/v1/api_keys/get_api_keys/", json=api_keys_response) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "api_id": "1", "role": "Admin", "expires_before": "2024-01-01T00:00:00Z", "expires_after": "2020-01-01T00:00:00Z", } response = api_key_list_command(client, args) assert response.outputs == api_keys_response["reply"]["DATA"] assert response.outputs_prefix == "PaloAltoNetworksXDR.APIKeyData" assert "API Keys" in response.readable_output def test_api_key_delete_command(requests_mock): """ Given: - an XDR client - arguments (api_id) When - Running api_key_delete_command Then - Verify the returned result is as we expected """ from CortexXDRIR import Client, api_key_delete_command requests_mock.post(f"{XDR_URL}/public_api/v1/api_keys/delete/", json={"reply": "ok"}) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"api_id": "1,2"} response = api_key_delete_command(client, args) assert response.readable_output == "API Keys deleted successfully." @freeze_time("1993-06-17 11:00:00 GMT") def test_fetch_incidents_name_generation(mocker): """ Given: - Raw incidents from XDR (V4 with incident_name and Legacy without it) When: - Running fetch_incidents Then: - Verify the incident name is generated correctly for both cases """ from CortexXDRIR import Client, fetch_incidents # 1. XDR V4 (has incident_name) # 2. XDR Legacy (no incident_name, has description) raw_incidents = [ { "incident": { "incident_id": "100", "incident_name": "V4 Incident Name", "creation_time": 740314800000, "description": "V4 Description", } }, {"incident": {"incident_id": "200", "creation_time": 740314800000, "description": "Legacy Description"}}, ] mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=raw_incidents) mocker.patch.object(Client, "save_modified_incidents_to_integration_context") mocker.patch.object(demisto, "params", return_value={"exclude_fields": False, "mirror_direction": "Incoming"}) mocker.patch("CortexXDRIR.ALERTS_LIMIT_PER_INCIDENTS", new=50) client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) _, incidents = fetch_incidents(client, "3 month", "MyInstance", exclude_artifacts=False, last_run={}) assert len(incidents) == 2 assert incidents[0]["name"] == "XDR Incident 100 - V4 Incident Name" assert incidents[1]["name"] == "XDR Incident 200 - Legacy Description" def test_get_asset_list_command(mocker): """ Given: - asset_id_list in args When: - Running get_asset_list_command Then: - Verify the client.get_asset is called and results are correct with rich data """ from CortexXDRIR import Client, get_asset_list_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"asset_id": "asset1,asset2"} mock_assets = [ { "xdm.asset.id": "asset1", "xdm.asset.name": "name1", "xdm.asset.related_issues.critical_assets": 5, "xdm.asset.related_issues.critical_issues": 10, "xdm.asset.first_observed": 1609459200000, "xdm.asset.last_observed": 1609545600000, }, { "xdm.asset.id": "asset2", "xdm.asset.name": "name2", "xdm.asset.related_issues.critical_assets": 0, "xdm.asset.related_issues.critical_issues": 1, "xdm.asset.first_observed": 1609459200000, "xdm.asset.last_observed": 1609545600000, }, ] mocker.patch.object(Client, "get_asset", side_effect=[[mock_assets[0]], [mock_assets[1]]]) res = get_asset_list_command(client, args) assert isinstance(res.outputs, list) assert len(res.outputs) == 2 assert res.outputs[0]["xdm_asset_id"] == "asset1" assert res.outputs[1]["xdm_asset_id"] == "asset2" assert res.outputs[0]["xdm_asset_related_issues_critical_assets"] == 5 assert "Cortex XDR Assets" in res.readable_output assert "asset1" in res.readable_output assert "name1" in res.readable_output assert "asset2" in res.readable_output assert "name2" in res.readable_output def test_get_asset_list_command_list(mocker): """ Given: - No asset_id in args, but filter and sort When: - Running get_asset_list_command Then: - Verify the client.list_assets is called and results are correct with rich data """ from CortexXDRIR import Client, get_asset_list_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "filter_json": '{"field": "xdm.asset.name", "operator": "contains", "value": "test"}', "sort_field": "xdm.asset.name", "sort_order": "DESC", "limit": "2", } mock_assets = [ { "xdm.asset.id": "asset1", "xdm.asset.name": "test-asset-1", "xdm.asset.related_issues.critical_assets": 1, "xdm.asset.related_issues.critical_issues": 2, "xdm.asset.first_observed": 1609459200000, "xdm.asset.last_observed": 1609545600000, }, { "xdm.asset.id": "asset2", "xdm.asset.name": "test-asset-2", "xdm.asset.related_issues.critical_assets": 0, "xdm.asset.related_issues.critical_issues": 0, "xdm.asset.first_observed": 1609459200000, "xdm.asset.last_observed": 1609545600000, }, ] mocker.patch.object(Client, "list_assets", return_value=mock_assets) res = get_asset_list_command(client, args) assert isinstance(res.outputs, list) assert len(res.outputs) == 2 assert res.outputs[0]["xdm_asset_id"] == "asset1" assert res.outputs[1]["xdm_asset_name"] == "test-asset-2" assert "Cortex XDR Assets" in res.readable_output assert "test-asset-1" in res.readable_output def test_get_asset_schema_command(mocker): """ Given: - No args When: - Running get_asset_schema_command Then: - Verify the client.get_asset_schema is called and results are correct """ from CortexXDRIR import Client, get_asset_schema_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_schema = [ {"name": "xdm.asset.id", "type": "string", "description": "Asset ID"}, {"name": "xdm.asset.name", "type": "string", "description": "Asset Name"}, {"name": "xdm.asset.status", "type": "enum", "description": "Asset Status"}, ] mocker.patch.object(Client, "get_asset_schema", return_value=mock_schema) res = get_asset_schema_command(client, {}) assert isinstance(res.outputs, list) assert res.outputs == mock_schema assert len(res.outputs) == 3 assert res.outputs[0]["name"] == "xdm.asset.id" assert res.outputs[2]["type"] == "enum" assert "Cortex XDR Asset Schema" in res.readable_output def test_get_asset_schema_field_options_command(mocker): """ Given: - field_name in args When: - Running get_asset_schema_field_options_command Then: - Verify the client.get_asset_schema_field_options is called and results are correct """ from CortexXDRIR import Client, get_asset_schema_field_options_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"field_name": "xdm.asset.status"} mock_options = [ {"value": "active", "description": "Active Asset"}, {"value": "inactive", "description": "Inactive Asset"}, {"value": "pending", "description": "Pending Asset"}, ] mocker.patch.object(Client, "get_asset_schema_field_options", return_value=mock_options) res = get_asset_schema_field_options_command(client, args) assert isinstance(res.outputs, dict) assert res.outputs["field_name"] == "xdm.asset.status" assert res.outputs["options"] == mock_options assert len(res.outputs["options"]) == 3 assert res.outputs["options"][0]["value"] == "active" assert "Cortex XDR Asset Schema Options for xdm.asset.status" in res.readable_output def test_create_asset_group_command(mocker): """ Given: - group_name, group_type, group_description, membership_predicate_json in args When: - Running create_asset_group_command Then: - Verify the client.create_asset_group is called and results are correct """ from CortexXDRIR import Client, create_asset_group_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "group_name": "group1", "group_type": "static", "group_description": "description1", "membership_predicate_json": '{"field": "xdm.asset.name", "operator": "eq", "value": "test"}', } mock_res = {"group_id": "g1", "group_name": "group1", "status": "created"} mocker.patch.object(Client, "create_asset_group", return_value=mock_res) res = create_asset_group_command(client, args) assert res.readable_output == "Asset group created successfully" assert res.raw_response == mock_res assert res.raw_response["status"] == "created" def test_delete_asset_group_command(mocker): """ Given: - group_id in args When: - Running delete_asset_group_command Then: - Verify the client.delete_asset_group is called """ from CortexXDRIR import Client, delete_asset_group_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"group_id": "g1"} mocker.patch.object(Client, "delete_asset_group") res = delete_asset_group_command(client, args) assert res.readable_output == "Asset group deleted successfully." def test_list_asset_groups_command(mocker): """ Given: - No args When: - Running list_asset_groups_command Then: - Verify the client.list_asset_groups is called and results are correct """ from CortexXDRIR import Client, list_asset_groups_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_groups = [ { "XDM.ASSET_GROUP.ID": "g1", "XDM.ASSET_GROUP.NAME": "group1", "XDM.ASSET_GROUP.TYPE": "static", "XDM.ASSET_GROUP.DESCRIPTION": "desc1", }, { "XDM.ASSET_GROUP.ID": "g2", "XDM.ASSET_GROUP.NAME": "group2", "XDM.ASSET_GROUP.TYPE": "dynamic", "XDM.ASSET_GROUP.DESCRIPTION": "desc2", }, ] mocker.patch.object(Client, "list_asset_groups", return_value=mock_groups) res = list_asset_groups_command(client, {}) assert isinstance(res.outputs, list) assert len(res.outputs) == 2 assert res.outputs[0]["XDM_ASSET_GROUP_ID"] == "g1" assert res.outputs[1]["XDM_ASSET_GROUP_NAME"] == "group2" assert "Cortex XDR Asset Groups" in res.readable_output assert "group1" in res.readable_output assert "group2" in res.readable_output def test_update_asset_group_command(mocker): """ Given: - group_id, group_name, group_type, group_description, membership_predicate_json in args When: - Running update_asset_group_command Then: - Verify the client.update_asset_group is called """ from CortexXDRIR import Client, update_asset_group_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = { "group_id": "g1", "group_name": "new_name", "group_type": "dynamic", "group_description": "new_desc", "membership_predicate_json": '{"field": "xdm.asset.name", "operator": "contains", "value": "test"}', } mocker.patch.object(Client, "update_asset_group") res = update_asset_group_command(client, args) assert res.readable_output == "Asset group updated successfully" def test_replace_dots_in_keys(): """ Given: - A data structure (dict, list, or primitive) containing keys with dots. When: - Calling replace_dots_in_keys. Then: - All dots in dictionary keys should be replaced with underscores. - Nested structures (dicts within lists, etc.) should be processed correctly. """ from CortexXDRIR import replace_dots_in_keys # Test with a simple dictionary data = {"a.b": 1, "c.d.e": "value"} expected = {"a_b": 1, "c_d_e": "value"} assert replace_dots_in_keys(data) == expected # Test with nested dictionary data = {"a.b": {"c.d": 1}} expected = {"a_b": {"c_d": 1}} assert replace_dots_in_keys(data) == expected # Test with list of dictionaries data = [{"a.b": 1}, {"c.d": 2}] expected = [{"a_b": 1}, {"c_d": 2}] assert replace_dots_in_keys(data) == expected # Test with complex nested structure data = {"outer.key": [{"inner.key": 1, "another.key": {"deep.key": "deep.value"}}, "simple string"], "primitive": 123} expected = {"outer_key": [{"inner_key": 1, "another_key": {"deep_key": "deep.value"}}, "simple string"], "primitive": 123} assert replace_dots_in_keys(data) == expected # Test with no dots data = {"key": "value", "list": [1, 2, 3]} assert replace_dots_in_keys(data) == data # Test with non-dict/list input assert replace_dots_in_keys("string.with.dots") == "string.with.dots" assert replace_dots_in_keys(123) == 123 @pytest.mark.parametrize( "file_name, file_content", [ ("test_script.py", b"print('hello world')"), ("script_with_spaces.py", b"import os\nos.listdir('.')"), ("empty_script.py", b""), ], ids=["simple-script", "multi-line-script", "empty-script"], ) def test_automation_script_create_command(mocker, tmp_path, file_name, file_content): """ Given: - An XDR client - An entry_id pointing to a file to upload as an automation script When: - Running automation_script_create_command Then: - Verify the command returns a success message - Verify the client.create_automation_script is called with the correct file data """ from CortexXDRIR import Client, automation_script_create_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) # Create a temporary file to simulate the war room file test_file = tmp_path / file_name test_file.write_bytes(file_content) mocker.patch.object(demisto, "getFilePath", return_value={"path": str(test_file), "name": file_name}) mock_create = mocker.patch.object(Client, "create_automation_script") args = {"entry_id": "test_entry_id"} result = automation_script_create_command(client, args) assert result.readable_output == "Automation script created successfully." mock_create.assert_called_once() call_args = mock_create.call_args files_arg = call_args[0][0] if call_args[0] else call_args[1]["files"] assert files_arg["file"][0] == file_name assert files_arg["file"][1] == file_content @pytest.mark.parametrize( "field, value, expected_filename", [ ("script_uid", "abc123", "automation_script_abc123"), ("script_name", "my_script", "automation_script_my_script"), ("script_uid", "uid-with-dashes", "automation_script_uid-with-dashes"), ], ids=["by-uid", "by-name", "uid-with-special-chars"], ) def test_automation_script_get_command(mocker, field, value, expected_filename): """ Given: - An XDR client - Arguments specifying a field and value to identify the script When: - Running automation_script_get_command Then: - Verify the command returns a file result with the correct filename - Verify the client.get_automation_script is called with the correct request data """ from CortexXDRIR import Client, automation_script_get_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_file_content = b"script file content bytes" mocker.patch.object(Client, "get_automation_script", return_value=mock_file_content) mock_file_result = mocker.patch( "CortexXDRIR.fileResult", return_value={"Contents": "", "ContentsFormat": "text", "Type": 3, "File": expected_filename, "FileID": "123"}, ) args = {"field": field, "value": value} result = automation_script_get_command(client, args) expected_request_data = {"request_data": {"filter": {"field": field, "value": value}}} Client.get_automation_script.assert_called_once_with(expected_request_data) mock_file_result.assert_called_once_with(filename=expected_filename, data=mock_file_content) assert result["File"] == expected_filename @pytest.mark.parametrize( "field, value", [ ("script_uid", "abc123"), ("script_name", "my_script"), ("script_uid", "uid-456"), ], ids=["delete-by-uid", "delete-by-name", "delete-by-uid-2"], ) def test_automation_script_delete_command(mocker, field, value): """ Given: - An XDR client - Arguments specifying a field and value to identify the script to delete When: - Running automation_script_delete_command Then: - Verify the command returns a success message - Verify the client.delete_automation_script is called with the correct request data """ from CortexXDRIR import Client, automation_script_delete_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_delete = mocker.patch.object(Client, "delete_automation_script") args = {"field": field, "value": value} result = automation_script_delete_command(client, args) expected_request_data = {"request_data": {"filter": {"field": field, "value": value}}} mock_delete.assert_called_once_with(expected_request_data) assert result.readable_output == "Automation script deleted successfully." @pytest.mark.parametrize( "file_name, file_content", [ ("test_playbook.json", b'{"name": "test playbook"}'), ("playbook.yml", b"name: test\nsteps:\n - step1"), ("empty_playbook.json", b""), ], ids=["json-playbook", "yaml-playbook", "empty-playbook"], ) def test_automation_playbook_create_command(mocker, tmp_path, file_name, file_content): """ Given: - An XDR client - An entry_id pointing to a file to upload as an automation playbook When: - Running automation_playbook_create_command Then: - Verify the command returns a success message - Verify the client.create_automation_playbook is called with the correct file data """ from CortexXDRIR import Client, automation_playbook_create_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) # Create a temporary file to simulate the war room file test_file = tmp_path / file_name test_file.write_bytes(file_content) mocker.patch.object(demisto, "getFilePath", return_value={"path": str(test_file), "name": file_name}) mock_create = mocker.patch.object(Client, "create_automation_playbook") args = {"entry_id": "test_entry_id"} result = automation_playbook_create_command(client, args) assert result.readable_output == "Automation playbook created successfully." mock_create.assert_called_once() call_args = mock_create.call_args files_arg = call_args[0][0] if call_args[0] else call_args[1]["files"] assert files_arg["file"][0] == file_name assert files_arg["file"][1] == file_content @pytest.mark.parametrize( "field, value, expected_filename", [ ("playbook_uid", "pb-123", "automation_playbook_pb-123"), ("playbook_name", "my_playbook", "automation_playbook_my_playbook"), ("playbook_uid", "uid-with-dashes", "automation_playbook_uid-with-dashes"), ], ids=["by-uid", "by-name", "uid-with-special-chars"], ) def test_automation_playbook_get_command(mocker, field, value, expected_filename): """ Given: - An XDR client - Arguments specifying a field and value to identify the playbook When: - Running automation_playbook_get_command Then: - Verify the command returns a file result with the correct filename - Verify the client.get_automation_playbook is called with the correct request data """ from CortexXDRIR import Client, automation_playbook_get_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_file_content = b"playbook file content bytes" mocker.patch.object(Client, "get_automation_playbook", return_value=mock_file_content) mock_file_result = mocker.patch( "CortexXDRIR.fileResult", return_value={"Contents": "", "ContentsFormat": "text", "Type": 3, "File": expected_filename, "FileID": "456"}, ) args = {"field": field, "value": value} result = automation_playbook_get_command(client, args) expected_request_data = {"request_data": {"filter": {"field": field, "value": value}}} Client.get_automation_playbook.assert_called_once_with(expected_request_data) mock_file_result.assert_called_once_with(filename=expected_filename, data=mock_file_content) assert result["File"] == expected_filename @pytest.mark.parametrize( "field, value", [ ("playbook_uid", "pb-123"), ("playbook_name", "my_playbook"), ("playbook_uid", "uid-789"), ], ids=["delete-by-uid", "delete-by-name", "delete-by-uid-2"], ) def test_automation_playbook_delete_command(mocker, field, value): """ Given: - An XDR client - Arguments specifying a field and value to identify the playbook to delete When: - Running automation_playbook_delete_command Then: - Verify the command returns a success message - Verify the client.delete_automation_playbook is called with the correct request data """ from CortexXDRIR import Client, automation_playbook_delete_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_delete = mocker.patch.object(Client, "delete_automation_playbook") args = {"field": field, "value": value} result = automation_playbook_delete_command(client, args) expected_request_data = {"request_data": {"filter": {"field": field, "value": value}}} mock_delete.assert_called_once_with(expected_request_data) assert result.readable_output == "Automation playbook deleted successfully." @pytest.mark.parametrize( "args, expected_filters, expected_sort, expected_search_from, expected_search_to", [ ( {"case_id": "100", "status": "new"}, [ {"field": "case_id", "operator": "in", "value": [100]}, {"field": "status_progress", "operator": "in", "value": ["new"]}, ], {}, # automatic pagination: no page/page_size -> window [0, default limit=50) 0, 50, ), ( {"severity": "high", "sort_field": "creation_time", "sort_order": "asc"}, [{"field": "severity", "operator": "in", "value": ["high"]}], {"field": "creation_time", "keyword": "asc"}, 0, 50, ), ( {"case_domain": "example.com", "limit": "10"}, [{"field": "case_domain", "operator": "in", "value": ["example.com"]}], {}, # automatic pagination driven by limit -> window [0, 10) 0, 10, ), ( # manual pagination with page + page_size -> limit is ignored {"case_domain": "example.com", "limit": "10", "page": "2", "page_size": "5"}, [{"field": "case_domain", "operator": "in", "value": ["example.com"]}], {}, 10, 15, ), ( # manual pagination with only page -> page_size falls back to limit (default 50) {"case_domain": "example.com", "page": "1"}, [{"field": "case_domain", "operator": "in", "value": ["example.com"]}], {}, 50, 100, ), ], ) def test_case_list_command(args, expected_filters, expected_sort, expected_search_from, expected_search_to): """ Given: - args for case list command When: - Running case_list_command Then: - Verify the client.search_cases is called with correct filters, sort and pagination window """ from CortexXDRIR import Client, case_list_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with patch.object(Client, "search_cases", return_value=[{"case_id": 1}]) as mock_search: case_list_command(client, args) call_args = mock_search.call_args[0][0] assert call_args["request_data"]["filters"] == expected_filters assert call_args["request_data"]["sort"] == expected_sort assert call_args["request_data"]["search_from"] == expected_search_from assert call_args["request_data"]["search_to"] == expected_search_to @pytest.mark.parametrize( "args, expected_search_from, expected_limit", [ # automatic pagination: default limit=50, no page/page_size -> window [0, 50) ({"extra_data": "true"}, 0, 50), # automatic pagination driven by limit -> window [0, 10) ({"extra_data": "true", "limit": "10"}, 0, 10), # manual pagination with page + page_size -> limit ignored, window [10, 15) ({"extra_data": "true", "limit": "10", "page": "2", "page_size": "5"}, 10, 15), ], ids=["auto-default", "auto-limit", "manual-paged"], ) def test_case_list_command_extra_data_pagination(mocker, args, expected_search_from, expected_limit): """ Given: - args for case list command with extra_data=true When: - Running case_list_command (extra data path) Then: - Verify client.get_multiple_incidents_extra_data is called with a paging window that respects manual ('page'/'page_size') vs automatic ('limit') pagination """ from CortexXDRIR import Client, case_list_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_extra_data = mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=[]) case_list_command(client, args) call_kwargs = mock_extra_data.call_args.kwargs assert call_kwargs["search_from"] == expected_search_from assert call_kwargs["limit"] == expected_limit @pytest.mark.parametrize( "args, expected_update_data", [ # status mapping to the exact API strings ({"case_id": "100", "status": "new"}, {"status_progress": "New"}), ({"case_id": "100", "status": "under_investigation"}, {"status_progress": "In Progress"}), # notes-only update (operational comment, e.g. a ServiceNow ticket id) ({"case_id": "100", "notes": "SNOW-12345"}, {"notes": "SNOW-12345"}), # assigned_user update ({"case_id": "100", "assigned_user": "analyst@example.com"}, {"assigned_user": "analyst@example.com"}), # user_severity update ({"case_id": "100", "user_severity": "high"}, {"user_severity": "high"}), # clearing user_severity with an explicit empty string ({"case_id": "100", "user_severity": ""}, {"user_severity": ""}), # each resolve_reason mapping (requires status Resolved) ( {"case_id": "100", "status": "resolved", "resolve_reason": "resolved_known_issue"}, {"status_progress": "Resolved", "resolve_reason": "Resolved - Known Issue"}, ), ( {"case_id": "100", "status": "resolved", "resolve_reason": "resolved_duplicate"}, {"status_progress": "Resolved", "resolve_reason": "Resolved - Duplicate Case"}, ), ( {"case_id": "100", "status": "resolved", "resolve_reason": "resolved_false_positive"}, {"status_progress": "Resolved", "resolve_reason": "Resolved - False Positive"}, ), ( {"case_id": "100", "status": "resolved", "resolve_reason": "resolved_true_positive"}, {"status_progress": "Resolved", "resolve_reason": "Resolved - True Positive"}, ), ( {"case_id": "100", "status": "resolved", "resolve_reason": "resolved_security_testing"}, {"status_progress": "Resolved", "resolve_reason": "Resolved - Security Testing"}, ), ( {"case_id": "100", "status": "resolved", "resolve_reason": "resolved_other"}, {"status_progress": "Resolved", "resolve_reason": "Resolved - Other"}, ), # resolving with a resolve_comment as well ( { "case_id": "100", "status": "resolved", "resolve_reason": "resolved_known_issue", "resolve_comment": "done", }, { "status_progress": "Resolved", "resolve_reason": "Resolved - Known Issue", "resolve_comment": "done", }, ), ], ) def test_case_update_command(args, expected_update_data): """ Given: - args for case update command When: - Running case_update_command Then: - Verify the client.update_case is called with the correct update_data payload """ from CortexXDRIR import Client, case_update_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with patch.object(Client, "update_case") as mock_update: res = case_update_command(client, args) assert res.readable_output == f"Case {args['case_id']} updated successfully" mock_update.assert_called_with(args["case_id"], request_data={"request_data": {"update_data": expected_update_data}}) @pytest.mark.parametrize( "args, expected_error", [ # resolving without a resolve_reason ( {"case_id": "100", "status": "resolved"}, "The 'resolve_reason' argument is required when resolving a case", ), # resolve_reason provided without status Resolved ( {"case_id": "100", "resolve_reason": "resolved_other"}, "can only be provided when 'status' is set to 'Resolved'", ), # resolve_comment provided without status Resolved ( {"case_id": "100", "resolve_comment": "some comment"}, "can only be provided when 'status' is set to 'Resolved'", ), # empty update (no updatable fields) ({"case_id": "100"}, "No fields to update were provided"), ], ) def test_case_update_command_errors(args, expected_error): """ Given: - args that violate the case update conditional rules When: - Running case_update_command Then: - A DemistoException is raised with a clear message and no API call is made """ from CortexXDRIR import Client, case_update_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with patch.object(Client, "update_case") as mock_update: with pytest.raises(DemistoException, match=expected_error): case_update_command(client, args) mock_update.assert_not_called() @pytest.mark.parametrize( "args, expected_update_data", [ # custom_fields valid JSON object only -> merged keys appear in update_data ( {"case_id": "100", "custom_fields": '{"my_custom_field": "value", "another_field": 42}'}, {"my_custom_field": "value", "another_field": 42}, ), # custom_fields combined with a standard field (notes) -> both present ( {"case_id": "100", "notes": "see ticket", "custom_fields": '{"my_custom_field": "value"}'}, {"notes": "see ticket", "my_custom_field": "value"}, ), # custom_fields key colliding with a standard field name must NOT override the standard value ( {"case_id": "100", "notes": "authoritative", "custom_fields": '{"notes": "override-attempt", "extra": 1}'}, {"notes": "authoritative", "extra": 1}, ), ], ) def test_case_update_command_custom_fields(args, expected_update_data): """ Given: - args for case update command including a custom_fields JSON object When: - Running case_update_command Then: - Verify the parsed custom_fields are merged into update_data and standard fields win on collision """ from CortexXDRIR import Client, case_update_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with patch.object(Client, "update_case") as mock_update: res = case_update_command(client, args) assert res.readable_output == f"Case {args['case_id']} updated successfully" mock_update.assert_called_with(args["case_id"], request_data={"request_data": {"update_data": expected_update_data}}) @pytest.mark.parametrize( "custom_fields_value", [ # invalid JSON string "{not valid json}", # valid JSON but not an object (a list) "[1, 2, 3]", # valid JSON but not an object (a bare string) '"a string"', ], ) def test_case_update_command_custom_fields_errors(custom_fields_value): """ Given: - args with a custom_fields value that is not a valid JSON object When: - Running case_update_command Then: - A DemistoException is raised with a clear message and no API call is made """ from CortexXDRIR import Client, case_update_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) args = {"case_id": "100", "custom_fields": custom_fields_value} with patch.object(Client, "update_case") as mock_update: with pytest.raises(DemistoException, match="The 'custom_fields' argument must be a valid JSON object."): case_update_command(client, args) mock_update.assert_not_called() @pytest.mark.parametrize( "mock_response, expected_count_network, expected_count_file", [ ( [ { "network_artifacts": {"DATA": [{"id": 1}], "TOTAL_COUNT": 1}, "file_artifacts": {"DATA": [{"id": 2}], "TOTAL_COUNT": 1}, } ], 1, 1, ), ( [ { "network_artifacts": {"DATA": [], "TOTAL_COUNT": 0}, "file_artifacts": {"DATA": [{"id": 2}], "TOTAL_COUNT": 1}, } ], 0, 1, ), ( [ { "network_artifacts": {"DATA": [], "TOTAL_COUNT": 0}, "file_artifacts": {"DATA": [], "TOTAL_COUNT": 0}, } ], 0, 0, ), ], ) def test_case_artifact_list_command(mock_response, expected_count_network, expected_count_file): """ Given: - mock response for get_case_artifacts When: - Running case_artifact_list_command Then: - Verify the number of returned results matches expected artifacts """ from CortexXDRIR import Client, case_artifact_list_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with patch.object(Client, "get_case_artifacts", return_value=mock_response): res = case_artifact_list_command(client, {"case_id": "100"}) if expected_count_network == 0 and expected_count_file == 0: assert len(res) == 1 assert "No artifacts found" in res[0].readable_output else: count = 0 if expected_count_network > 0: count += 1 if expected_count_file > 0: count += 1 assert len(res) == count @pytest.mark.parametrize( "args, expected_request_data", [ ( {"name": "test_bioc", "severity": "high", "page": "1", "limit": "10", "extra_data": "true"}, { "request_data": { "filters": [ {"field": "name", "operator": "EQ", "value": "test_bioc"}, {"field": "severity", "operator": "EQ", "value": "SEV_040_HIGH"}, ], "extended_view": True, "search_from": 10, "search_to": 20, } }, ), ( {}, { "request_data": { "extended_view": False, "search_from": 0, "search_to": 50, "filters": [], } }, ), ], ) def test_bioc_list_command(mocker, args, expected_request_data): """ Given: - Arguments for filtering BIOCs. When: - Running bioc_list_command. Then: - Verify the client.get_biocs is called with correct parameters. """ from CortexXDRIR import Client, bioc_list_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_reply = {"objects": [{"rule_id": "1", "name": "test_bioc", "type": "host", "severity": "high", "status": "enabled"}]} mocker.patch.object(Client, "get_biocs", return_value=mock_reply) res = bioc_list_command(client, args) assert res.outputs == mock_reply["objects"] Client.get_biocs.assert_called_with(expected_request_data) @pytest.mark.parametrize( "args, expected_request_data, expected_output, expected_error", [ ( { "name": "test_bioc", "severity": "high", "type": "bioc_type", "is_xql": "true", "comment": "test_comment", "status": "enabled", "mitre_technique_id_and_name": "T1000", "mitre_tactic_id_and_name": "TA0001", "indicator": '{"field": "value"}', }, { "request_data": [ { "rule_id": None, "name": "test_bioc", "severity": "SEV_040_HIGH", "type": "bioc_type", "is_xql": True, "comment": "test_comment", "status": "enabled", "mitre_technique_id_and_name": "T1000", "mitre_tactic_id_and_name": "TA0001", "indicator": {"field": "value"}, } ] }, {"rule_id": "1", "readable_output": "BIOC created successfully"}, None, ), ( {"name": "test_bioc", "severity": "high", "indicator": "invalid_json"}, None, None, "Unable to parse 'indicator'. Please use the JSON format.", ), ], ) def test_bioc_create_command(mocker, args, expected_request_data, expected_output, expected_error): """ Given: - Arguments for creating a BIOC. When: - Running bioc_create_command. Then: - Verify the client.insert_or_update_biocs is called and results are correct. """ from CortexXDRIR import Client, bioc_create_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_reply = {"added_objects": [{"id": "1", "status": "BIOC created successfully"}]} mocker.patch.object(Client, "insert_or_update_biocs", return_value=mock_reply) if expected_error: with pytest.raises(DemistoException) as e: bioc_create_command(client, args) assert expected_error in str(e.value) else: res = bioc_create_command(client, args) assert res.outputs == {"rule_id": expected_output["rule_id"]} assert res.readable_output == expected_output["readable_output"] Client.insert_or_update_biocs.assert_called_with(expected_request_data) @pytest.mark.parametrize( "mock_reply, expected_output, expected_readable_output", [ ( {"updated_objects": [{"id": "1", "status": "BIOC updated successfully"}]}, {"rule_id": "1"}, "BIOC updated successfully", ), ( {"updated_objects": []}, {}, "No BIOCs updated.", ), ], ) def test_bioc_update_command(mocker, mock_reply, expected_output, expected_readable_output): """ Given: - Arguments for updating a BIOC. When: - Running bioc_update_command. Then: - Verify the client.insert_or_update_biocs is called and results are correct. """ from CortexXDRIR import Client, bioc_update_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mocker.patch.object(Client, "insert_or_update_biocs", return_value=mock_reply) args = {"rule_id": "1", "name": "test_bioc", "severity": "high"} res = bioc_update_command(client, args) assert res.outputs == expected_output assert res.readable_output == expected_readable_output @pytest.mark.parametrize( "mock_reply, expected_output", [ ({"objects": ["1"]}, "BIOC with id 1 deleted successfully."), ({"objects": ["1", "2"]}, "BIOCs with ids 1, 2 deleted successfully."), ({"objects": []}, "No BIOCs were found to delete."), ], ) def test_bioc_delete_command(mocker, mock_reply, expected_output): """ Given: - Arguments for deleting a BIOC. When: - Running bioc_delete_command. Then: - Verify the client.delete_biocs is called and results are correct. """ from CortexXDRIR import Client, bioc_delete_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mocker.patch.object(Client, "delete_biocs", return_value=mock_reply) args = {"name": "test_bioc"} res = bioc_delete_command(client, args) assert res.readable_output == expected_output @pytest.mark.parametrize( "args, expected_request_data", [ ( {"name": "test_rule", "page": "1", "limit": "10", "extra_data": "true"}, { "request_data": { "filters": [{"field": "name", "operator": "EQ", "value": "test_rule"}], "extended_view": True, "search_from": 10, "search_to": 20, } }, ), ( {"filter_json": '[{"field": "name", "operator": "EQ", "value": "test_rule"}]'}, { "request_data": { "filters": [{"field": "name", "operator": "EQ", "value": "test_rule"}], "extended_view": False, "search_from": 0, "search_to": 50, } }, ), ], ) def test_correlation_rule_list_command(mocker, args, expected_request_data): """ Given: - Arguments for filtering correlation rules. When: - Running correlation_rule_list_command. Then: - Verify the client.get_correlation_rules is called and results are correct. """ from CortexXDRIR import Client, correlation_rule_list_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_reply = {"objects": [{"rule_id": "1", "name": "test_rule", "description": "desc", "is_enabled": True}]} mocker.patch.object(Client, "get_correlation_rules", return_value=mock_reply) res = correlation_rule_list_command(client, args) assert res.outputs == mock_reply["objects"] Client.get_correlation_rules.assert_called_with(expected_request_data) @pytest.mark.parametrize( "args, expected_request_data, expected_output", [ ( { "name": "test_rule", "severity": "high", "xql_query": "dataset = xdr_data", "is_enabled": "true", "timezone": "UTC", "dataset": "xdr_data", "alert_category": "category", "execution_mode": "real_time", "mapping_strategy": "strategy", "description": "desc", "alert_name": "alert", "alert_description": "alert_desc", "search_window": "1h", "schedule_linux": "* * * * *", "schedule": "daily", "drilldown_query_timeframe": "1h", "investigation_query_link": "link", "suppression_enabled": "true", "suppression_duration": "1h", "suppression_fields": "field1", "user_defined_severity": "medium", "user_defined_category": "cat", "mitre_defs_json": '{"tactic": "test"}', "alert_fields": '{"field": "value"}', }, { "request_data": [ { "rule_id": None, "name": "test_rule", "severity": "SEV_040_HIGH", "xql_query": "dataset = xdr_data", "is_enabled": True, "action": "ALERTS", "timezone": "UTC", "dataset": "xdr_data", "alert_category": "CATEGORY", "execution_mode": "REAL_TIME", "mapping_strategy": "STRATEGY", "description": "desc", "alert_name": "alert", "alert_description": "alert_desc", "search_window": "1h", "crontab": "* * * * *", "simple_schedule": "daily", "drilldown_query_timeframe": "1h", "investigation_query_link": "link", "suppression_enabled": True, "suppression_duration": "1h", "suppression_fields": "field1", "user_defined_severity": "medium", "user_defined_category": "cat", "mitre_defs": {"tactic": "test"}, "alert_fields": {"field": "value"}, } ] }, {"rule_id": "1", "readable_output": "Rule created successfully"}, ) ], ) def test_correlation_rule_create_command(mocker, args, expected_request_data, expected_output): """ Given: - Arguments for creating a correlation rule. When: - Running correlation_rule_create_command. Then: - Verify the client.create_or_update_correlation_rules is called and results are correct. """ from CortexXDRIR import Client, correlation_rule_create_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_reply = {"added_objects": [{"id": "1", "status": "Rule created successfully"}]} mocker.patch.object(Client, "create_or_update_correlation_rules", return_value=mock_reply) res = correlation_rule_create_command(client, args) assert res.outputs == {"rule_id": expected_output["rule_id"]} assert res.readable_output == expected_output["readable_output"] Client.create_or_update_correlation_rules.assert_called_with(expected_request_data) @pytest.mark.parametrize( "args, expected_request_data, expected_output", [ ( {"rule_id": "1", "name": "test_rule", "severity": "high", "is_enabled": "true"}, { "request_data": [ { "rule_id": "1", "name": "test_rule", "severity": "SEV_040_HIGH", "xql_query": None, "is_enabled": True, "action": "ALERTS", "timezone": None, "dataset": None, "alert_category": None, "execution_mode": None, "mapping_strategy": None, "description": None, "alert_name": None, "alert_description": None, "search_window": None, "crontab": None, "simple_schedule": None, "drilldown_query_timeframe": None, "investigation_query_link": None, "suppression_enabled": None, "suppression_duration": None, "suppression_fields": None, "user_defined_severity": None, "user_defined_category": None, "mitre_defs": {}, "alert_fields": {}, } ] }, {"rule_id": "1", "readable_output": "Rule updated successfully"}, ) ], ) def test_correlation_rule_update_command(mocker, args, expected_request_data, expected_output): """ Given: - Arguments for updating a correlation rule. When: - Running correlation_rule_update_command. Then: - Verify the client.create_or_update_correlation_rules is called and results are correct. """ from CortexXDRIR import Client, correlation_rule_update_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_reply = {"updated_objects": [{"id": "1", "status": "Rule updated successfully"}]} mocker.patch.object(Client, "create_or_update_correlation_rules", return_value=mock_reply) res = correlation_rule_update_command(client, args) assert res.outputs == {"rule_id": expected_output["rule_id"]} assert res.readable_output == expected_output["readable_output"] Client.create_or_update_correlation_rules.assert_called_with(expected_request_data) @pytest.mark.parametrize( "mock_reply, args, expected_output, expected_filters", [ ( {"objects": ["1"], "objects_count": 1}, {"rule_id": "1"}, "Correlation Rule 1 was deleted.", {"request_data": {"filters": [{"field": "rule_id", "operator": "EQ", "value": 1}]}}, ), ( {"objects": ["1", "2"], "objects_count": 2}, {"rule_id": "1,2"}, "Correlation Rules 1, 2 were deleted.", { "request_data": { "filters": [ {"field": "rule_id", "operator": "EQ", "value": 1}, {"field": "rule_id", "operator": "EQ", "value": 2}, ] } }, ), ( {"objects": [], "objects_count": 0}, {"rule_id": "1"}, "Could not find any correlation rules to delete.", {"request_data": {"filters": [{"field": "rule_id", "operator": "EQ", "value": 1}]}}, ), ( {"objects": ["1"], "objects_count": 1}, {"rule_id": "1,invalid"}, "Correlation Rule 1 was deleted.", {"request_data": {"filters": [{"field": "rule_id", "operator": "EQ", "value": 1}]}}, ), ], ) def test_correlation_rule_delete_command(mocker, mock_reply, args, expected_output, expected_filters): """ Given: - Arguments for deleting correlation rules. When: - Running correlation_rule_delete_command. Then: - Verify the client.delete_correlation_rules is called and results are correct. """ from CortexXDRIR import Client, correlation_rule_delete_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mocker.patch.object(Client, "delete_correlation_rules", return_value=mock_reply) res = correlation_rule_delete_command(client, args) assert res.readable_output == expected_output Client.delete_correlation_rules.assert_called_with(expected_filters) def test_create_filters_for_bioc_and_correlation_rules_all_fields(): """ Given: - All possible arguments for creating filters. When: - Running create_filters_for_bioc_and_correlation_rules. Then: - Verify the returned filters list contains all expected filters. """ from CortexXDRIR import create_filters_for_bioc_and_correlation_rules args = { "name": "test_name", "severity": "high", "type": "bioc_type", "is_xql": "true", "comment": "test_comment", "status": "enabled", "indicator": "test_indicator", "mitre_technique_id_and_name": "T1000,T1001", "mitre_tactic_id_and_name": "TA0001,TA0002", "xql_query": "test_query", "is_enabled": "true", "description": "test_description", "alert_name": "test_alert_name", "alert_category": "test_alert_category", "alert_description": "test_alert_description", "alert_fields": "field1,field2", "execution_mode": "real_time", "search_window": "1h", "schedule": "daily", "timezone": "UTC", "schedule_linux": "* * * * *", "suppression_enabled": "true", "suppression_duration": "1h", "suppression_fields": "field1", "dataset": "xdr_data", "user_defined_severity": "medium", "user_defined_category": "category", "mitre_defs_json": '{"tactic": "test"}', "investigation_query_link": "link", "drilldown_query_timeframe": "1h", "mapping_strategy": "strategy", "alert_domain": "domain", } filters = create_filters_for_bioc_and_correlation_rules(args) assert {"field": "name", "operator": "EQ", "value": "test_name"} in filters assert {"field": "severity", "operator": "EQ", "value": "SEV_040_HIGH"} in filters assert {"field": "type", "operator": "EQ", "value": "bioc_type"} in filters assert {"field": "is_xql", "operator": "EQ", "value": True} in filters assert {"field": "comment", "operator": "EQ", "value": "test_comment"} in filters assert {"field": "status", "operator": "EQ", "value": "enabled"} in filters assert {"field": "indicator", "operator": "EQ", "value": "test_indicator"} in filters assert {"field": "mitre_technique_id_and_name", "operator": "EQ", "value": ["T1000", "T1001"]} in filters assert {"field": "mitre_tactic_id_and_name", "operator": "EQ", "value": ["TA0001", "TA0002"]} in filters assert {"field": "xql_query", "operator": "EQ", "value": "test_query"} in filters assert {"field": "is_enabled", "operator": "EQ", "value": True} in filters assert {"field": "description", "operator": "EQ", "value": "test_description"} in filters assert {"field": "alert_name", "operator": "EQ", "value": "test_alert_name"} in filters assert {"field": "alert_category", "operator": "EQ", "value": "test_alert_category"} in filters assert {"field": "alert_description", "operator": "EQ", "value": "test_alert_description"} in filters assert {"field": "alert_fields", "operator": "EQ", "value": ["field1", "field2"]} in filters assert {"field": "execution_mode", "operator": "EQ", "value": "real_time"} in filters assert {"field": "search_window", "operator": "EQ", "value": "1h"} in filters assert {"field": "schedule", "operator": "EQ", "value": "daily"} in filters assert {"field": "timezone", "operator": "EQ", "value": "UTC"} in filters assert {"field": "schedule_linux", "operator": "EQ", "value": "* * * * *"} in filters assert {"field": "suppression_enabled", "operator": "EQ", "value": True} in filters assert {"field": "suppression_duration", "operator": "EQ", "value": "1h"} in filters assert {"field": "suppression_fields", "operator": "EQ", "value": "field1"} in filters assert {"field": "dataset", "operator": "EQ", "value": "xdr_data"} in filters assert {"field": "user_defined_severity", "operator": "EQ", "value": "medium"} in filters assert {"field": "user_defined_category", "operator": "EQ", "value": "category"} in filters assert {"field": "mitre_defs", "operator": "EQ", "value": {"tactic": "test"}} in filters assert {"field": "investigation_query_link", "operator": "EQ", "value": "link"} in filters assert {"field": "drilldown_query_timeframe", "operator": "EQ", "value": "1h"} in filters assert {"field": "mapping_strategy", "operator": "EQ", "value": "strategy"} in filters assert {"field": "alert_domain", "operator": "EQ", "value": "domain"} in filters @pytest.mark.parametrize( "mock_response, args, expected_outputs_prefix, expected_hr_contains", [ ( { "vulnerabilityID": "CVE-2021-44228", "description": "Apache Log4j2 RCE", "cvss": {"score": 10.0}, "publishedDate": "2021-12-10", }, {"vulnerability_id": "CVE-2021-44228"}, "PaloAltoNetworksXDR.Vulnerability", "CVE-2021-44228", ), ( { "vulnerabilityID": "CVE-2023-0001", "description": "Test vulnerability", "cvss": {}, "publishedDate": None, }, {"vulnerability_id": "CVE-2023-0001"}, "PaloAltoNetworksXDR.Vulnerability", "CVE-2023-0001", ), ], ) def test_get_vulnerability_details_command(mocker, mock_response, args, expected_outputs_prefix, expected_hr_contains): """ Given: - A vulnerability ID to look up When: - Running get_vulnerability_details_command Then: - Verify the returned CommandResults contains the expected vulnerability data """ from CortexXDRIR import Client, get_vulnerability_details_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mocker.patch.object(Client, "get_vulnerability_details", return_value=mock_response) result = get_vulnerability_details_command(client, args) assert result.outputs_prefix == expected_outputs_prefix assert result.outputs_key_field == "vulnerabilityID" assert result.outputs == mock_response assert result.raw_response == mock_response assert expected_hr_contains in result.readable_output assert "Vulnerability Details" in result.readable_output def test_endpoint_triage_preset_list_command(mocker): """ Given: - An XDR client When: - Running endpoint_triage_preset_list_command Then: - Verify the returned CommandResults contains the expected presets """ from CortexXDRIR import Client, endpoint_triage_preset_list_command mock_presets = [ { "name": "Full Triage", "uuid": "uuid-1234", "os": "windows", "type": "full", "created_by": "admin", "description": "Full triage preset", }, { "name": "Quick Triage", "uuid": "uuid-5678", "os": "linux", "type": "quick", "created_by": "admin", "description": "Quick triage preset", }, ] client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mocker.patch.object(Client, "get_triage_presets", return_value=mock_presets) result = endpoint_triage_preset_list_command(client) assert result.outputs_prefix == "PaloAltoNetworksXDR.EndpointTriagePreset" assert result.outputs_key_field == "uuid" assert result.outputs == mock_presets assert result.raw_response == mock_presets assert len(result.outputs) == 2 assert "Endpoint Triage Presets" in result.readable_output assert "Full Triage" in result.readable_output assert "Quick Triage" in result.readable_output def test_endpoint_triage_preset_list_command_empty(mocker): """ Given: - An XDR client with no triage presets When: - Running endpoint_triage_preset_list_command Then: - Verify the returned CommandResults contains an empty list """ from CortexXDRIR import Client, endpoint_triage_preset_list_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mocker.patch.object(Client, "get_triage_presets", return_value=[]) result = endpoint_triage_preset_list_command(client) assert result.outputs == [] assert result.outputs_prefix == "PaloAltoNetworksXDR.EndpointTriagePreset" @pytest.mark.parametrize( "mock_response, expected_status_text", [ ({"status": "OK"}, "Cortex XDR health status: OK"), ({"status": "ERROR"}, "Cortex XDR health status: ERROR"), ({}, "Cortex XDR health status: unknown"), ], ) def test_healthcheck_run_command(mocker, mock_response, expected_status_text): """ Given: - An XDR client When: - Running healthcheck_run_command Then: - Verify the returned CommandResults contains the expected health status """ from CortexXDRIR import Client, healthcheck_run_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mocker.patch.object(Client, "run_healthcheck", return_value=mock_response) result = healthcheck_run_command(client) assert result.outputs_prefix == "PaloAltoNetworksXDR.HealthStatus" assert result.outputs == mock_response assert result.raw_response == mock_response assert expected_status_text in result.readable_output @pytest.mark.parametrize( "args, expected_request_data", [ ( {"endpoint_id": "agent1,agent2"}, {"request_data": {"agent_ids": ["agent1", "agent2"]}}, ), ( {"endpoint_id": "agent1", "collector_uuid": "preset-uuid-123"}, {"request_data": {"agent_ids": ["agent1"], "collector_uuid": "preset-uuid-123"}}, ), ( {"endpoint_id": "agent1"}, {"request_data": {"agent_ids": ["agent1"]}}, ), ], ) def test_endpoint_triage_command(mocker, args, expected_request_data): """ Given: - Endpoint IDs and optional collector_uuid When: - Running endpoint_triage_command Then: - Verify the client.triage_endpoint is called with correct request data - Verify the returned CommandResults contains the expected outputs """ from CortexXDRIR import Client, endpoint_triage_command mock_reply = { "TRIAGE_ID": "triage-123", "SUCCESSFUL_AGENT_IDS": ["agent1"], "UNSUCCESSFUL_AGENT_IDS": [], } client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_triage = mocker.patch.object(Client, "triage_endpoint", return_value=mock_reply) result = endpoint_triage_command(client, args) mock_triage.assert_called_once_with(expected_request_data) assert result.outputs_prefix == "PaloAltoNetworksXDR.EndpointTriage" assert result.outputs == mock_reply assert result.raw_response == mock_reply assert "Triage Endpoint Results" in result.readable_output @pytest.mark.parametrize( "args, expected_filters, expected_sort", [ ( {"issue_id": "100", "status": "new"}, [ {"field": "id", "operator": "in", "value": [100]}, {"field": "status.progress", "operator": "in", "value": ["New"]}, ], {}, ), ( {"severity": "high", "sort_field": "severity", "sort_order": "desc"}, [{"field": "severity", "operator": "in", "value": ["high"]}], {"field": "severity", "keyword": "desc"}, ), ( {"domain": "network", "limit": "10"}, [{"field": "issue_domain", "operator": "in", "value": ["network"]}], {}, ), ( {"external_id": "ext-1,ext-2"}, [{"field": "external_id", "operator": "in", "value": ["ext-1", "ext-2"]}], {}, ), ( {"detection_method": "xdr_agent"}, [{"field": "detection.method", "operator": "in", "value": ["xdr_agent"]}], {}, ), ( {"sort_field": "issue_id", "sort_order": "asc"}, [], {"field": "id", "keyword": "asc"}, ), ], ) def test_list_issues_command(args, expected_filters, expected_sort): """ Given: - args for issue list command When: - Running list_issues_command Then: - Verify the client.list_issues is called with correct filters and sort arguments """ from CortexXDRIR import Client, list_issues_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with patch.object(Client, "list_issues", return_value=[{"id": 1, "name": "test issue"}]) as mock_list: result = list_issues_command(client, args) call_args = mock_list.call_args[0][0] if expected_filters: assert call_args["request_data"]["filters"] == expected_filters else: assert "filters" not in call_args["request_data"] if expected_sort: assert call_args["request_data"]["sort"] == expected_sort else: assert "sort" not in call_args["request_data"] assert result.outputs_prefix == "PaloAltoNetworksXDR.Issue" assert result.outputs_key_field == "id" assert "Issues" in result.readable_output @pytest.mark.parametrize( "args, expected_issue_data", [ ( { "name": "Test Issue", "description": "A test issue", "observation_time": "2024-01-01T00:00:00Z", "domain": "network", "category": "security", "severity": "high", }, { "name": "Test Issue", "description": "A test issue", "issue_domain": "network", "category": "security", "severity": "HIGH", }, ), ( { "name": "Issue with extras", "description": "Extended issue", "observation_time": "2024-01-01T00:00:00Z", "domain": "identity", "category": "compliance", "severity": "medium", "type": "misconfiguration", "is_excluded": "true", "is_starred": "false", "assigned_to": "admin@example.com", "asset_id": "asset-1,asset-2", }, { "name": "Issue with extras", "description": "Extended issue", "issue_domain": "identity", "category": "compliance", "severity": "MEDIUM", "type": "misconfiguration", "is_excluded": True, "is_starred": False, "assigned_to": "admin@example.com", "asset_ids": ["asset-1", "asset-2"], }, ), ], ) def test_create_issue_command(args, expected_issue_data): """ Given: - args for issue create command When: - Running create_issue_command Then: - Verify the client.create_issue is called with correct issue data - Verify the returned CommandResults contains the expected outputs """ from CortexXDRIR import Client, create_issue_command mock_reply = {"external_id": "ext-123", "id": 1} client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with patch.object(Client, "create_issue", return_value=mock_reply) as mock_create: result = create_issue_command(client, args) call_args = mock_create.call_args[0][0] issue_data = call_args["request_data"]["issue"] for key, value in expected_issue_data.items(): assert issue_data[key] == value assert result.outputs_prefix == "PaloAltoNetworksXDR.Issue" assert result.outputs_key_field == "external_id" assert result.outputs == mock_reply assert "Created Issue" in result.readable_output def test_create_issue_command_invalid_json(): """ Given: - args with invalid JSON in normalized_fields_json When: - Running create_issue_command Then: - Verify a DemistoException is raised for invalid JSON """ from CortexXDRIR import Client, create_issue_command args = { "name": "Test", "description": "desc", "observation_time": "2024-01-01T00:00:00Z", "domain": "network", "category": "security", "severity": "high", "normalized_fields_json": "invalid-json{", } client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with pytest.raises(DemistoException, match="Invalid JSON format in field"): create_issue_command(client, args) @pytest.mark.parametrize( "args, expected_update_data", [ ( {"issue_id": "100", "status": "new"}, {"status": "New"}, ), ( {"issue_id": "200", "severity": "high"}, {"severity": "HIGH"}, ), ( { "issue_id": "300", "status": "resolved", "resolve_reason": "resolved_false_positive", "resolve_comment": "Not a real issue", }, { "status": "Resolved", "status_resolution_reason": "resolved - false positive", "status_resolution_comment": "Not a real issue", }, ), ( {"issue_id": "400", "status": "in_progress", "severity": "low"}, {"severity": "LOW", "status": "In Progress"}, ), ( { "issue_id": "500", "resolve_reason": "resolved_known_issue", }, { "status_resolution_reason": "resolved - known issue", }, ), ], ) def test_update_issue_command(args, expected_update_data): """ Given: - args for issue update command When: - Running update_issue_command Then: - Verify the client.update_issue is called with correct arguments - Verify the readable output confirms the update """ from CortexXDRIR import Client, update_issue_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) with patch.object(Client, "update_issue") as mock_update: result = update_issue_command(client, args) assert result.readable_output == f"Issue with ID {args['issue_id']} updated successfully" mock_update.assert_called_with(args["issue_id"], {"request_data": {"update_data": expected_update_data}}) def test_normalize_case_data_record_maps_fields_and_nests_data(): """ Given: - A raw record from the get_multiple_incidents_extra_data endpoint, wrapped in an "incident" key and containing nested alerts, file_artifacts and network_artifacts. When: - Running normalize_case_data_record (used by the xdr-case-list extra_data path). Then: - Incident fields are renamed to their case-shaped equivalents (e.g. incident_id -> case_id). - Nested alerts/artifacts are surfaced under Issues/FileArtifacts/NetworkArtifacts. - Each nested record inherits the parent case_id when one is not already set. """ from CortexXDRIR import normalize_case_data_record incident_record = { "incident": { "incident_id": "100", "incident_name": "My Case", "status": "new", "incident_domain": "example.com", "alert_count": 3, "description": "some description", }, "alerts": {"data": [{"alert_id": "a1"}, {"alert_id": "a2", "case_id": "999"}]}, "file_artifacts": {"data": [{"name": "file.exe"}]}, "network_artifacts": {"data": [{"ip": "1.2.3.4"}]}, } case = normalize_case_data_record(incident_record) # Renamed incident fields. assert case["case_id"] == "100" assert case["case_name"] == "My Case" assert case["status_progress"] == "new" assert case["case_domain"] == "example.com" assert case["issue_count"] == 3 # Fields without a mapping are kept as-is. assert case["description"] == "some description" assert "incident_id" not in case # Nested data surfaced under the case-shaped keys. assert case["Issues"] == [ {"alert_id": "a1", "case_id": "100"}, {"alert_id": "a2", "case_id": "999"}, ] assert case["FileArtifacts"] == [{"name": "file.exe", "case_id": "100"}] assert case["NetworkArtifacts"] == [{"ip": "1.2.3.4", "case_id": "100"}] def test_normalize_case_data_record_flat_record_without_nested_data(): """ Given: - A flat record (no "incident" wrapper) and without any nested alerts/artifacts. When: - Running normalize_case_data_record. Then: - The flat fields are mapped and no Issues/FileArtifacts/NetworkArtifacts keys are added. """ from CortexXDRIR import normalize_case_data_record case = normalize_case_data_record({"incident_id": "200", "incident_name": "Flat Case"}) assert case["case_id"] == "200" assert case["case_name"] == "Flat Case" assert "Issues" not in case assert "FileArtifacts" not in case assert "NetworkArtifacts" not in case def test_case_list_command_extra_data_returns_normalized_cases(mocker): """ Given: - args for the case list command with extra_data=true. - The client returns raw extra-data records with nested alerts/artifacts. When: - Running case_list_command. Then: - The extra-data client method is used (search_cases is NOT called). - The outputs are normalized into case-shaped records (mapped fields + nested data). - The CommandResults metadata (outputs_prefix, key field, raw_response) is correct. """ from CortexXDRIR import Client, case_list_command raw_records = [ { "incident": { "incident_id": "100", "incident_name": "My Case", "status": "new", "incident_domain": "example.com", }, "alerts": {"data": [{"alert_id": "a1"}]}, "file_artifacts": {"data": [{"name": "file.exe"}]}, "network_artifacts": {"data": [{"ip": "1.2.3.4"}]}, } ] client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_extra_data = mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=raw_records) mock_search = mocker.patch.object(Client, "search_cases") result = case_list_command(client, {"extra_data": "true", "case_id": "100"}) # The extra-data path was taken, not the regular search path. mock_extra_data.assert_called_once() mock_search.assert_not_called() assert result.outputs_prefix == "PaloAltoNetworksXDR.Case" assert result.outputs_key_field == "case_id" assert result.raw_response == raw_records assert isinstance(result.outputs, list) assert len(result.outputs) == 1 case = result.outputs[0] assert case["case_id"] == "100" assert case["case_name"] == "My Case" assert case["case_domain"] == "example.com" assert case["Issues"] == [{"alert_id": "a1", "case_id": "100"}] assert case["FileArtifacts"] == [{"name": "file.exe", "case_id": "100"}] assert case["NetworkArtifacts"] == [{"ip": "1.2.3.4", "case_id": "100"}] def test_case_list_command_extra_data_maps_sort_field(mocker): """ Given: - args for the case list command with extra_data=true and sort_field=case_id. When: - Running case_list_command. Then: - The case-shaped sort field is translated to the incident-shaped sort field (case_id -> incident_id) before calling the extra-data client method. """ from CortexXDRIR import Client, case_list_command client = Client(base_url=f"{XDR_URL}/public_api/v1", verify=False, timeout=120, proxy=False) mock_extra_data = mocker.patch.object(Client, "get_multiple_incidents_extra_data", return_value=[]) case_list_command(client, {"extra_data": "true", "sort_field": "case_id", "sort_order": "asc"}) call_kwargs = mock_extra_data.call_args.kwargs assert call_kwargs["sort_field"] == "incident_id" assert call_kwargs["sort_order"] == "asc"