import json, os, sys S = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}")) I = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}")) def out(value): print(json.dumps(value, default=str)) def fail(message, **extra): payload = {"error": message} payload.update(extra) print(json.dumps(payload, default=str)) sys.exit(1) def as_bool(v): return v if isinstance(v, bool) else str(v).lower() in ("1", "true", "yes") def as_int(v, default=None): try: return int(v) except (TypeError, ValueError): return default def as_list(v): if isinstance(v, list): return v if v in (None, ""): return [] return [x.strip() for x in str(v).split(",") if x.strip()] try: from pycti import OpenCTIApiClient except ImportError as e: fail("The 'pycti' Python library is required for the OpenCTI integration. " "Install it on the execution host (engine): pip install pycti", detail=str(e)) def client(): base = str(S.get("base_url", "")).strip().rstrip("/") api_key = S.get("api_key") or (S.get("credentials") or {}).get("password") return OpenCTIApiClient(base, api_key, ssl_verify=not as_bool(S.get("insecure")), log_level="error") def get_incidents(client, search="", created_by=None, creator=None, created_after=None, created_before=None, incident_types=None, label=None, limit=500, last_run_id=None, get_all=False): filters = {"mode": "and", "filters": [], "filterGroups": []} if label: filters["filters"].append({"key": "objectLabel", "values": [label], "operator": "eq", "mode": "or"}) if created_by: filters["filters"].append({"key": "createdBy", "values": [created_by], "operator": "eq", "mode": "or"}) if creator: filters["filters"].append({"key": "creator_id", "values": [creator], "operator": "eq"}) if incident_types: filters["filters"].append({"key": "incident_types", "values": incident_types, "operator": "eq", "mode": "or"}) if created_after: filters["filters"].append({"key": "created_at", "values": [created_after], "operator": "gt"}) if created_before: filters["filters"].append({"key": "created_at", "values": [created_before], "operator": "lt"}) return client.incident.list( after=last_run_id, first=limit, withPagination=True, getAll=get_all, filters=filters, search=search ) search = I.get("search", "") created_by = I.get("created_by") creator = I.get("creator") created_after = I.get("created_after") created_before = I.get("created_before") incident_types = as_list(I.get("incident_types")) label = I.get("label_id") limit = as_int(I.get("limit", 500), 500) last_run_id = I.get("last_run_id") get_all = as_bool(I.get("all_results", "false")) try: raw = get_incidents( client(), search=search, created_by=created_by, creator=creator, created_after=created_after, created_before=created_before, incident_types=incident_types, label=label, limit=limit, last_run_id=last_run_id, get_all=get_all, ) except Exception as e: fail("Can't list incidents from OpenCTI.", detail=str(e)) last_run = None if get_all else raw.get("pagination", {}).get("endCursor") incidents_list = raw if get_all else raw.get("entities", []) normalized = [] for incident in incidents_list: normalized.append({ "id": incident.get("id"), "name": incident.get("name"), "description": incident.get("description"), "source": incident.get("source"), "confidence": incident.get("confidence"), "severity": incident.get("severity"), "objective": incident.get("objective"), "createdBy": (incident.get("createdBy") or {}).get("name") or "", "creators": [c.get("name") for c in incident.get("creators", [])], "labels": [l.get("value") for l in incident.get("objectLabel", [])], "incidentTypes": incident.get("incident_types"), "created": incident.get("created"), "updatedAt": incident.get("updated_at"), }) out({"entities": normalized, "pagination": {"endCursor": last_run}})