Commit Graph

3 Commits

Author SHA1 Message Date
f3nris eeebbfed3a fix(rapid7-insightidr): a partial region result is not a quiet period (v1.6.0)
An RRN states its region — rrn:alerts:eu:<org>:alert:… — while the base URL is
built from the instance's configured `region`. Following that thread found a
gap that matters more than the naming.

The Alert Triage API is multi-region behind one gateway, and eleven of its
endpoints can answer HTTP 200 with a region_failures list. The spec is explicit:
the presence of items in that field IS the partial failure. Three of the
commands here call such endpoints and all three read only the payload, so a
region the gateway could not reach produced fewer alerts and nothing else — no
error, no count, no log line. For an ingestion feed that is indistinguishable
from a quiet period, which is the one failure mode this integration has now hit
three separate times.

So region_failures is carried into the run metadata by every command that can
receive it, alongside the regions actually seen in the collected RRNs, the
configured region, and any mismatch between them.

The mismatch report is deliberately a report and not a correction. On a
single-region tenant the two always agree. On a multi-customer key, which spans
organizations, they need not — and rewriting the host per resource would be a
guess about how Rapid7 routes these calls, made without a tenant to verify it
against. Naming the discrepancy is what can be done honestly today; if it ever
fires, the metadata says so instead of the alerts silently going missing.

list_alert_fields already passed region_failures through untouched, since it
returns the API response as it stands.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 09:07:52 +02:00
f3nris 7e231c7c78 fix(rapid7-insightidr): name the input when terms_json will not parse (v1.2.1)
json.loads answers a bad value with "Expecting value: line 1 column 1 (char 0)",
which names neither the input at fault nor what it actually received. The
command has three string inputs; nothing in that message says which one broke,
so the operator is left guessing.

The mistake it hides is the obvious one. Documentation shows the input name and
the value together, so `terms_json: [{...}]` gets pasted whole into the value
field, and the parser then chokes on the field name it was handed. Echoing the
first 80 characters back makes that visible immediately.

Also carry a worked example in the manifest — the term that keeps only alerts
attached to an investigation, which is the filter this input mainly exists for —
and say explicitly to paste the array alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:31:27 +02:00
f3nris da44d41555 feat(rapid7-insightidr): add the Alert Triage API commands (v1.1.0)
An ingested investigation carried almost nothing: title, priority, status,
assignee and timestamps. Not a host, not an account, not a command line — so
no entity was ever indexed, and neither the pivot graph nor the AI analysis
had anything to read. Fetching the investigation's alerts did not help: that
endpoint answers with the rule name (already the investigation's title), the
alert source and an alert RRN, and nothing else.

The detection content lives in a different API. The Alert Triage API is served
under /idr/at — its own base, next to /idr/v1 and /idr/v2 — and it is where
the evidence, the actors, the MITRE T-codes and the process trees actually
are. It was missing from this package entirely.

Six read commands:

  search_alerts            POST /alerts/ops/search
  get_alert                GET  /alerts/{rrn}
  get_alert_evidence       GET  /alerts/{rrn}/evidences
  get_alert_actors         GET  /alerts/{rrn}/actors
  get_alert_process_trees  POST /alerts/{rrn}/process_trees/latest
  list_alert_fields        GET  /alerts/2/fields

search_alerts is the one that changes the shape of the feed. It returns full
alert objects — rule with its mitre_tcodes, rule_keys_of_interest, the
AI-suggested disposition, the parent investigation RRN, the status transition
timings and the log entries behind the alert — and its start_time is required
by the API, which makes it a natural incremental watermark. So the alerts can
be read directly, paginated, with no per-investigation fan-out.

Two things worth knowing before using them:

  - field_ids is not optional in practice. The API returns no additional
    fields when it is empty, and those additional fields are where the
    hostnames, accounts and command lines are. Their ids are per-tenant dotted
    paths (process.cmd_line, …), which is what list_alert_fields is for.
    /alerts/fields is deprecated, hence /alerts/2/fields.

  - the whole API is gated on Managed Detection and Response with access to
    the Alerts experience. A key that works on every investigation endpoint
    can still be refused here, so 401 and 403 are reported with that named
    explanation rather than as a bare status code — a licence boundary should
    not read as a bug.

Written against the published OpenAPI spec (SIEM Alerts API 39.10.0); not yet
exercised against a live tenant.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 22:31:12 +02:00