use reasoner_graph::model::{InferenceRule, SecurityAction, Triple};
use reasoner_graph::store::GraphStore;
use crate::inference::InferenceContext;
use anyhow::Result;
#[derive(Debug)]
pub struct RuleEngine {
rules: Vec<InferenceRule>,
}
impl RuleEngine {
pub fn new() -> Self {
Self {
rules: Vec::new(),
}
}
pub fn add_rule(&mut self, rule: InferenceRule) {
self.rules.push(rule);
}
pub fn get_rules(&self) -> &[InferenceRule] {
&self.rules
}
pub async fn evaluate_rule(
&self,
store: &GraphStore,
rule: &InferenceRule,
_context: &InferenceContext,
) -> Result<Vec<SecurityAction>> {
if self.check_conditions(store, &rule.conditions) {
Ok(rule.actions.clone())
} else {
Ok(Vec::new())
}
}
fn check_conditions(&self, store: &GraphStore, conditions: &[Triple]) -> bool {
for condition in conditions {
let subject = if condition.subject.starts_with('?') {
None
} else {
Some(condition.subject.as_str())
};
let predicate = if condition.predicate.starts_with('?') {
None
} else {
Some(condition.predicate.as_str())
};
let object = if condition.object.starts_with('?') {
None
} else {
Some(condition.object.as_str())
};
let matches = store.find_triples(subject, predicate, object);
if matches.is_empty() {
return false;
}
if condition.subject.starts_with('?') || condition.predicate.starts_with('?') || condition.object.starts_with('?') {
let mut found_match = false;
for triple in &matches {
let subject_matches = if condition.subject.starts_with('?') {
true } else {
triple.subject == condition.subject
};
let predicate_matches = if condition.predicate.starts_with('?') {
true } else {
triple.predicate == condition.predicate
};
let object_matches = if condition.object.starts_with('?') {
true } else {
triple.object == condition.object
};
if subject_matches && predicate_matches && object_matches {
found_match = true;
break;
}
}
if !found_match {
return false;
}
}
}
true
}
pub fn add_default_cyber_rules(&mut self) {
self.add_rule(InferenceRule {
name: "malicious_ip_connection".to_string(),
description: "Detect connections to known malicious IPs".to_string(),
conditions: vec![
Triple {
subject: "?connection".to_string(),
predicate: "type".to_string(),
object: "NetworkConnection".to_string(),
},
Triple {
subject: "?connection".to_string(),
predicate: "destIp".to_string(),
object: "?malicious_ip".to_string(),
},
Triple {
subject: "?malicious_ip".to_string(),
predicate: "threatLevel".to_string(),
object: "high".to_string(),
},
],
actions: vec![
SecurityAction::BlockConnection {
source_ip: "?source_ip".to_string(),
dest_ip: "?malicious_ip".to_string(),
reason: "Connection to known malicious IP detected".to_string(),
},
SecurityAction::Alert {
severity: "high".to_string(),
message: "Malicious IP connection attempt".to_string(),
details: serde_json::json!({
"connection": "?connection",
"malicious_ip": "?malicious_ip"
}),
},
],
});
self.add_rule(InferenceRule {
name: "lateral_movement".to_string(),
description: "Detect potential lateral movement between hosts".to_string(),
conditions: vec![
Triple {
subject: "?login1".to_string(),
predicate: "type".to_string(),
object: "UserLogin".to_string(),
},
Triple {
subject: "?login1".to_string(),
predicate: "user".to_string(),
object: "?user".to_string(),
},
Triple {
subject: "?login1".to_string(),
predicate: "sourceIp".to_string(),
object: "?ip1".to_string(),
},
Triple {
subject: "?login2".to_string(),
predicate: "type".to_string(),
object: "UserLogin".to_string(),
},
Triple {
subject: "?login2".to_string(),
predicate: "user".to_string(),
object: "?user".to_string(),
},
Triple {
subject: "?login2".to_string(),
predicate: "sourceIp".to_string(),
object: "?ip2".to_string(),
},
],
actions: vec![
SecurityAction::Alert {
severity: "medium".to_string(),
message: "Potential lateral movement detected".to_string(),
details: serde_json::json!({
"user": "?user",
"from_ip": "?ip1",
"to_ip": "?ip2"
}),
},
],
});
self.add_rule(InferenceRule {
name: "privilege_escalation".to_string(),
description: "Detect dangerous use of privileged accounts".to_string(),
conditions: vec![
Triple {
subject: "?process".to_string(),
predicate: "type".to_string(),
object: "ProcessExecution".to_string(),
},
Triple {
subject: "?process".to_string(),
predicate: "user".to_string(),
object: "?privileged_user".to_string(),
},
Triple {
subject: "?privileged_user".to_string(),
predicate: "privilegeLevel".to_string(),
object: "admin".to_string(),
},
Triple {
subject: "?process".to_string(),
predicate: "commandLine".to_string(),
object: "?suspicious_cmd".to_string(),
},
],
actions: vec![
SecurityAction::IsolateHost {
host_ip: "?host_ip".to_string(),
reason: "Privileged account executing suspicious commands".to_string(),
},
SecurityAction::Alert {
severity: "critical".to_string(),
message: "Privilege escalation detected".to_string(),
details: serde_json::json!({
"user": "?privileged_user",
"process": "?process",
"command": "?suspicious_cmd"
}),
},
],
});
}
}