Skip to content

Commit 3547c59

Browse files
committed
Refactor RuleCondition to unify log source matching under a single type
1 parent 64a8e86 commit 3547c59

1 file changed

Lines changed: 35 additions & 23 deletions

File tree

src/pipeline.rs

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
//! conditions:
2525
//! index: "windows"
2626
//! rule_conditions:
27-
//! - type: logsource_product
27+
//! - type: logsource
2828
//! product: windows
2929
//! "#;
3030
//!
@@ -873,30 +873,42 @@ pub struct TransformationConfig {
873873
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
874874
#[serde(tag = "type")]
875875
pub enum RuleCondition {
876-
/// Match rules by log source category.
877-
#[serde(rename = "logsource_category")]
878-
LogSourceCategory { category: String },
879-
880-
/// Match rules by log source product.
881-
#[serde(rename = "logsource_product")]
882-
LogSourceProduct { product: String },
883-
884-
/// Match rules by log source service.
885-
#[serde(rename = "logsource_service")]
886-
LogSourceService { service: String },
876+
/// Match rules by log source attributes.
877+
///
878+
/// Any combination of `category`, `product`, and `service` can be specified.
879+
/// Only the fields that are set are compared; unspecified fields are ignored.
880+
/// This mirrors pySigma's `LogsourceCondition`.
881+
#[serde(rename = "logsource")]
882+
LogSource {
883+
#[serde(default, skip_serializing_if = "Option::is_none")]
884+
category: Option<String>,
885+
#[serde(default, skip_serializing_if = "Option::is_none")]
886+
product: Option<String>,
887+
#[serde(default, skip_serializing_if = "Option::is_none")]
888+
service: Option<String>,
889+
},
887890
}
888891

889892
impl RuleCondition {
890893
fn matches(&self, rule: &SigmaRule) -> bool {
891894
match self {
892-
Self::LogSourceCategory { category } => {
893-
rule.logsource.category.as_deref() == Some(category)
894-
}
895-
Self::LogSourceProduct { product } => {
896-
rule.logsource.product.as_deref() == Some(product)
897-
}
898-
Self::LogSourceService { service } => {
899-
rule.logsource.service.as_deref() == Some(service)
895+
Self::LogSource { category, product, service } => {
896+
if let Some(cat) = category
897+
&& rule.logsource.category.as_deref() != Some(cat)
898+
{
899+
return false;
900+
}
901+
if let Some(prod) = product
902+
&& rule.logsource.product.as_deref() != Some(prod)
903+
{
904+
return false;
905+
}
906+
if let Some(svc) = service
907+
&& rule.logsource.service.as_deref() != Some(svc)
908+
{
909+
return false;
910+
}
911+
true
900912
}
901913
}
902914
}
@@ -1134,7 +1146,7 @@ transformations:
11341146
type: field_name_prefix
11351147
prefix: "proc."
11361148
rule_conditions:
1137-
- type: logsource_category
1149+
- type: logsource
11381150
category: process_creation
11391151
"#;
11401152

@@ -1406,7 +1418,7 @@ transformations:
14061418
type: field_name_prefix
14071419
prefix: "proc."
14081420
rule_conditions:
1409-
- type: logsource_product
1421+
- type: logsource
14101422
product: linux
14111423
"#;
14121424

@@ -2423,7 +2435,7 @@ transformations:
24232435
type: field_name_prefix
24242436
prefix: "s."
24252437
rule_conditions:
2426-
- type: logsource_service
2438+
- type: logsource
24272439
service: sysmon
24282440
"#;
24292441
let pipeline = ProcessingPipeline::from_yaml(yaml).unwrap();

0 commit comments

Comments
 (0)