# ============================================================================= # Integration manifest template — copy to integrations//manifest.yaml # This file is named *.example.yaml on purpose so Riposte never ingests it # (only files named exactly "manifest.yaml" are picked up). # ============================================================================= id: example_integration # required · unique slug · [a-z0-9_] name: Example Integration # required · shown in the UI version: 1.0.0 # semver · bump on every change description: One-line description of what this integration does. # changelog: shown to operators when an update is available, so they can assess # risk before updating. Describe notable/breaking changes for THIS version. changelog: "1.0.0 — Initial release." category: enrichment # free text: enrichment | containment | ticketing | ... # --------------------------------------------------------------------------- # config_schema — per-instance settings the operator fills in when creating an # instance. JSON-Schema shape: { properties: {...}, required: [...] }. # Property fields: type (string|number|boolean), description, default, # and x-soar-sensitive: true for secrets (encrypted in the vault, never returned). # --------------------------------------------------------------------------- config_schema: properties: base_url: type: string description: API base URL default: https://api.example.com/v1 api_key: type: string description: API key / token x-soar-sensitive: true required: - api_key # --------------------------------------------------------------------------- # auth — authentication methods, referenced from commands via auth_ref. # value_template: {{secret}} is replaced by the value of secret_field. # api_key in header → name is the header (e.g. x-apikey, Authorization) # bearer → typically name: Authorization, value_template: "Bearer {{secret}}" # --------------------------------------------------------------------------- auth: - id: apikey type: api_key # api_key | bearer | basic | oauth2_client_credentials in: header # header | query name: Authorization value_template: "Bearer {{secret}}" secret_field: api_key commands: # Every command declares `risk:` — read | safe_write | destructive. It is what # the agent approval gate reads: `read` runs unattended, `safe_write` and # `destructive` sit behind the operator's configured threshold. An omitted # risk is treated as `destructive`, which is the safe default but makes a # lookup as noisy as an isolation, so declare it rather than let it default. # read — only queries; changes nothing outside Riposte # safe_write — additive or reversible: a comment, a ticket, a tag, a # sandbox submission, an alert status, a collection job # destructive — changes the estate or weakens a control: containment and # its removal, blocklists, exclusions, deletes, identity and # credential operations, running code on a host # --- Request-based command (recommended: declarative, no sandbox) --------- # # `category` says what the command is FOR. It is what the agent browses the # estate by: an analyst who wants to decode a rewritten URL and one who wants # to isolate a host are not looking in the same place, and every command of # your integration shares the manifest-level `category` above, which describes # the PRODUCT and cannot separate them. # # Optional. A command that declares none is classified from its id and # description when Riposte projects it into an agent tool — a decent guess, # and no more than that. Declaring it stops the guessing for that command, # which is the point of the field: you know, the classifier infers. # # enrich reputation or analysis of an indicator by a third party # hunt search telemetry: events, logs, process trees # inspect fetch one object in detail — a detection, a host, a record # transform decode, defang, parse, extract — acting on data, not on an estate # collect gather artefacts: jobs, forensic packages, dumps # contain isolate, block, quarantine, suspend # remediate undo a control or delete: unisolate, unblock, restore, purge # identity accounts: disable, reset a password, revoke a session # notify send a message, an e-mail, a page # ticket create or update a ticket or a case # manage policies, exclusions, configuration, agent lifecycle # # A value outside this list is ignored and the command is classified instead, # so a typo costs the declaration rather than inventing a category nothing # else ever lands in. - id: lookup name: Lookup indicator description: Fetches a report for an indicator over HTTP. risk: read # required in practice · read | safe_write | destructive category: enrich # optional · what the command is FOR (see above) inputs_schema: properties: indicator: type: string description: The value to look up required: - indicator outputs_schema: properties: {} request: method: GET # GET | POST | PUT | PATCH | DELETE path: /lookup/{indicator} # {indicator} is substituted from inputs query: [] # input names to send as query params body: [] # input names to send as JSON body fields auth_ref: apikey # --- Script-based command ------------------------------------------------- # No `request:` block. Provide scripts/.py next to this manifest. # The script receives inputs in the global dict __inputs__ and MUST print # exactly one JSON object to stdout (that becomes the command output). # See templates/scripts/example_command.py. - id: example_command name: Example scripted command description: Demonstrates a Python-backed command. risk: read inputs_schema: properties: indicator: type: string required: - indicator outputs_schema: properties: {}