Skip to main content

rsigma_convert/
state.rs

1use std::collections::HashMap;
2
3/// Trait for deferred query expressions that are finalized after main condition conversion.
4///
5/// In pySigma, deferred expressions postpone part of the query (e.g. Splunk `| regex`,
6/// `| where`) to the `finish_query` phase. Each backend can define custom deferred types.
7pub trait DeferredExpression: std::fmt::Debug + Send + Sync {
8    fn finalize(&self) -> String;
9    fn negate(&mut self);
10    fn is_negated(&self) -> bool;
11}
12
13/// Simple template-based deferred expression (covers most text-backend cases).
14#[derive(Debug, Clone)]
15pub struct DeferredTextExpression {
16    pub template: String,
17    pub field: String,
18    pub value: String,
19    pub negated: bool,
20    /// `(positive_op, negated_op)` substituted into `{op}` in the template.
21    pub operators: (&'static str, &'static str),
22}
23
24impl DeferredExpression for DeferredTextExpression {
25    fn finalize(&self) -> String {
26        let op = if self.negated {
27            self.operators.1
28        } else {
29            self.operators.0
30        };
31        self.template
32            .replace("{field}", &self.field)
33            .replace("{value}", &self.value)
34            .replace("{op}", op)
35    }
36
37    fn negate(&mut self) {
38        self.negated = !self.negated;
39    }
40
41    fn is_negated(&self) -> bool {
42        self.negated
43    }
44}
45
46/// Return type for conversion methods that may produce a direct string or a deferred expression.
47#[derive(Debug)]
48pub enum ConvertResult {
49    Query(String),
50    Deferred(Box<dyn DeferredExpression>),
51}
52
53/// Per-condition conversion state carried through the conversion of a single rule condition.
54#[derive(Debug, Default)]
55pub struct ConversionState {
56    /// Key-value state inherited from pipeline `SetState` transformations.
57    pub processing_state: HashMap<String, serde_json::Value>,
58    /// Deferred query parts to be appended after the main condition.
59    pub deferred: Vec<Box<dyn DeferredExpression>>,
60}
61
62impl ConversionState {
63    pub fn new(processing_state: HashMap<String, serde_json::Value>) -> Self {
64        Self {
65            processing_state,
66            deferred: Vec::new(),
67        }
68    }
69
70    pub fn add_deferred(&mut self, expr: Box<dyn DeferredExpression>) {
71        self.deferred.push(expr);
72    }
73
74    pub fn has_deferred(&self) -> bool {
75        !self.deferred.is_empty()
76    }
77
78    pub fn get_state_str(&self, key: &str) -> Option<&str> {
79        self.processing_state.get(key)?.as_str()
80    }
81}