fukurow_engine/
engine.rs

1//! Inference engine for security event reasoning
2
3use fukurow_core::model::{CyberEvent, SecurityAction, InferenceRule};
4use fukurow_store::store::RdfStore;
5use fukurow_rules::{RuleRegistry, Rule};
6use super::orchestration::{ReasoningEngine, ProcessingOptions};
7use std::sync::Arc;
8use tokio::sync::RwLock;
9use tracing::{info, warn};
10
11/// Compatibility layer for legacy ReasonerEngine API
12/// Delegates to the new ReasoningEngine
13pub struct ReasonerEngine {
14    rdf_store: Arc<RwLock<RdfStore>>,
15    reasoning_engine: ReasoningEngine,
16}
17
18impl ReasonerEngine {
19    /// Create new reasoning engine
20    pub fn new() -> Self {
21        let rdf_store = Arc::new(RwLock::new(RdfStore::new()));
22        let reasoning_engine = ReasoningEngine::new();
23
24        Self {
25            rdf_store,
26            reasoning_engine,
27        }
28    }
29
30    /// Add a cyber security event for reasoning
31    pub async fn add_event(&self, event: CyberEvent) -> Result<(), ReasonerError> {
32        info!("Adding cyber event: {:?}", event);
33
34        // Convert event to JSON-LD and add to graph
35        let jsonld_doc = fukurow_core::jsonld::cyber_event_to_jsonld(&event)
36            .map_err(ReasonerError::GraphError)?;
37
38        let triples = fukurow_core::jsonld::jsonld_to_triples(&jsonld_doc)
39            .map_err(ReasonerError::GraphError)?;
40
41        let mut store = self.rdf_store.write().await;
42        for triple in triples {
43            store.insert(triple, fukurow_store::provenance::GraphId::Named("events".to_string()),
44                         fukurow_store::provenance::Provenance::Sensor {
45                             source: "reasoner-engine".to_string(),
46                             confidence: None,
47                         });
48        }
49
50        Ok(())
51    }
52
53    /// Execute reasoning and return proposed security actions
54    /// No side effects - only returns action proposals
55    pub async fn reason(&self) -> Result<Vec<SecurityAction>, ReasonerError> {
56        info!("Starting reasoning process");
57
58        let store = self.rdf_store.read().await;
59        let result = self.reasoning_engine.process(&store).await
60            .map_err(|e| ReasonerError::ReasoningError(e.to_string()))?;
61
62        info!("Reasoning complete, proposed {} actions", result.actions.len());
63        Ok(result.actions)
64    }
65
66    /// Get current graph store (read-only access)
67    pub async fn get_graph_store(&self) -> Arc<RwLock<RdfStore>> {
68        Arc::clone(&self.rdf_store)
69    }
70
71    /// Clear all events and reset reasoning state
72    pub async fn reset(&mut self) -> Result<(), ReasonerError> {
73        let mut store = self.rdf_store.write().await;
74        store.clear_all();
75        Ok(())
76    }
77
78    /// Add custom inference rule
79    pub fn add_rule(&mut self, _rule: InferenceRule) {
80        // TODO: Implement rule addition for new architecture
81        warn!("Rule addition not yet implemented in new architecture");
82    }
83}
84
85/// Reasoning engine errors
86#[derive(Debug, thiserror::Error)]
87pub enum ReasonerError {
88    #[error("Graph operation error: {0}")]
89    GraphError(#[from] anyhow::Error),
90
91    #[error("Rule evaluation error: {0}")]
92    RuleError(String),
93
94    #[error("Reasoning process error: {0}")]
95    ReasoningError(String),
96
97    #[error("Store operation error: {0}")]
98    StoreError(String),
99}