GIBDRPIncidentUpdate
This script prevents duplication of existing incidents. This automation runs using the default Limited User role, unless you explicitly change the permissions. For more information, see the section about permissions here: https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/6.10/Cortex-XSOAR-Administrator-Guide/Automations
python · Group-IB Digital Risk Protection
Source
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 import json from typing import Any IGNORE_UPDATE_KEYS = { "id", "investigationId", } REMOVE_BEFORE_UPDATE_KEYS = { "CustomFields", "labels", "occurred", "sla", } def _escape_lucene_phrase(value: str) -> str: if not isinstance(value, str): value = str(value) value = value.replace("\x00", "") value = value.replace("\r", " ").replace("\n", " ") return value.replace("\\", "\\\\").replace('"', '\\"') def _extract_gibdrp_id(current_incident: dict[str, Any]) -> str | None: custom_fields = current_incident.get("CustomFields") or {} gibdrpid = custom_fields.get("gibdrpid") if gibdrpid: demisto.debug(f"GIBDRPIncidentUpdate: extracted gibdrpid from CustomFields: {gibdrpid}") return gibdrpid top_level = current_incident.get("gibdrpid") if top_level: demisto.debug(f"GIBDRPIncidentUpdate: extracted gibdrpid from top-level: {top_level}") return top_level raw_json_str = current_incident.get("rawJSON") if isinstance(raw_json_str, str) and raw_json_str: try: raw_obj = json.loads(raw_json_str) if not isinstance(raw_obj, dict): demisto.debug( "GIBDRPIncidentUpdate: rawJSON parsed but is not a dict; " f"type={type(raw_obj).__name__}. Skipping rawJSON extraction." ) raw_obj = {} raw_id = raw_obj.get("id") if raw_id: demisto.debug(f"GIBDRPIncidentUpdate: extracted gibdrpid from rawJSON.id: {raw_id}") return raw_id raw_nested_id = (raw_obj.get("violation") or {}).get("id") if raw_nested_id: demisto.debug(f"GIBDRPIncidentUpdate: extracted gibdrpid from rawJSON.violation.id: {raw_nested_id}") return raw_nested_id except Exception as e: demisto.debug(f"GIBDRPIncidentUpdate: failed to parse rawJSON: {e!s}") mirror_id = current_incident.get("dbotMirrorId") if mirror_id: demisto.debug(f"GIBDRPIncidentUpdate: extracted gibdrpid from dbotMirrorId: {mirror_id}") return mirror_id demisto.debug("GIBDRPIncidentUpdate: gibdrpid not found in CustomFields, top-level, rawJSON or dbotMirrorId") return None def _build_update_payload(current_incident: dict[str, Any]) -> dict[str, Any]: demisto.debug(f"GIBDRPIncidentUpdate: building update payload, incoming keys: {list(current_incident.keys())}") prepared: dict[str, Any] = {} base = dict(current_incident) custom_fields = base.get("CustomFields") or {} removed_keys: list[str] = [] for key in REMOVE_BEFORE_UPDATE_KEYS: if key in base: base.pop(key, None) removed_keys.append(key) if removed_keys: demisto.debug(f"GIBDRPIncidentUpdate: removed transient keys before update: {removed_keys}") prepared.update(base) prepared.update(custom_fields) for forbidden in IGNORE_UPDATE_KEYS: prepared.pop(forbidden, None) demisto.debug(f"GIBDRPIncidentUpdate: prepared payload keys: {list(prepared.keys())}") return prepared def _search_existing_incident_by_gibdrpid(gibdrpid: str) -> dict[str, Any] | None: query = f'gibdrpid:"{_escape_lucene_phrase(gibdrpid)}"' demisto.debug(f"GIBDRPIncidentUpdate: searching for duplicates with query: {query}") search_incident = demisto.executeCommand("getIncidents", {"query": query}) if not search_incident: demisto.debug("GIBDRPIncidentUpdate: getIncidents returned empty result") return None contents = (search_incident[0] or {}).get("Contents") or {} total = int(contents.get("total", 0) or 0) data = contents.get("data") or [] demisto.debug(f"GIBDRPIncidentUpdate: search results - total: {total}, items: {len(data) if isinstance(data, list) else 0}") if total <= 0 or not isinstance(data, list) or len(data) == 0: demisto.debug("GIBDRPIncidentUpdate: no existing incident found") return None chosen = data[-1] demisto.debug(f"GIBDRPIncidentUpdate: chosen existing incident id: {chosen.get('id')}") return chosen def prevent_duplication(current_incident: dict[str, Any]) -> bool: demisto.debug( "GIBDRPIncidentUpdate: received incident for preprocessing - " f"type={current_incident.get('type')}, id={current_incident.get('id')}, " f"hasCustomFields={bool(current_incident.get('CustomFields'))}" ) gibdrpid = _extract_gibdrp_id(current_incident) if not gibdrpid: demisto.debug("GIBDRPIncidentUpdate: gibdrpid not found on incoming incident; allowing creation.") return True existing = _search_existing_incident_by_gibdrpid(gibdrpid) if not existing: demisto.debug("GIBDRPIncidentUpdate: no duplicates found, creating new incident.") return True incident_id = existing.get("id") incident_gibdrpid = existing.get("gibdrpid") update_payload = _build_update_payload(current_incident) demisto.debug(f"GIBDRPIncidentUpdate: applying {len(update_payload)} fields to incident {incident_id}") for key, value in update_payload.items(): demisto.debug( f"GIBDRPIncidentUpdate: Update incident key: {key} value: {value} " f"DataUpdate incident id: {incident_id} incident_gibdrpid: {incident_gibdrpid}" ) demisto.executeCommand("setIncident", {"id": incident_id, key: value}) demisto.debug(f"GIBDRPIncidentUpdate: Updated incident id: {incident_id} incident_gibdrpid: {incident_gibdrpid}") return False def main(): try: demisto.debug("GIBDRPIncidentUpdate: main invoked") return_results(prevent_duplication(demisto.incident())) except Exception as e: demisto.debug(f"GIBDRPIncidentUpdate: exception occurred: {e!s}") return_error(f"Error: {str(e)}") if __name__ in ("__main__", "__builtin__", "builtins"): main()
README
This script prevents duplication of existing incidents.
Permissions
This automation runs using the default Limited User role, unless you explicitly change the permissions.
For more information, see the section about permissions here: https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/6.10/Cortex-XSOAR-Administrator-Guide/Automations
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Tags | preProcessing |
| Cortex XSOAR Version | 6.0.0 |
Inputs
There are no inputs for this script.
Outputs
There are no outputs for this script.