id: opencti
name: OpenCTI
version: 1.0.0
description: "OpenCTI threat-intelligence platform (GraphQL API, compatible with OpenCTI 5.x/6.x). Query and manage observables, indicators, incidents, relationships, labels, markings, organizations and external references; ingest OpenCTI incidents with an OCSF mapper. Runs on a remote engine. Requires the Python 'pycti' library on the engine host (pip install pycti)."
changelog: "1.0.0 — Initial release: observables (list/create/delete/field update/add/remove), indicators (list/create/update/field add/remove, types), incidents (list/create/delete, types) with OCSF ingestion mapper, relationships (list/create/delete), and reference data (organizations, labels, marking definitions, external references)."
category: threat_intel

# Per-instance configuration. The integration talks to the OpenCTI GraphQL API at
# <base_url>/graphql using the user API key. Run it on a remote engine that can
# reach the OpenCTI platform. The bundled scripts require the Python 'pycti'
# library on the engine host: pip install pycti
config_schema:
  properties:
    base_url:
      type: string
      description: "OpenCTI base URL, e.g. https://opencti.company.com (scripts append /graphql)"
    api_key:
      type: string
      description: "OpenCTI API key (user profile → API access → API KEY)"
      x-soar-sensitive: true
    insecure:
      type: boolean
      description: "Trust any TLS certificate (not secure)"
      default: false
  required:
    - base_url
    - api_key

# Documented for reference; pycti builds the Authorization header itself from the
# api_key (Bearer token) when the scripts construct the client.
auth:
  - id: apikey
    type: api_key
    in: header
    name: Authorization
    value_template: "Bearer {{secret}}"
    secret_field: api_key

commands:
  # ── Observables ───────────────────────────────────────────────────────────
  - id: get_observables
    name: opencti-get-observables
    description: "List/search observables, optionally filtered by type, score and free text."
    risk: read
    inputs_schema:
      properties:
        limit: { type: number, description: "Max observables to return (default 50, max 500)" }
        score_start: { type: number, description: "Minimum score to filter by (0-100)" }
        score_end: { type: number, description: "Maximum score to filter by (0-100)" }
        score: { type: string, description: "A specific score (0-100) or 'Unknown'" }
        observable_types: { type: string, description: "Comma-separated types: ALL, Account, Domain, Email, File, Host, IP, IPv6, Registry Key, URL (default ALL)" }
        last_run_id: { type: string, description: "Pagination cursor from a previous call (OpenCTI.Observables.LastRunID)" }
        search: { type: string, description: "Observable value to filter by (partial allowed)" }
        all_results: { type: boolean, description: "Fetch all results, ignoring limit (default false)" }
      required: []
    outputs_schema: { properties: {} }
  - id: observable_create
    name: opencti-observable-create
    description: "Create a new observable (optionally creating a related indicator)."
    risk: safe_write
    inputs_schema:
      properties:
        type: { type: string, description: "Observable type: Account, Domain, Email, File-MD5, File-SHA1, File-SHA256, Host, IP, IPv6, Registry Key, URL" }
        value: { type: string, description: "Observable value" }
        created_by: { type: string, description: "Organization ID (see organization_list)" }
        marking_id: { type: string, description: "Marking definition ID (see marking_definition_list)" }
        label_id: { type: string, description: "Label ID (see label_list / label_create)" }
        external_references_id: { type: string, description: "External reference ID (see external_reference_create)" }
        description: { type: string, description: "Observable description" }
        score: { type: number, description: "Observable score 0-100 (default 50)" }
        create_indicator: { type: boolean, description: "Also create a related indicator (default false)" }
      required: [type, value]
    outputs_schema: { properties: {} }
  - id: observable_delete
    name: opencti-observable-delete
    description: "Delete an observable by ID."
    inputs_schema:
      properties:
        id: { type: string, description: "Observable ID" }
      required: [id]
    outputs_schema: { properties: {} }
  - id: observable_field_update
    name: opencti-observable-field-update
    description: "Update an observable field (score or description)."
    risk: safe_write
    inputs_schema:
      properties:
        id: { type: string, description: "Observable ID" }
        field: { type: string, description: "Field to update: score or description" }
        value: { type: string, description: "New value" }
      required: [id, field, value]
    outputs_schema: { properties: {} }
  - id: observable_field_add
    name: opencti-observable-field-add
    description: "Add a marking definition or label to an observable."
    risk: safe_write
    inputs_schema:
      properties:
        id: { type: string, description: "Observable ID" }
        field: { type: string, description: "Field to add: marking or label" }
        value: { type: string, description: "Label ID or marking definition ID to add" }
      required: [id, field, value]
    outputs_schema: { properties: {} }
  - id: observable_field_remove
    name: opencti-observable-field-remove
    description: "Remove a marking definition or label from an observable."
    inputs_schema:
      properties:
        id: { type: string, description: "Observable ID" }
        field: { type: string, description: "Field to remove: marking or label" }
        value: { type: string, description: "Label ID or marking definition ID to remove" }
      required: [id, field, value]
    outputs_schema: { properties: {} }

  # ── Indicators ────────────────────────────────────────────────────────────
  - id: get_indicators
    name: opencti-get-indicators
    description: "List/search indicators with optional filters and pagination."
    risk: read
    inputs_schema:
      properties:
        search: { type: string, description: "Indicator value to filter by (partial allowed)" }
        created_by: { type: string, description: "Creator organization ID" }
        creator: { type: string, description: "Creator user ID" }
        created_after: { type: string, description: "Created-after date (YYYY-MM-DDThh:mm:ss.sssZ)" }
        created_before: { type: string, description: "Created-before date (YYYY-MM-DDThh:mm:ss.sssZ)" }
        valid_until_after: { type: string, description: "Valid-until-after date" }
        valid_until_before: { type: string, description: "Valid-until-before date" }
        valid_from_after: { type: string, description: "Valid-from-after date" }
        valid_from_before: { type: string, description: "Valid-from-before date" }
        indicator_types: { type: string, description: "Comma-separated indicator types (see indicator_types_list)" }
        label_id: { type: string, description: "Label ID to filter by" }
        limit: { type: number, description: "Max indicators to return (default 50, max 500)" }
        last_run_id: { type: string, description: "Pagination cursor (OpenCTI.Indicators.LastRunID)" }
        all_results: { type: boolean, description: "Fetch all results, ignoring limit (default false)" }
      required: []
    outputs_schema: { properties: {} }
  - id: indicator_create
    name: opencti-indicator-create
    description: "Create a new indicator (STIX pattern built from value + observable type)."
    risk: safe_write
    inputs_schema:
      properties:
        name: { type: string, description: "Indicator name" }
        indicator: { type: string, description: "Indicator value" }
        main_observable_type: { type: string, description: "Main observable type: Account, Domain, Email, File-MD5, File-SHA1, File-SHA256, IP, IPv6, Registry Key, URL" }
        indicator_types: { type: string, description: "Comma-separated indicator types (see indicator_types_list)" }
        description: { type: string, description: "Indicator description" }
        confidence: { type: number, description: "Confidence 0-100 (default 50)" }
        score: { type: number, description: "Score 0-100 (default 50)" }
        valid_from: { type: string, description: "Valid-from date (YYYY-MM-DDThh:mm:ss.sssZ)" }
        valid_until: { type: string, description: "Valid-until date (YYYY-MM-DDThh:mm:ss.sssZ)" }
        created_by: { type: string, description: "Creator organization ID" }
        label_id: { type: string, description: "Label ID" }
        marking_id: { type: string, description: "Marking definition ID" }
        external_references_id: { type: string, description: "External reference ID" }
        create_observables: { type: boolean, description: "Also create the related observable (default false)" }
      required: [name, indicator, main_observable_type]
    outputs_schema: { properties: {} }
  - id: indicator_update
    name: opencti-indicator-update
    description: "Update an existing indicator's fields."
    risk: safe_write
    inputs_schema:
      properties:
        id: { type: string, description: "Indicator ID" }
        name: { type: string, description: "Indicator name" }
        indicator_types: { type: string, description: "Comma-separated indicator types" }
        description: { type: string, description: "Indicator description" }
        confidence: { type: number, description: "Confidence 0-100 (default 50)" }
        score: { type: number, description: "Score 0-100 (default 50)" }
        valid_from: { type: string, description: "Valid-from date" }
        valid_until: { type: string, description: "Valid-until date" }
        label_id: { type: string, description: "Comma-separated label IDs" }
        marking_id: { type: string, description: "Comma-separated marking IDs" }
        external_references_id: { type: string, description: "Comma-separated external reference IDs" }
      required: [id]
    outputs_schema: { properties: {} }
  - id: indicator_field_add
    name: opencti-indicator-field-add
    description: "Add a marking definition or label to an indicator."
    risk: safe_write
    inputs_schema:
      properties:
        id: { type: string, description: "Indicator ID" }
        field: { type: string, description: "Field to add: marking or label" }
        value: { type: string, description: "Label ID or marking definition ID to add" }
      required: [id, field, value]
    outputs_schema: { properties: {} }
  - id: indicator_field_remove
    name: opencti-indicator-field-remove
    description: "Remove a marking definition or label from an indicator."
    inputs_schema:
      properties:
        id: { type: string, description: "Indicator ID" }
        field: { type: string, description: "Field to remove: marking or label" }
        value: { type: string, description: "Label ID or marking definition ID to remove" }
      required: [id, field, value]
    outputs_schema: { properties: {} }
  - id: indicator_types_list
    name: opencti-indicator-types-list
    description: "List all indicator types (vocabulary)."
    risk: read
    inputs_schema:
      properties: {}
      required: []
    outputs_schema: { properties: {} }

  # ── Incidents (ingestion source) ──────────────────────────────────────────
  - id: get_incidents
    name: opencti-get-incidents
    description: "Fetch OpenCTI incidents for ingestion or search. Returns the entities list; use it as the alert-rule results path."
    risk: read
    inputs_schema:
      properties:
        search: { type: string, description: "Incident value to filter by (partial allowed)" }
        created_by: { type: string, description: "Creator organization ID" }
        creator: { type: string, description: "Creator user ID" }
        created_after: { type: string, description: "Created-after date / incremental watermark (YYYY-MM-DDThh:mm:ss.sssZ)" }
        created_before: { type: string, description: "Created-before date" }
        incident_types: { type: string, description: "Comma-separated incident types (see incident_types_list)" }
        label_id: { type: string, description: "Label ID to filter by" }
        limit: { type: number, description: "Max incidents to return (default 50, max 500)" }
        last_run_id: { type: string, description: "Pagination cursor (OpenCTI.Incidents.LastRunID)" }
        all_results: { type: boolean, description: "Fetch all results, ignoring limit (default false)" }
      required: []
    outputs_schema: { properties: {} }
    ingest:
      results_path: entities
      dedup_key: id
      incremental_field: created_after
  - id: incident_create
    name: opencti-incident-create
    description: "Create a new incident."
    risk: safe_write
    inputs_schema:
      properties:
        name: { type: string, description: "Incident name" }
        incident_type: { type: string, description: "Incident type name (see incident_types_list)" }
        confidence: { type: number, description: "Confidence 0-100 (default 50)" }
        severity: { type: string, description: "Severity: low, medium, high, critical" }
        description: { type: string, description: "Incident description" }
        source: { type: string, description: "Incident source" }
        objective: { type: string, description: "Incident objective" }
        created_by: { type: string, description: "Creator organization ID" }
        first_seen: { type: string, description: "First seen (YYYY-MM-DDThh:mm:ss.sssZ)" }
        last_seen: { type: string, description: "Last seen (YYYY-MM-DDThh:mm:ss.sssZ)" }
        label_id: { type: string, description: "Label ID" }
        marking_id: { type: string, description: "Marking definition ID" }
        external_references_id: { type: string, description: "External reference ID" }
      required: [name]
    outputs_schema: { properties: {} }
  - id: incident_delete
    name: opencti-incident-delete
    description: "Delete an incident by ID."
    inputs_schema:
      properties:
        id: { type: string, description: "Incident ID" }
      required: [id]
    outputs_schema: { properties: {} }
  - id: incident_types_list
    name: opencti-incident-types-list
    description: "List all incident types (vocabulary)."
    risk: read
    inputs_schema:
      properties: {}
      required: []
    outputs_schema: { properties: {} }

  # ── Relationships ─────────────────────────────────────────────────────────
  - id: relationship_create
    name: opencti-relationship-create
    description: "Create a relationship between two entities."
    risk: safe_write
    inputs_schema:
      properties:
        from_id: { type: string, description: "Source entity ID" }
        to_id: { type: string, description: "Target entity ID" }
        relationship_type: { type: string, description: "Relationship type (e.g. related-to, indicates, targets, uses, mitigates; default related-to)" }
        description: { type: string, description: "Relationship description" }
        confidence: { type: number, description: "Confidence 0-100" }
      required: [from_id, to_id]
    outputs_schema: { properties: {} }
  - id: relationship_delete
    name: opencti-relationship-delete
    description: "Delete a relationship by ID."
    inputs_schema:
      properties:
        id: { type: string, description: "Relationship ID" }
      required: [id]
    outputs_schema: { properties: {} }
  - id: relationship_list
    name: opencti-relationship-list
    description: "List relationships from a given entity."
    risk: read
    inputs_schema:
      properties:
        from_id: { type: string, description: "Source entity ID" }
        limit: { type: number, description: "Max relationships to return (default 50, max 200)" }
        last_run_id: { type: string, description: "Pagination cursor (OpenCTI.Relationships.relationshipsLastRun)" }
      required: [from_id]
    outputs_schema: { properties: {} }

  # ── Reference data ────────────────────────────────────────────────────────
  - id: organization_list
    name: opencti-organization-list
    description: "List all organizations."
    risk: read
    inputs_schema:
      properties:
        limit: { type: number, description: "Max organizations to return (default 50, max 200)" }
        last_run_id: { type: string, description: "Pagination cursor (OpenCTI.Organizations.organizationsLastRun)" }
      required: []
    outputs_schema: { properties: {} }
  - id: organization_create
    name: opencti-organization-create
    description: "Create a new organization."
    risk: safe_write
    inputs_schema:
      properties:
        name: { type: string, description: "Organization name" }
        description: { type: string, description: "Organization description" }
        reliability: { type: string, description: "Reliability: A, B, C, D, E, F" }
      required: [name]
    outputs_schema: { properties: {} }
  - id: label_list
    name: opencti-label-list
    description: "List all labels."
    risk: read
    inputs_schema:
      properties:
        limit: { type: number, description: "Max labels to return (default 50)" }
        last_run_id: { type: string, description: "Pagination cursor (OpenCTI.Labels.labelsLastRun)" }
      required: []
    outputs_schema: { properties: {} }
  - id: label_create
    name: opencti-label-create
    description: "Create a new label."
    risk: safe_write
    inputs_schema:
      properties:
        name: { type: string, description: "Label name" }
      required: [name]
    outputs_schema: { properties: {} }
  - id: marking_definition_list
    name: opencti-marking-definition-list
    description: "List all marking definitions."
    risk: read
    inputs_schema:
      properties:
        limit: { type: number, description: "Max marking definitions to return (default 50)" }
        last_run_id: { type: string, description: "Pagination cursor (OpenCTI.MarkingDefinitions.markingsLastRun)" }
      required: []
    outputs_schema: { properties: {} }
  - id: external_reference_create
    name: opencti-external-reference-create
    description: "Create an external reference."
    risk: safe_write
    inputs_schema:
      properties:
        url: { type: string, description: "External reference URL" }
        source_name: { type: string, description: "External reference source name" }
      required: [url, source_name]
    outputs_schema: { properties: {} }

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

ingestion:
  command: get_incidents
  mapper: get_incidents
  default_incident_type: "OpenCTI Incident"
