Skip to content

Commit

Permalink
Xdr alert mrroring (demisto#33685)
Browse files Browse the repository at this point in the history
* add comment

* fix

* fix

* tests

* mirroring alerts

* fixe get alerts

* DELETE DEBUG

* SPACE

* del,ete dev

* fix

* tests

* pre-commit

* pre-commit

* fix params close

* RN

* fix readme

* add test

* fix

* Updated docker image to demisto/pcap-miner:1.0.0.91369. PR batch #1/3 (demisto#33830)

* Updated docker image to demisto/pcap-miner:1.0.0.91369. PR batch #2/3 (demisto#33831)

Co-authored-by: Tal Zichlinsky <[email protected]>

* fix rn

* fix merge of auto docker

* fix merge docker related

* add test

* pre-commit

* cr

* FIX CR

* fix

* revert

* fix

* fix tests

* remove dev

* fix raw

* fix

* fix comment

* fix dev

* Bump pack from version CortexXDR to 6.1.29.

* fix after alerts changed

* Apply suggestions from code review

doc review

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

* Merge remote-tracking branch 'origin' into xdr_alert_mrroring

* Apply suggestions from code review

docs and adi

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

* cr

* fix

* fix test

* assign params

* fix debug

* FIX PALYBOOK

* fix test

* delete informatinal

* 6_1_30

* fix playbook

* add version

* rn31

* Bump pack from version CortexXDR to 6.1.32.

* fix rn

* fix

* fix 33

* fix

* Bump pack from version CortexXDR to 6.1.35.

* Bump pack from version CortexXDR to 6.1.36.

* Bump pack from version CortexXDR to 6.1.37.

* docker image

---------

Co-authored-by: samuelFain <[email protected]>
Co-authored-by: Tal Zichlinsky <[email protected]>
Co-authored-by: Content Bot <[email protected]>
Co-authored-by: ShirleyDenkberg <[email protected]>
Co-authored-by: Adi Bamberger Edri <[email protected]>
  • Loading branch information
6 people authored May 22, 2024
1 parent 89f98fe commit 210e2f0
Show file tree
Hide file tree
Showing 8 changed files with 949 additions and 222 deletions.
78 changes: 77 additions & 1 deletion Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,23 @@ def get_multiple_incidents_extra_data(self, incident_id_list=[], fields_to_exclu
incidents = reply.get('reply')
return incidents.get('incidents', {}) if isinstance(incidents, dict) else incidents # type: ignore

def update_alerts_in_xdr_request(self, alerts_ids, severity, status, comment) -> List[Any]:
request_data = {"request_data": {
"alert_id_list": alerts_ids,
}}
update_data = assign_params(severity=severity, status=status, comment=comment)
request_data['request_data']['update_data'] = update_data
response = self._http_request(
method='POST',
url_suffix='/alerts/update_alerts',
json_data=request_data,
headers=self.headers,
timeout=self.timeout,
)
if "reply" not in response or "alerts_ids" not in response["reply"]:
raise DemistoException(f"Parse Error. Response not in format, can't find reply key. The response {response}.")
return response['reply']['alerts_ids']


def get_headers(params: dict) -> dict:
api_key = params.get('apikey_creds', {}).get('password', '') or params.get('apikey', '')
Expand Down Expand Up @@ -471,10 +488,12 @@ def update_incident_command(client, args):
assigned_user_mail = args.get('assigned_user_mail')
assigned_user_pretty_name = args.get('assigned_user_pretty_name')
status = args.get('status')
demisto.debug(f"this_is_the_status {status}")
severity = args.get('manual_severity')
unassign_user = args.get('unassign_user') == 'true'
resolve_comment = args.get('resolve_comment')
add_comment = args.get('add_comment')
resolve_alerts = argToBoolean(args.get('resolve_alerts', False))

if assigned_user_pretty_name and not assigned_user_mail:
raise DemistoException('To set a new assigned_user_pretty_name, '
Expand All @@ -490,6 +509,10 @@ def update_incident_command(client, args):
resolve_comment=resolve_comment,
add_comment=add_comment,
)
is_closed = resolve_comment or (status and argToList(status, '_')[0] == 'RESOLVED')
if resolve_alerts and is_closed:
args['status'] = args['status'].lower()
update_related_alerts(client, args)

return f'Incident {incident_id} has been updated', None, None

Expand Down Expand Up @@ -954,16 +977,28 @@ def update_remote_system_command(client, args):
if remote_args.delta:
demisto.debug(f'Got the following delta keys {str(list(remote_args.delta.keys()))} to update'
f'incident {remote_args.remote_incident_id}')
demisto.debug(f'{remote_args.delta=}')
try:
if remote_args.incident_changed:
demisto.debug(f"update_remote_system_command {incident_id=} {remote_args.incident_changed=}")
update_args = get_update_args(remote_args)

update_args['incident_id'] = remote_args.remote_incident_id
demisto.debug(f'Sending incident with remote ID [{remote_args.remote_incident_id}]\n')
demisto.debug(f"Before checking status {update_args=}")
is_closed = (update_args.get('close_reason') or update_args.get('closeReason') or update_args.get('closeNotes')
or update_args.get('resolve_comment') or update_args.get('closingUserId'))
closed_without_status = not update_args.get('close_reason') and not update_args.get('closeReason')
if is_closed and closed_without_status:
update_args['status'] = XSOAR_RESOLVED_STATUS_TO_XDR.get('Other')
demisto.debug(f"After checking status {update_args=}")
update_incident_command(client, update_args)

close_alerts_in_xdr = argToBoolean(client._params.get("close_alerts_in_xdr", False))
# Check all relevant fields for an incident being closed in XSOAR UI
demisto.debug(f"Defining whether to close related alerts by: {is_closed=} {close_alerts_in_xdr=}")
if close_alerts_in_xdr and is_closed:
update_related_alerts(client, update_args)

else:
demisto.debug(f'Skipping updating remote incident fields [{remote_args.remote_incident_id}] '
f'as it is not new nor changed')
Expand All @@ -977,6 +1012,23 @@ def update_remote_system_command(client, args):
return remote_args.remote_incident_id


def update_related_alerts(client: Client, args: dict):
new_status = args.get('status')
incident_id = args.get('incident_id')
comment = f"Resolved by XSOAR, due to incident {incident_id} that has been resolved."
demisto.debug(f"{new_status=}, {comment=}")
if not new_status:
raise DemistoException(f"Failed to update alerts related to incident {incident_id},"
"no status found")
incident_extra_data = client.get_incident_extra_data(incident_id)
if 'alerts' in incident_extra_data and 'data' in incident_extra_data['alerts']:
alerts_array = incident_extra_data['alerts']['data']
related_alerts_ids_array = [str(alert['alert_id']) for alert in alerts_array if 'alert_id' in alert]
demisto.debug(f"{related_alerts_ids_array=}")
args_for_command = {'alert_ids': related_alerts_ids_array, 'status': new_status, 'comment': comment}
return_results(update_alerts_in_xdr_command(client, args_for_command))


def fetch_incidents(client, first_fetch_time, integration_instance, last_run: dict = None, max_fetch: int = 10,
statuses: List = [], starred: Optional[bool] = None, starred_incidents_fetch_window: str = None,
fields_to_exclude: bool = True):
Expand Down Expand Up @@ -1176,6 +1228,27 @@ def replace_featured_field_command(client: Client, args: Dict) -> CommandResults
)


def update_alerts_in_xdr_command(client: Client, args: Dict) -> CommandResults:
alerts_list = argToList(args.get('alert_ids'))
array_of_all_ids = []
severity = args.get('severity')
status = args.get('status')
comment = args.get('comment')
if not severity and not status and not comment:
raise DemistoException(
f"Can not find a field to update for alerts {alerts_list}, please fill in severity/status/comment.")
# API is limited to 100 alerts per request, doing the request in batches of 100.
for index in range(0, len(alerts_list), 100):
alerts_sublist = alerts_list[index:index + 100]
demisto.debug(f'{alerts_sublist=}, {severity=}, {status=}, {comment=}')
array_of_sublist_ids = client.update_alerts_in_xdr_request(alerts_sublist, severity, status, comment)
array_of_all_ids += array_of_sublist_ids
if not array_of_all_ids:
raise DemistoException("Could not find alerts to update, please make sure you used valid alert IDs.")
return CommandResults(readable_output="Alerts with IDs {} have been updated successfully.".format(",".join(array_of_all_ids))
)


def main(): # pragma: no cover
"""
Executes an integration command
Expand Down Expand Up @@ -1601,6 +1674,9 @@ def main(): # pragma: no cover
elif command in ('xdr-set-user-role', 'xdr-remove-user-role'):
return_results(change_user_role_command(client, args))

elif command == 'xdr-update-alert':
return_results(update_alerts_in_xdr_command(client, args))

except Exception as err:
return_error(str(err))

Expand Down
52 changes: 51 additions & 1 deletion Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ configuration:
type: 8
section: Collect
advanced: true
- display: Close all related alerts in XDR
name: close_alerts_in_xdr
required: false
additionalinfo: "Close all related alerts in Cortex XDR once an incident has been closed in Cortex XSOAR."
advanced: true
type: 8
section: Collect
description: Cortex XDR is the world's first detection and response app that natively integrates network, endpoint, and cloud data to stop sophisticated attacks.
display: Palo Alto Networks Cortex XDR - Investigation and Response
name: Cortex XDR - IR
Expand Down Expand Up @@ -631,6 +638,13 @@ script:
- 'true'
- description: Add a comment to the incident.
name: add_comment
- auto: PREDEFINED
description: Whether to resolve alerts related to a resolved incident. The incident is considered resolved when the status argument includes the "RESOLVED" or "resolve_comment" value.
name: resolve_alerts
predefined:
- 'true'
- 'false'
defaultValue: 'false'
description: 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.
name: xdr-update-incident
- arguments:
Expand Down Expand Up @@ -3493,7 +3507,43 @@ script:
isArray: true
name: xdr-remove-user-role
description: Remove one or more users from a role.
dockerimage: demisto/python3:3.10.14.91134
- arguments:
- description: A comma-separated list of alert IDs.
name: alert_ids
required: true
isArray: true
- auto: PREDEFINED
description: Required severity to update alerts to.
name: severity
required: false
predefined:
- critical
- high
- medium
- low
- auto: PREDEFINED
description: New status for updated alerts.
name: status
required: false
predefined:
- new
- resolved_threat_handled
- under_investigation
- resolved_security_testing
- resolved_auto
- resolved_known_issue
- resolved_duplicate
- resolved_other
- resolved_false_positive
- resolved_true_positive
- description: Comment to append to updated alerts.
name: comment
required: false
description: |-
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.
name: xdr-update-alert
dockerimage: demisto/python3:3.10.14.92207
isfetch: true
isfetch:xpanse: false
script: ''
Expand Down
Loading

0 comments on commit 210e2f0

Please sign in to comment.