Hunting in the Archive
rsigma hunt run closes the bottom arrow of the detection-engineering loop: a hunt takes a detection rule, runs it against the PostgreSQL/TimescaleDB archive your telemetry already lands in, and streams the matching rows back as exemplar-shaped NDJSON that every downstream authoring tool already reads.
The boundary is deliberate: rsigma does not store or search logs. The logs stay in your store; rsigma is a read-only client of a store it already generates queries for and whose SQL dialect it owns via the PostgreSQL backend. No index, no retention, no query language of its own.
Workflow
# 1. Review the query without connecting (works in every build).
rsigma hunt run -r hunts/suspicious_curl.yml -t postgres \
-O table=security_events --since 7d --emit sql
# 2. Run the hunt read-only, streaming matches to an exemplar file.
rsigma hunt run -r hunts/suspicious_curl.yml -t postgres \
--dsn postgres://hunter@archive.example/siem \
--since 7d -o hunted.ndjson
# 3. Feed the exemplars to the authoring tools.
rsigma rule draft -e @hunted.ndjson
rsigma rule tune -r rules/ --rule <id> --fp @false-positives.ndjson --tp @hunted.ndjson
rsigma rule backtest -r rules/ --corpus hunted.ndjson
Each line of the output is one raw JSON event object; per-rule row counts, warnings, and the final summary (rows, elapsed, truncation) go to stderr, so stdout pipes cleanly into files and other tools. When --limit (default 1000 per rule) is hit, stderr says so: a truncated hunt is never mistaken for a complete one.
Field names: no reverse mapping
Hunt output events carry the archive’s native field names, because the pipeline mapped the rule’s fields to the archive’s columns before conversion. Consume the output downstream without re-applying the mapping pipeline; rule draft and friends mine the exemplars’ native field names, which is exactly what the archive produced.
Flat tables vs JSONB
Two archive layouts are supported, selected by the backend’s -O options:
- Flat-column tables (the reference
security_eventslayout): each non-NULL column becomes a JSON key.timestamptzbecomes an RFC 3339 string,ineta string, ints/floats numbers,jsonbis inlined. NULL columns are dropped so presence-based mining downstream is not skewed by the wide table’s mostly-NULL category columns. - JSONB tables (
-O json_field=data): the stored document is the original event and is emitted verbatim, with the timestamp column merged under its column name when the body lacks one. Round-trip fidelity is exact by construction; prefer this layout when you control the schema.
Safety posture
- Read-only is enforced, not promised. The session opens with
SET default_transaction_read_only = onandSET statement_timeout = <timeout>before any hunt SQL runs, so even a buggy generated query cannot write and a pathological scan is bounded server-side. A dedicated read-only role for the DSN is still recommended defense in depth. - DSN hygiene. The connection string comes from
--dsnorRSIGMA_HUNT_DSN(keeping the password out ofps auxand shell history). Logs and errors render a DSN rebuilt from the non-secret fields; the password never appears. - TLS from the start. rustls with the system root store;
sslmodein the DSN is honored (disable,preferwith plaintext fallback,require).
Scope and alternatives
hunt run is a one-shot batch operation: it is not a daemon endpoint, not a scheduled job, and it does not label exemplars (deciding which matches are true positives is the operator’s job, or rule tune’s verification loop’s).
- Correlation rules return aggregate rows (group keys plus counts), not events, and are rejected with a pointed error. Convert with
backend convert -t postgresand run the query manually. - Non-postgres targets stay convert-only: delegated sigma-cli targets by definition (rsigma cannot execute a Splunk query), and other native backends either emit rules rather than queries (Fibratus) or lack a hunt client. The error points at
backend convert -t <target>, which remains the way to reach Splunk, Elasticsearch, Sentinel, and the rest of the pySigma ecosystem. - Grafana-side hunting (running generated queries inside Grafana against configured data sources) shares the same wrapped-SQL builder;
--emit sqlis the portable artifact between the two.
See also
- CLI reference:
hunt runfor the full flag table. - Rule Conversion for the convert-side workflow this builds on.
- Rule Drafting, Rule Tuning, and Verdict-Driven Corpora for the exemplar consumers.
- PostgreSQL backend reference for JSONB mode and the
-Ooptions.