rsigma-convert
Convert parsed Sigma rules into backend-native query strings. Ships with PostgreSQL/TimescaleDB and LynxDB backends; the Backend trait lets you add your own.
When to use
- Generate SQL for an existing log store: PostgreSQL, TimescaleDB.
- Generate SPL2 for LynxDB.
- Build a custom backend (Elasticsearch DSL, Loki LogQL, ClickHouse SQL, Splunk SPL, KQL, anything that can be expressed as a text query). Implement
Backendonce and reuse the rule-walking machinery.
For event evaluation (running rules against in-memory events), use rsigma-eval.
Install
[dependencies]
rsigma-parser = "0.18.0"
rsigma-convert = "0.18.0"
No features. The crate is pure Rust + regex.
Public surface
| Type | Purpose |
|---|---|
Backend trait |
The plug-in surface (~30 methods). Implement one method per detection-item shape, return the query as a string. |
TextQueryConfig |
~90-field config struct that drives most text-query backends declaratively. Mirrors pySigma’s TextQueryBackend class variables (precedence, boolean operators, wildcards, string and field quoting, regex and CIDR templates, IN-list optimization, deferred parts, query envelope). |
PostgresBackend |
The PostgreSQL/TimescaleDB backend. Output formats: default, view, timescaledb, continuous_aggregate, sliding_window. |
LynxDbBackend |
The LynxDB backend. Output formats: default, minimal. |
TestBackend |
A backend-neutral text format used by the test suite and useful for debugging how a rule lowers to a generic boolean expression. |
convert_collection(backend, &SigmaCollection, &[Pipeline], output_format) |
Convert a whole collection, applying pipelines per rule. Returns a ConversionOutput with per-rule queries and per-rule errors. |
Backend::convert_rule(rule, output_format, &ConversionState) |
Lower-level single-rule entry point on the trait. |
ConversionOutput, ConversionResult, ConversionState |
Output-format-specific result wrapper, per-rule result, and the per-rule pipeline state used during conversion. |
The full Backend trait method list and the per-backend modifier mapping are in the crate README and in the PostgreSQL and LynxDB backend references.
Minimum example
use rsigma_convert::{convert_collection, backends::postgres::PostgresBackend};
use rsigma_parser::parse_sigma_yaml;
let rule_yaml = r#"
title: Whoami
id: 8b1d8c97-5b3a-4d77-9b48-7c5f7c8b1a2a
logsource: { product: windows, category: process_creation }
detection:
selection:
CommandLine|contains: 'whoami'
condition: selection
"#;
let collection = parse_sigma_yaml(rule_yaml)?;
let backend = PostgresBackend::new();
let output = convert_collection(&backend, &collection, &[], "default")?;
for result in &output.queries {
for q in &result.queries {
println!("-- {}\n{}\n", result.rule_title, q);
}
}
// -- Whoami
// SELECT * FROM security_events WHERE "CommandLine" ILIKE '%whoami%'
Backend options
PostgresBackend::from_options(&HashMap<String, String>) reads the CLI -O key=value map. Recognised keys:
| Key | Effect |
|---|---|
table |
Default table name (default security_events). |
schema |
PostgreSQL schema. |
database |
Connection-level metadata for some output formats. |
timestamp_field |
Column name for the timestamp (default time). |
json_field |
Treat field references as JSONB extraction paths in this column. |
case_sensitive_re |
Use ~ instead of ~* for regex. |
LynxDB has no CLI options today; its only knob is the target index, controlled via pipeline set_state with key: index (default main).
Writing a custom backend
The smallest viable backend implements Backend, returns a TextQueryConfig, and lets the trait’s default methods do the heavy lifting:
use rsigma_convert::{Backend, TextQueryConfig, TokenType};
pub struct MyBackend;
static MY_CONFIG: TextQueryConfig = TextQueryConfig {
precedence: (TokenType::NOT, TokenType::AND, TokenType::OR),
group_expression: "({expr})",
token_separator: " ",
and_token: "AND",
or_token: "OR",
not_token: "NOT",
eq_token: " = ",
not_eq_token: Some(" <> "),
// ... 80+ other knobs, see the docs.rs page
.. TextQueryConfig::PYSIGMA_DEFAULTS
};
impl Backend for MyBackend {
fn name(&self) -> &str { "my_backend" }
fn formats(&self) -> &[(&str, &str)] {
&[("default", "Plain MyBackend query")]
}
fn text_query_config(&self) -> Option<&TextQueryConfig> {
Some(&MY_CONFIG)
}
}
The default convert_rule walks the condition AST and dispatches into text_* helpers (e.g. text_convert_field_eq_str, text_convert_field_eq_cidr) that consult the config. Only override the methods that your backend needs to behave differently from pySigma’s TextQueryBackend default.
See Adding Backends for the step-by-step walkthrough, the testing pattern, and how to wire a new backend into rsigma backend convert if you also want CLI integration.
Error handling
ConvertError from thiserror. Variants include RuleConversion (a rule could not be converted with the chosen backend or format), UnsupportedModifier, InvalidIdentifier (table/schema name failed validation), and Pipeline (a pre-conversion pipeline step failed).
See also
- Rule Conversion for the operator-facing workflow.
- PostgreSQL backend reference and LynxDB backend reference.
- Adding Backends for the contributor walkthrough.
rsigma-convertREADME for the full Backend trait reference.- docs.rs/rsigma-convert.