1use std::collections::HashMap;
4use midstreamer_strange_loop::{StrangeLoop, StrangeLoopConfig, MetaLevel, MetaKnowledge};
5use crate::{MitigationOutcome, FeedbackSignal};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct AdaptiveRule {
11 pub id: String,
12 pub pattern: ThreatPattern,
13 pub confidence: f64,
14 pub created_at: chrono::DateTime<chrono::Utc>,
15 pub updated_at: chrono::DateTime<chrono::Utc>,
16 pub success_count: u64,
17 pub failure_count: u64,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ThreatPattern {
23 pub features: HashMap<String, f64>,
24 pub threat_type: String,
25 pub severity_threshold: f64,
26}
27
28impl Default for ThreatPattern {
29 fn default() -> Self {
30 Self {
31 features: HashMap::new(),
32 threat_type: "unknown".to_string(),
33 severity_threshold: 0.5,
34 }
35 }
36}
37
38impl ThreatPattern {
39 pub fn from_features(features: &HashMap<String, f64>) -> Self {
40 Self {
41 features: features.clone(),
42 threat_type: "detected".to_string(),
43 severity_threshold: 0.5,
44 }
45 }
46}
47
48pub struct MetaLearningEngine {
50 learner: StrangeLoop,
52
53 learned_patterns: Vec<AdaptiveRule>,
55
56 pattern_effectiveness: HashMap<String, EffectivenessMetrics>,
58
59 current_level: usize,
61
62 learning_rate: f64,
64}
65
66impl MetaLearningEngine {
67 pub fn new() -> Self {
69 let config = StrangeLoopConfig {
70 max_meta_depth: 25,
71 enable_self_modification: true,
72 max_modifications_per_cycle: 10,
73 safety_check_enabled: true,
74 };
75
76 Self {
77 learner: StrangeLoop::new(config),
78 learned_patterns: Vec::new(),
79 pattern_effectiveness: HashMap::new(),
80 current_level: 0,
81 learning_rate: 0.1,
82 }
83 }
84
85 pub async fn learn_from_outcome(&mut self, outcome: &MitigationOutcome) {
87 let pattern = self.extract_pattern(outcome);
89
90 self.update_pattern_effectiveness(&pattern, outcome.success);
92
93 if self.is_significant_pattern(&pattern) {
95 self.apply_meta_learning(pattern).await;
96 }
97 }
98
99 pub async fn learn_from_incident(&mut self, incident: &ThreatIncident) {
101 let features = self.extract_incident_features(incident);
103
104 let rule = AdaptiveRule {
106 id: uuid::Uuid::new_v4().to_string(),
107 pattern: ThreatPattern::from_features(&features),
108 confidence: 0.5, created_at: chrono::Utc::now(),
110 updated_at: chrono::Utc::now(),
111 success_count: 0,
112 failure_count: 0,
113 };
114
115 self.learned_patterns.push(rule);
117
118 self.optimize_patterns().await;
120 }
121
122 pub fn optimize_strategy(&mut self, feedback: &[FeedbackSignal]) {
124 for signal in feedback {
125 if let Some(metrics) = self.pattern_effectiveness.get_mut(&signal.strategy_id) {
127 metrics.update(signal.effectiveness_score, signal.success);
128 }
129 }
130
131 self.recursive_optimize(self.current_level);
133
134 if self.should_advance_level() {
136 self.current_level = (self.current_level + 1).min(25);
137 }
138 }
139
140 pub fn learned_patterns_count(&self) -> usize {
142 self.learned_patterns.len()
143 }
144
145 pub fn current_optimization_level(&self) -> usize {
147 self.current_level
148 }
149
150 fn extract_pattern(&self, outcome: &MitigationOutcome) -> LearnedPattern {
152 LearnedPattern {
153 id: uuid::Uuid::new_v4().to_string(),
154 strategy_id: outcome.strategy_id.clone(),
155 threat_type: outcome.threat_type.clone(),
156 features: outcome.features.clone(),
157 success: outcome.success,
158 timestamp: chrono::Utc::now(),
159 }
160 }
161
162 fn update_pattern_effectiveness(&mut self, pattern: &LearnedPattern, success: bool) {
164 let metrics = self.pattern_effectiveness
165 .entry(pattern.id.clone())
166 .or_insert_with(EffectivenessMetrics::new);
167
168 metrics.update(if success { 1.0 } else { 0.0 }, success);
169 }
170
171 fn is_significant_pattern(&self, pattern: &LearnedPattern) -> bool {
173 if let Some(metrics) = self.pattern_effectiveness.get(&pattern.id) {
174 metrics.total_applications >= 5 && metrics.average_score > 0.6
175 } else {
176 false
177 }
178 }
179
180 async fn apply_meta_learning(&mut self, pattern: LearnedPattern) {
182 let meta_level = MetaLevel(self.current_level);
184 let confidence = self.calculate_pattern_confidence(&pattern);
185
186 let knowledge_data = vec![
188 format!("pattern_id: {}", pattern.id),
189 format!("threat_type: {}", pattern.threat_type),
190 format!("confidence: {}", confidence),
191 ];
192
193 if let Ok(meta_knowledge_vec) = self.learner.learn_at_level(
195 meta_level,
196 &knowledge_data,
197 ) {
198 if let Some(meta_knowledge) = meta_knowledge_vec.first() {
200 self.update_learned_patterns_from_knowledge(&pattern.id, meta_knowledge.clone());
201 }
202 }
203 }
204
205 fn calculate_pattern_confidence(&self, pattern: &LearnedPattern) -> f64 {
207 if let Some(metrics) = self.pattern_effectiveness.get(&pattern.id) {
208 metrics.average_score
209 } else {
210 0.5
211 }
212 }
213
214 fn update_learned_patterns_from_knowledge(&mut self, pattern_id: &str, knowledge: MetaKnowledge) {
216 if let Some(rule) = self.learned_patterns.iter_mut()
218 .find(|r| r.id == pattern_id) {
219 rule.confidence = knowledge.confidence;
220 rule.updated_at = chrono::Utc::now();
221 }
222 }
223
224 fn extract_incident_features(&self, incident: &ThreatIncident) -> HashMap<String, f64> {
226 let mut features = HashMap::new();
227
228 features.insert("severity".to_string(), incident.severity as f64);
229 features.insert("confidence".to_string(), incident.confidence);
230
231 match &incident.threat_type {
233 ThreatType::Anomaly(score) => {
234 features.insert("anomaly_score".to_string(), *score);
235 }
236 ThreatType::Attack(attack_type) => {
237 features.insert("attack_type_id".to_string(), attack_type.to_id() as f64);
238 }
239 ThreatType::Intrusion(level) => {
240 features.insert("intrusion_level".to_string(), *level as f64);
241 }
242 }
243
244 features
245 }
246
247 async fn optimize_patterns(&mut self) {
249 for level in 0..=self.current_level {
251 self.recursive_optimize(level);
252 }
253
254 self.learned_patterns.retain(|p| p.confidence > 0.3);
256 }
257
258 fn recursive_optimize(&mut self, level: usize) {
260 let optimization_effectiveness = self.calculate_optimization_effectiveness();
262
263 if optimization_effectiveness > 0.8 {
265 self.learning_rate *= 1.1; } else if optimization_effectiveness < 0.4 {
267 self.learning_rate *= 0.9; }
269
270 let learning_rate = self.learning_rate;
272 for pattern in &mut self.learned_patterns {
273 let refinement = learning_rate * (level as f64 / 25.0);
275 pattern.confidence = (pattern.confidence + refinement).clamp(0.0, 1.0);
276 }
277 }
278
279 fn calculate_optimization_effectiveness(&self) -> f64 {
281 if self.pattern_effectiveness.is_empty() {
282 return 0.5;
283 }
284
285 let total: f64 = self.pattern_effectiveness.values()
286 .map(|m| m.average_score)
287 .sum();
288
289 total / self.pattern_effectiveness.len() as f64
290 }
291
292 #[allow(dead_code)]
294 fn refine_confidence(&self, current: f64, level: usize) -> f64 {
295 let refinement = self.learning_rate * (level as f64 / 25.0);
297 (current + refinement).clamp(0.0, 1.0)
298 }
299
300 fn should_advance_level(&self) -> bool {
302 let effectiveness = self.calculate_optimization_effectiveness();
303 effectiveness > 0.75 && self.learned_patterns.len() >= 10
304 }
305}
306
307impl Default for MetaLearningEngine {
308 fn default() -> Self {
309 Self::new()
310 }
311}
312
313#[derive(Debug, Clone, Serialize, Deserialize)]
315struct LearnedPattern {
316 id: String,
317 strategy_id: String,
318 threat_type: String,
319 features: HashMap<String, f64>,
320 success: bool,
321 timestamp: chrono::DateTime<chrono::Utc>,
322}
323
324#[derive(Debug, Clone)]
326struct EffectivenessMetrics {
327 total_applications: u64,
328 successful_applications: u64,
329 average_score: f64,
330 last_updated: chrono::DateTime<chrono::Utc>,
331}
332
333impl EffectivenessMetrics {
334 fn new() -> Self {
335 Self {
336 total_applications: 0,
337 successful_applications: 0,
338 average_score: 0.0,
339 last_updated: chrono::Utc::now(),
340 }
341 }
342
343 fn update(&mut self, score: f64, success: bool) {
344 self.total_applications += 1;
345 if success {
346 self.successful_applications += 1;
347 }
348
349 self.average_score = (self.average_score * (self.total_applications - 1) as f64 + score)
351 / self.total_applications as f64;
352
353 self.last_updated = chrono::Utc::now();
354 }
355}
356
357#[derive(Debug, Clone)]
359pub struct ThreatIncident {
360 pub id: String,
361 pub threat_type: ThreatType,
362 pub severity: u8,
363 pub confidence: f64,
364 pub timestamp: chrono::DateTime<chrono::Utc>,
365}
366
367#[derive(Debug, Clone)]
369pub enum ThreatType {
370 Anomaly(f64),
371 Attack(AttackType),
372 Intrusion(u8),
373}
374
375#[derive(Debug, Clone)]
377pub enum AttackType {
378 DDoS,
379 SqlInjection,
380 XSS,
381 CSRF,
382 Other(String),
383}
384
385impl AttackType {
386 fn to_id(&self) -> u8 {
387 match self {
388 AttackType::DDoS => 1,
389 AttackType::SqlInjection => 2,
390 AttackType::XSS => 3,
391 AttackType::CSRF => 4,
392 AttackType::Other(_) => 99,
393 }
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400
401 #[tokio::test]
402 async fn test_meta_learning_creation() {
403 let engine = MetaLearningEngine::new();
404 assert_eq!(engine.current_level, 0);
405 assert_eq!(engine.learned_patterns_count(), 0);
406 }
407
408 #[tokio::test]
409 async fn test_pattern_learning() {
410 let mut engine = MetaLearningEngine::new();
411
412 let incident = ThreatIncident {
413 id: "test-1".to_string(),
414 threat_type: ThreatType::Anomaly(0.85),
415 severity: 7,
416 confidence: 0.9,
417 timestamp: chrono::Utc::now(),
418 };
419
420 engine.learn_from_incident(&incident).await;
421 assert!(engine.learned_patterns_count() > 0);
422 }
423
424 #[test]
425 fn test_effectiveness_metrics() {
426 let mut metrics = EffectivenessMetrics::new();
427
428 metrics.update(0.8, true);
429 assert_eq!(metrics.total_applications, 1);
430 assert_eq!(metrics.successful_applications, 1);
431 assert_eq!(metrics.average_score, 0.8);
432
433 metrics.update(0.6, false);
434 assert_eq!(metrics.total_applications, 2);
435 assert_eq!(metrics.successful_applications, 1);
436 assert_eq!(metrics.average_score, 0.7);
437 }
438
439 #[test]
440 fn test_optimization_level_advancement() {
441 let mut engine = MetaLearningEngine::new();
442
443 for i in 0..15 {
445 engine.learned_patterns.push(AdaptiveRule {
446 id: format!("rule-{}", i),
447 pattern: ThreatPattern::default(),
448 confidence: 0.8,
449 created_at: chrono::Utc::now(),
450 updated_at: chrono::Utc::now(),
451 success_count: 10,
452 failure_count: 2,
453 });
454 }
455
456 assert!(engine.should_advance_level());
458 }
459}