Skip to content

Commit

Permalink
fix: Use metadata during rule compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
vadorovsky authored and banditopazzo committed Jun 18, 2024
1 parent 80ab035 commit 29adc53
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 12 deletions.
16 changes: 10 additions & 6 deletions crates/modules/rules-engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{collections::HashMap, fs, path::Path, str::FromStr, sync::Arc};

use glob::glob;
use pulsar_core::{
event::PayloadDiscriminant,
event::{PayloadDiscriminant, Value},
pdk::{Event, ModuleSender},
};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -88,9 +88,13 @@ impl PulsarEngine {
// Match against a discriminant ruleset if there is one
if let Some(ruleset) = self.internal.rulesets.get(&discriminant) {
for r in ruleset.matches(event) {
self.internal
.sender
.send_threat_derived(event, r.name.clone(), None);
let metadata_value =
Value::try_from(&r.metadata).expect("failed to serialize metadata");
self.internal.sender.send_threat_derived(
event,
r.rule.name.clone(),
Some(metadata_value),
);
}
}
}
Expand Down Expand Up @@ -195,7 +199,7 @@ impl RuleFile {
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Metadata {
pub category: Category,
pub description: String,
Expand All @@ -208,7 +212,7 @@ pub struct RuleWithMetadata {
pub(crate) metadata: Metadata,
}

#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum Category {
CommandAndControl,
Expand Down
24 changes: 18 additions & 6 deletions crates/modules/rules-engine/src/ruleset.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
use validatron::{CompiledRule, Validatron, ValidatronError};

use crate::engine::RuleWithMetadata;
use crate::engine::{Metadata, RuleWithMetadata};

/// Set of rules which can be applied over any instance of type `T`.
///
/// Each rule has been validated and compiled into single closure.
pub struct Ruleset<T: Validatron + 'static> {
pub(crate) rules: Vec<CompiledRule<T>>,
pub(crate) rules: Vec<CompiledRuleWithMetadata<T>>,
}

/// CompiledRuleWithMetadata is a CompiledRule with additional metadata
/// that is used to store the rule name and description.
pub struct CompiledRuleWithMetadata<T: Validatron + 'static> {
pub rule: CompiledRule<T>,
pub metadata: Metadata,
}

impl<T: Validatron> Ruleset<T> {
/// Create a ruleset from a [Vec] of [CompiledRuleWithMetadata].
#[allow(dead_code)]
pub fn from_compiled(rules: Vec<CompiledRule<T>>) -> Self {
pub fn from_compiled(rules: Vec<CompiledRuleWithMetadata<T>>) -> Self {
Self { rules }
}

Expand All @@ -22,7 +29,12 @@ impl<T: Validatron> Ruleset<T> {
pub fn from_rules(rules: Vec<RuleWithMetadata>) -> Result<Self, ValidatronError> {
let compiled_rules = rules
.into_iter()
.map(|r| r.rule.compile())
.map(|r| {
r.rule.compile().map(|rule| CompiledRuleWithMetadata {
rule,
metadata: r.metadata,
})
})
.collect::<Result<Vec<_>, ValidatronError>>()?;

log::debug!("Loaded {} rules", compiled_rules.len());
Expand All @@ -33,7 +45,7 @@ impl<T: Validatron> Ruleset<T> {
}

/// Perform the check on an instance of a type `T` and returns an iterator over the matching rules.
pub fn matches<'a>(&'a self, e: &'a T) -> impl Iterator<Item = &CompiledRule<T>> {
self.rules.iter().filter(|r| r.is_match(e))
pub fn matches<'a>(&'a self, e: &'a T) -> impl Iterator<Item = &CompiledRuleWithMetadata<T>> {
self.rules.iter().filter(|r| r.rule.is_match(e))
}
}

0 comments on commit 29adc53

Please sign in to comment.