Skip to main content

rsigma_eval/correlation/
keys.rs

1use serde::Serialize;
2
3use crate::event::{Event, EventValue};
4
5use super::types::GroupByField;
6
7// =============================================================================
8// Group Key
9// =============================================================================
10
11/// Composite key for group-by partitioning.
12///
13/// Each element corresponds to a `GroupByField` value extracted from an event.
14/// `None` means the field was absent from the event.
15#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, serde::Deserialize)]
16pub struct GroupKey(pub Vec<Option<String>>);
17
18impl GroupKey {
19    /// Extract a group key from an event given the group-by fields and the
20    /// rule reference identifiers (ID, name, etc.) that produced the detection match.
21    pub fn extract(event: &impl Event, group_by: &[GroupByField], rule_refs: &[&str]) -> Self {
22        let values = group_by
23            .iter()
24            .map(|field| {
25                let field_name = field.resolve(rule_refs);
26                event
27                    .get_field(field_name)
28                    .and_then(|v| value_to_string(&v))
29            })
30            .collect();
31        GroupKey(values)
32    }
33
34    /// Build a group key from explicit field-value pairs (for chaining).
35    pub fn from_pairs(pairs: &[(String, String)], group_by: &[GroupByField]) -> Self {
36        let values = group_by
37            .iter()
38            .map(|field| {
39                let name = field.name();
40                pairs
41                    .iter()
42                    .find(|(k, _)| k == name)
43                    .map(|(_, v)| v.clone())
44            })
45            .collect();
46        GroupKey(values)
47    }
48
49    /// Convert to field-name/value pairs for output.
50    pub fn to_pairs(&self, group_by: &[GroupByField]) -> Vec<(String, String)> {
51        group_by
52            .iter()
53            .zip(self.0.iter())
54            .filter_map(|(field, value)| {
55                value
56                    .as_ref()
57                    .map(|v| (field.name().to_string(), v.clone()))
58            })
59            .collect()
60    }
61}
62
63/// Convert an [`EventValue`] to a string for group-key purposes.
64fn value_to_string(v: &EventValue) -> Option<String> {
65    match v {
66        EventValue::Str(s) => Some(s.to_string()),
67        EventValue::Int(n) => Some(n.to_string()),
68        EventValue::Float(f) => Some(f.to_string()),
69        EventValue::Bool(b) => Some(b.to_string()),
70        _ => None,
71    }
72}