id: sentinelone_sdl
name: SentinelOne SDL
version: 1.0.0
description: "SentinelOne SDL (Security Data Lake) Unified Alerts via the GraphQL API — alert ingestion with rich filtering, full alert details, status/verdict/assignee updates, analyst notes and mitigation actions."
changelog: "1.0.0 — Initial release: unified alert ingestion (get_alerts) with an exhaustive OCSF mapper, alert details, update (status/verdict/assignee), add note and trigger mitigation action."
category: endpoint

# Per-instance configuration. The Unified Alerts GraphQL endpoint is on the
# tenant console URL; authentication uses an API token (ApiToken scheme).
config_schema:
  properties:
    url:
      type: string
      description: "SentinelOne console URL, e.g. https://tenant.sentinelone.net"
    api_token:
      type: string
      description: "SentinelOne API token"
      x-soar-sensitive: true
  required:
    - url
    - api_token

auth:
  - id: apitoken
    type: api_key
    in: header
    name: Authorization
    value_template: "ApiToken {{secret}}"
    secret_field: api_token

commands:
  # ── Ingestion ───────────────────────────────────────────────────────────────
  - id: get_alerts
    name: sentinelone-sdl-get-alerts
    description: "Fetch Unified Alerts with optional filters. Used for ingestion: results path = data (edges are flattened to alert nodes)."
    risk: read
    inputs_schema:
      properties:
        severity: { type: string, description: "Comma-separated severities (CRITICAL,HIGH,MEDIUM,LOW,INFO)" }
        status: { type: string, description: "Comma-separated statuses (NEW,IN_PROGRESS,RESOLVED)" }
        classification: { type: string, description: "Comma-separated classifications (MALWARE,RANSOMWARE,TROJAN,...)" }
        os_type: { type: string, description: "Comma-separated OS types (WINDOWS,LINUX,MACOS)" }
        attack_surface: { type: string, description: "Comma-separated attack surfaces (ENDPOINT,CLOUD,IDENTITY,NETWORK,EMAIL)" }
        analyst_verdict: { type: string, description: "Comma-separated analyst verdicts" }
        asset_id: { type: string, description: "Filter by asset ID" }
        external_id: { type: string, description: "Filter by external ID" }
        search_text: { type: string, description: "Full-text search on the alert name" }
        start_time: { type: string, description: "Lower bound on detectedAt (ISO-8601, epoch, or relative like '24 hours'). Incremental fetch watermark." }
        end_time: { type: string, description: "Upper bound on detectedAt (ISO-8601, epoch, or relative)" }
        unassigned_only: { type: string, description: "Only unassigned alerts (true/false)" }
        unmitigated_only: { type: string, description: "Only unmitigated alerts (true/false)" }
        limit: { type: number, description: "Maximum number of alerts (default 50, max 200)" }
      required: []
    outputs_schema: { properties: {} }
    ingest:
      results_path: data
      dedup_key: id
      incremental_field: start_time

  - id: get_alert_details
    name: sentinelone-sdl-get-alert-details
    description: "Get the full details of a single alert, including indicators, observables and related alerts."
    risk: read
    inputs_schema:
      properties:
        alert_id: { type: string, description: "Alert ID" }
      required: [alert_id]
    outputs_schema: { properties: {} }

  - id: update_alert
    name: sentinelone-sdl-update-alert
    description: "Update an alert: status, analyst verdict and/or assignee."
    risk: safe_write
    inputs_schema:
      properties:
        alert_id: { type: string, description: "Alert ID" }
        status: { type: string, description: "New status (NEW, IN_PROGRESS, RESOLVED)" }
        analyst_verdict: { type: string, description: "Analyst verdict (TRUE_POSITIVE_MALWARE, FALSE_POSITIVE_BENIGN, UNDEFINED, ...)" }
        assignee_user_id: { type: string, description: "User ID to assign (leave empty to skip)" }
      required: [alert_id]
    outputs_schema: { properties: {} }

  - id: add_note
    name: sentinelone-sdl-add-note
    description: "Add an analyst note to an alert."
    risk: safe_write
    inputs_schema:
      properties:
        alert_id: { type: string, description: "Alert ID" }
        note_text: { type: string, description: "Note content" }
      required: [alert_id, note_text]
    outputs_schema: { properties: {} }

  - id: trigger_action
    name: sentinelone-sdl-trigger-action
    description: "Trigger a mitigation action on an alert (e.g. QUARANTINE, KILL, REMEDIATE)."
    risk: destructive
    inputs_schema:
      properties:
        alert_id: { type: string, description: "Alert ID" }
        action_id: { type: string, description: "Action ID to trigger" }
        action_type: { type: string, description: "Action type (QUARANTINE, UNQUARANTINE, KILL, REMEDIATE, BLOCKLIST_ADD, EXCLUSION_ADD)" }
      required: [alert_id, action_id]
    outputs_schema: { properties: {} }

  # ── Connectivity test ─────────────────────────────────────────────────────
  - id: test_connection
    name: sentinelone-sdl-test-connection
    description: "Verify connectivity and credentials (used by the Test button)."
    risk: read
    inputs_schema:
      properties: {}
      required: []
    outputs_schema: { properties: {} }

ingestion:
  command: get_alerts
  mapper: get_alerts
  default_incident_type: "SentinelOne SDL Alert"
