feat(crowdstrike): fetch incrementally via a created_from watermark (v1.3.0)
search_detections had one input for everything, `filter`, so an alert rule configured for incremental fetch had nowhere to put its watermark but there — where it REPLACED the FQL with a bare timestamp instead of narrowing it. The API rejects that outright (HTTP 400, "invalid query filter in request"), and even had it not, the product/type scoping would have been silently discarded with it. The only working configuration left was a full fetch on every run. created_from is that missing input, following the shape get_alerts already uses on sentinelone: a timestamp of its own, declared as the command's incremental_field so the alert-rule editor offers it. The script folds it into the FQL as created_timestamp, which is where this API expresses a time bound. filter now carries the scoping only — the two no longer compete. Surrounding quotes on the value are stripped: FQL wants them, and an operator filling the first-fetch date by hand may reasonably include them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
id: crowdstrike
|
||||
name: CrowdStrike Falcon
|
||||
version: 1.2.4
|
||||
version: 1.3.0
|
||||
description: "CrowdStrike Falcon (OAuth2 API) — full IR coverage: device/IOC/process enrichment, detections & cases, host groups, Real Time Response, ML/IOA exclusions, quarantine, Spotlight/CVE, ODS scans, CSPM, users, IOA rules, CNAPP, and Fusion workflows."
|
||||
changelog: "1.2.4 — Fixed two silent defects in the search_detections OCSF mapper: severity was a ternary that resolved to nothing, so every alert kept the alert rule's default severity instead of Falcon's — it is now a plain path to severity_name, whose words the engine reads natively; and no entry fed the OCSF `time` field, so detected_at was never stamped and MTTD measured the collection delay as zero. 1.2.3 — Documentation wording cleanup. 1.2.2 — Corrected the search_detections OCSF mapper against the Falcon Raptor alert schema: domain is device.hostinfo.domain, dropped non-existent fields, added scenario/alleged_filetype/cid. 1.2.1 — Marked search_detections as an ingestion source (ingest hints: results_path=resources, dedup_key=composite_id) so the alert-rule editor pre-fills it. 1.2.0 — Added a pre-built OCSF mapper for search_detections (Falcon unified alerts → OCSF: device, finding, MITRE, actor/parent process, file and IOC). 1.1.1 — Added test_connection for the instance Test button. 1.1.0 — Expanded to 81 commands (host groups, cases, RTR files/scripts/responders, ML/IOA exclusions, quarantine, Spotlight host-by-vuln/CVE, ODS scans, CSPM, users, IOA rules, CNAPP, identity/mobile detection resolve, and workflows). 1.0.0 — Initial release: device/detection enrichment, Spotlight, IOC management, contain/lift, and core RTR."
|
||||
changelog: "1.3.0 — search_detections takes a created_from timestamp, folded into the FQL as created_timestamp, and declares it as the ingestion watermark input. An alert rule can now fetch incrementally instead of re-reading the whole window every run: this API expresses its time bound inside the FQL, so the watermark used to have nowhere to go but the filter input, where it replaced the query rather than narrowing it. filter now carries the scoping only. 1.2.4 — Fixed two silent defects in the search_detections OCSF mapper: severity was a ternary that resolved to nothing, so every alert kept the alert rule's default severity instead of Falcon's — it is now a plain path to severity_name, whose words the engine reads natively; and no entry fed the OCSF `time` field, so detected_at was never stamped and MTTD measured the collection delay as zero. 1.2.3 — Documentation wording cleanup. 1.2.2 — Corrected the search_detections OCSF mapper against the Falcon Raptor alert schema: domain is device.hostinfo.domain, dropped non-existent fields, added scenario/alleged_filetype/cid. 1.2.1 — Marked search_detections as an ingestion source (ingest hints: results_path=resources, dedup_key=composite_id) so the alert-rule editor pre-fills it. 1.2.0 — Added a pre-built OCSF mapper for search_detections (Falcon unified alerts → OCSF: device, finding, MITRE, actor/parent process, file and IOC). 1.1.1 — Added test_connection for the instance Test button. 1.1.0 — Expanded to 81 commands (host groups, cases, RTR files/scripts/responders, ML/IOA exclusions, quarantine, Spotlight host-by-vuln/CVE, ODS scans, CSPM, users, IOA rules, CNAPP, identity/mobile detection resolve, and workflows). 1.0.0 — Initial release: device/detection enrichment, Spotlight, IOC management, contain/lift, and core RTR."
|
||||
category: endpoint
|
||||
|
||||
# Per-instance configuration. Scripts obtain an OAuth2 bearer token from
|
||||
@@ -74,13 +74,15 @@ commands:
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
filter: { type: string, description: "FQL filter (default \"product:'epp'+type:'ldt'\"). For incremental fetch add e.g. created_timestamp:>'<ISO8601>'." }
|
||||
limit: { type: number, description: "Max alerts to return (default 50)." }
|
||||
filter: { type: string, description: "FQL scoping filter (default \"product:'epp'+type:'ldt'\"). Say WHAT to fetch; leave the time bound to created_from." }
|
||||
created_from: { type: string, description: "Return alerts created at or after this timestamp (ISO 8601). Folded into the FQL as created_timestamp. Receives the alert rule's incremental watermark." }
|
||||
limit: { type: number, description: "Max alerts to return (default 50). One page only — there is no pagination, so size it above the volume of one polling window." }
|
||||
required: []
|
||||
outputs_schema: { properties: {} }
|
||||
ingest:
|
||||
results_path: resources
|
||||
dedup_key: composite_id
|
||||
incremental_field: created_from
|
||||
|
||||
- id: list_host_groups
|
||||
name: crowdstrike-list-host-groups
|
||||
|
||||
@@ -34,6 +34,15 @@ def csv(v):
|
||||
def main():
|
||||
tok = token()
|
||||
fql = INPUTS.get("filter") or "product:'epp'+type:'ldt'"
|
||||
# The alert rule's incremental watermark lands in created_from, NOT in filter.
|
||||
# This API carries its time bound inside the FQL, so pointing the watermark at
|
||||
# filter would REPLACE the whole query with a bare timestamp rather than narrow
|
||||
# it — which the API rejects outright, and which would also silently discard the
|
||||
# product/type scoping above. Its own input lets the two coexist: filter says
|
||||
# what to look for, created_from says since when.
|
||||
since = str(INPUTS.get("created_from") or "").strip().strip("'\"")
|
||||
if since:
|
||||
fql += "+created_timestamp:>'" + since + "'"
|
||||
limit = INPUTS.get("limit", 50)
|
||||
params = [("filter", fql), ("limit", limit), ("sort", "created_timestamp.desc")]
|
||||
found = call("GET", "/alerts/queries/alerts/v2", tok, params=params)
|
||||
|
||||
Reference in New Issue
Block a user