id: splunk
name: Splunk
version: 1.1.0
description: "Splunk (REST API, management port 8089) — run SPL searches with notable/CIM finding ingestion and an OCSF mapper, manage search jobs, indexes and event submission (incl. HEC), full KV Store collection/entry management, and user administration. Token or basic authentication."
changelog: "1.1.0 — Full coverage: search jobs (create/status/results), indexes listing, event submission (receivers/simple + HEC), and the complete KV Store command set (collection create/config/delete, list, data list/add/delete, entry search/delete/update). 1.0.0 — Initial release: SPL search (oneshot) ingestion with a bundled OCSF mapper for notable/CIM events, get_users, delete_user and a KV Store entry update."
category: siem

# Per-instance configuration. The REST API lives on the Splunk management port (default 8089),
# NOT the web port. Token auth uses an authentication token (Settings → Tokens); basic auth
# uses a username + password. HEC fields are only needed for splunk-submit-event-hec.
config_schema:
  properties:
    host:
      type: string
      description: "Splunk server host or URL (e.g. splunk.example.com or https://splunk.example.com)"
    port:
      type: string
      description: "REST management port (default 8089)"
      default: "8089"
    auth_type:
      type: string
      description: "Authentication method: token (Bearer authentication token) or basic (username + password)"
      default: token
    username:
      type: string
      description: "Username (basic auth only)"
    password:
      type: string
      description: "Authentication token (token auth) or password (basic auth)"
      x-soar-sensitive: true
    app:
      type: string
      description: "Default app namespace for KV Store operations (default 'search')"
      default: search
    hec_url:
      type: string
      description: "HTTP Event Collector base URL for splunk-submit-event-hec (e.g. https://splunk.example.com:8088)"
    hec_token:
      type: string
      description: "HTTP Event Collector token for splunk-submit-event-hec"
      x-soar-sensitive: true
    verify:
      type: boolean
      description: "Verify the server TLS certificate (default false; Splunk often uses self-signed certs)"
      default: false
  required:
    - host
    - password

# Documented for reference; the bundled scripts build the Authorization header themselves.
# token: Authorization: Bearer <token>   basic: Authorization: Basic base64(user:pass)
auth:
  - id: apikey
    type: api_key
    in: header
    name: Authorization
    value_template: "Bearer {{secret}}"
    secret_field: password

commands:
  # ── Ingestion / search ────────────────────────────────────────────────────
  - id: search
    name: splunk-search
    description: "Run an SPL search (oneshot) and return the result rows. Use as an ingestion source by searching for notable events; results are under the 'results' array."
    risk: read
    inputs_schema:
      properties:
        query: { type: string, description: "SPL query (a leading 'search ' is added automatically if missing)" }
        earliest: { type: string, description: "Earliest time (e.g. -24h, -7d@d, or an epoch); incremental fetch watermark" }
        latest: { type: string, description: "Latest time (e.g. now)" }
        limit: { type: number, description: "Maximum result rows (default 100)" }
        app: { type: string, description: "App namespace to run the search in (defaults to the instance 'app' config)" }
      required: [query]
    outputs_schema: { properties: {} }
    ingest:
      results_path: results
      dedup_key: event_id
      incremental_field: earliest

  # ── Search jobs ───────────────────────────────────────────────────────────
  - id: job_create
    name: splunk-job-create
    description: "Dispatch an asynchronous search job and return its sid. Poll with splunk-job-status, then fetch with splunk-job-results."
    risk: read
    inputs_schema:
      properties:
        query: { type: string, description: "SPL query (a leading 'search ' is added automatically if missing)" }
        earliest: { type: string, description: "Earliest time (e.g. -24h)" }
        latest: { type: string, description: "Latest time (e.g. now)" }
        app: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
      required: [query]
    outputs_schema: { properties: {} }
  - id: job_status
    name: splunk-job-status
    description: "Return the status (dispatchState, doneProgress, resultCount) of a search job by sid."
    risk: read
    inputs_schema:
      properties:
        sid: { type: string, description: "Search job id" }
      required: [sid]
    outputs_schema: { properties: {} }
  - id: job_results
    name: splunk-job-results
    description: "Fetch the results of a completed search job by sid."
    risk: read
    inputs_schema:
      properties:
        sid: { type: string, description: "Search job id" }
        offset: { type: number, description: "Result offset (default 0)" }
        limit: { type: number, description: "Maximum result rows (default 100; 0 = all)" }
      required: [sid]
    outputs_schema: { properties: {} }

  # ── Indexes & event submission ────────────────────────────────────────────
  - id: get_indexes
    name: splunk-get-indexes
    description: "List the indexes configured on the Splunk instance with their event counts and sizes."
    risk: read
    inputs_schema:
      properties: {}
      required: []
    outputs_schema: { properties: {} }
  - id: submit_event
    name: splunk-submit-event
    description: "Submit a single event to an index via the REST receivers/simple endpoint."
    inputs_schema:
      properties:
        index: { type: string, description: "Target index name" }
        event: { type: string, description: "Event payload (raw string)" }
        sourcetype: { type: string, description: "Sourcetype to assign (optional)" }
        source: { type: string, description: "Source to assign (optional)" }
        host: { type: string, description: "Host to assign (optional)" }
      required: [index, event]
    outputs_schema: { properties: {} }
  - id: submit_event_hec
    name: splunk-submit-event-hec
    description: "Submit an event through the HTTP Event Collector (HEC). Requires hec_url and hec_token in the instance config."
    inputs_schema:
      properties:
        event: { type: string, description: "Event payload (string or JSON object as a string)" }
        index: { type: string, description: "Target index (optional)" }
        sourcetype: { type: string, description: "Sourcetype (optional)" }
        source: { type: string, description: "Source (optional)" }
        host: { type: string, description: "Host (optional)" }
        fields: { type: object, description: "Indexed fields object (optional)" }
      required: [event]
    outputs_schema: { properties: {} }

  # ── User management ───────────────────────────────────────────────────────
  - id: get_users
    name: splunk-get-users
    description: "List Splunk users with their roles and metadata."
    risk: read
    inputs_schema:
      properties: {}
      required: []
    outputs_schema: { properties: {} }
  - id: delete_user
    name: splunk-delete-user
    description: "Delete a Splunk user by username."
    inputs_schema:
      properties:
        username: { type: string, description: "Username to delete" }
      required: [username]
    outputs_schema: { properties: {} }

  # ── KV Store: collections ─────────────────────────────────────────────────
  - id: kv_store_collections_list
    name: splunk-kv-store-collections-list
    description: "List the KV Store collections defined in an app."
    risk: read
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
      required: []
    outputs_schema: { properties: {} }
  - id: kv_store_collection_create
    name: splunk-kv-store-collection-create
    description: "Create a new KV Store collection in an app."
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
        kv_store_name: { type: string, description: "Name of the collection to create" }
      required: [kv_store_name]
    outputs_schema: { properties: {} }
  - id: kv_store_collection_config
    name: splunk-kv-store-collection-config
    description: "Define field types on a KV Store collection (e.g. field.name=string). Pass a JSON object mapping field name to type."
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
        kv_store_collection_name: { type: string, description: "Collection name" }
        fields: { type: object, description: "Object mapping field name to type (string|number|bool|time|cidr)" }
      required: [kv_store_collection_name, fields]
    outputs_schema: { properties: {} }
  - id: kv_store_collection_delete
    name: splunk-kv-store-collection-delete
    description: "Delete a KV Store collection and all of its data."
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
        kv_store_collection_name: { type: string, description: "Collection name to delete" }
      required: [kv_store_collection_name]
    outputs_schema: { properties: {} }

  # ── KV Store: data ────────────────────────────────────────────────────────
  - id: kv_store_collection_add_entries
    name: splunk-kv-store-collection-add-entries
    description: "Insert one or more entries into a KV Store collection (batch_save). Pass a JSON array of objects."
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
        kv_store_collection_name: { type: string, description: "Collection name" }
        entries: { type: array, description: "Array of entry objects to insert" }
      required: [kv_store_collection_name, entries]
    outputs_schema: { properties: {} }
  - id: kv_store_collection_data_list
    name: splunk-kv-store-collection-data-list
    description: "List all entries in a KV Store collection."
    risk: read
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
        kv_store_collection_name: { type: string, description: "Collection name" }
        limit: { type: number, description: "Maximum entries (default 0 = all)" }
      required: [kv_store_collection_name]
    outputs_schema: { properties: {} }
  - id: kv_store_collection_data_delete
    name: splunk-kv-store-collection-data-delete
    description: "Delete ALL entries in a KV Store collection (the collection itself is kept)."
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
        kv_store_collection_name: { type: string, description: "Collection name" }
      required: [kv_store_collection_name]
    outputs_schema: { properties: {} }
  - id: kv_store_collection_search_entry
    name: splunk-kv-store-collection-search-entry
    description: "Search entries in a KV Store collection with a Mongo-style query (JSON object)."
    risk: read
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
        kv_store_collection_name: { type: string, description: "Collection name" }
        query: { type: object, description: "Mongo-style query object, e.g. {\"name\": \"foo\"}" }
      required: [kv_store_collection_name, query]
    outputs_schema: { properties: {} }
  - id: kv_store_collection_delete_entry
    name: splunk-kv-store-collection-delete-entry
    description: "Delete entries in a KV Store collection matching a Mongo-style query (JSON object)."
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
        kv_store_collection_name: { type: string, description: "Collection name" }
        query: { type: object, description: "Mongo-style query object selecting entries to delete" }
      required: [kv_store_collection_name, query]
    outputs_schema: { properties: {} }
  - id: kv_store_update_entry
    name: splunk-kv-store-update-entry
    description: "Update a single field of an existing KV Store entry by key, preserving the other fields."
    inputs_schema:
      properties:
        app_name: { type: string, description: "App namespace (defaults to the instance 'app' config)" }
        kv_store_collection_name: { type: string, description: "KV Store collection name" }
        entry_key: { type: string, description: "The _key of the entry to update" }
        field_name: { type: string, description: "Field to update" }
        new_value: { type: string, description: "New value for the field" }
      required: [kv_store_collection_name, entry_key, field_name, new_value]
    outputs_schema: { properties: {} }

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

ingestion:
  command: search
  mapper: search
  default_incident_type: "Splunk Notable"
