1use crate::scanner::Threat;
18use anyhow::Result;
19use async_trait::async_trait;
20use serde::{Deserialize, Serialize};
21use std::sync::Arc;
22use std::time::Duration;
23
24#[cfg(any(test, feature = "test-utils"))]
25use mockall::{automock, predicate::*};
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum Priority {
33 Normal,
34 Urgent,
35}
36
37#[derive(Debug, Clone)]
39pub struct EndpointStats {
40 pub success_count: u64,
41 pub failure_count: u64,
42 pub circuit_state: CircuitState,
43 pub available_tokens: u32,
44}
45
46pub trait EventBufferTrait: Send + Sync {
48 fn enqueue_event(&self, endpoint_id: u32, data: &[u8], priority: Priority) -> Result<u64>;
50
51 fn get_endpoint_stats(&self, endpoint_id: u32) -> Result<EndpointStats>;
53}
54
55#[async_trait]
57#[cfg_attr(any(test, feature = "test-utils"), automock)]
58pub trait SecurityEventProcessor: Send + Sync {
59 async fn process_event(&self, event: SecurityEvent) -> Result<EventHandle>;
61
62 fn get_stats(&self) -> ProcessorStats;
64
65 fn is_monitored(&self, endpoint: &str) -> bool;
67
68 async fn get_insights(&self, client_id: &str) -> Result<SecurityInsights>;
70
71 async fn cleanup(&self) -> Result<()>;
73}
74
75#[cfg_attr(any(test, feature = "test-utils"), automock)]
77pub trait EnhancedScanner: Send + Sync {
78 fn enhanced_scan(&self, data: &[u8]) -> Result<Vec<Threat>>;
80
81 fn get_metrics(&self) -> ScannerMetrics;
83
84 fn preload_patterns(&self, patterns: &[String]) -> Result<()>;
86}
87
88#[async_trait]
90#[cfg_attr(any(test, feature = "test-utils"), automock)]
91pub trait CorrelationEngine: Send + Sync {
92 async fn correlate(&self, events: &[SecurityEvent]) -> Result<Vec<ThreatPattern>>;
94
95 async fn update_rules(&self, rules: CorrelationRules) -> Result<()>;
97
98 fn get_correlation_stats(&self) -> CorrelationStats;
100}
101
102#[async_trait]
104#[cfg_attr(any(test, feature = "test-utils"), automock)]
105pub trait RateLimiter: Send + Sync {
106 async fn check_rate_limit(&self, key: &RateLimitKey) -> Result<RateLimitDecision>;
108
109 async fn record_request(&self, key: &RateLimitKey) -> Result<()>;
111
112 async fn apply_penalty(&self, client_id: &str, factor: f32) -> Result<()>;
114
115 fn get_stats(&self) -> RateLimiterStats;
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct SecurityEvent {
122 pub event_type: String,
123 pub client_id: String,
124 pub timestamp: u64,
125 pub metadata: serde_json::Value,
126}
127
128#[derive(Debug, Clone)]
130pub struct EventHandle {
131 pub event_id: u64,
132 pub processed: bool,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct ProcessorStats {
138 pub events_processed: u64,
139 pub events_per_second: f64,
140 pub buffer_utilization: f64,
141 pub correlation_hits: u64,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct SecurityInsights {
147 pub risk_score: f32,
148 pub detected_patterns: Vec<String>,
149 pub recommendations: Vec<String>,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct ScannerMetrics {
155 pub scans_performed: u64,
156 pub threats_detected: u64,
157 pub avg_scan_time_us: u64,
158 pub pattern_cache_hits: u64,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct ThreatPattern {
164 pub pattern_type: String,
165 pub confidence: f32,
166 pub events: Vec<u64>,
167 pub description: String,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct CorrelationRules {
173 pub time_window: std::time::Duration,
174 pub min_events: usize,
175 pub patterns: Vec<PatternRule>,
176}
177
178#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct PatternRule {
181 pub name: String,
182 pub event_types: Vec<String>,
183 pub threshold: u32,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct CorrelationStats {
189 pub patterns_detected: u64,
190 pub false_positives: u64,
191 pub avg_correlation_time_ms: u64,
192}
193
194#[derive(Debug, Clone, Hash, Eq, PartialEq)]
196pub struct RateLimitKey {
197 pub client_id: String,
198 pub method: Option<String>,
199}
200
201#[derive(Debug, Clone)]
203pub struct RateLimitDecision {
204 pub allowed: bool,
205 pub tokens_remaining: f64,
206 pub reset_after: std::time::Duration,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct RateLimiterStats {
212 pub requests_allowed: u64,
213 pub requests_denied: u64,
214 pub active_buckets: usize,
215}
216
217pub trait SecurityComponentFactory: Send + Sync {
219 fn create_event_processor(
221 &self,
222 config: &crate::config::Config,
223 storage: Arc<dyn crate::storage::StorageProvider>,
224 ) -> Result<Arc<dyn SecurityEventProcessor>>;
225
226 fn create_scanner(&self, config: &crate::config::Config) -> Result<Arc<dyn EnhancedScanner>>;
228
229 fn create_correlation_engine(
231 &self,
232 config: &crate::config::Config,
233 storage: Arc<dyn crate::storage::StorageProvider>,
234 ) -> Result<Arc<dyn CorrelationEngine>>;
235
236 fn create_rate_limiter(
238 &self,
239 config: &crate::config::Config,
240 storage: Arc<dyn crate::storage::StorageProvider>,
241 ) -> Result<Arc<dyn RateLimiter>>;
242
243 fn create_security_scanner(
245 &self,
246 config: &crate::config::Config,
247 ) -> Result<Arc<dyn SecurityScannerTrait>>;
248}
249
250#[async_trait]
252pub trait CircuitBreakerTrait: Send + Sync {
255 async fn call<F, T, Fut>(&self, name: &str, f: F) -> Result<T, CircuitBreakerError>
257 where
258 F: FnOnce() -> Fut + Send,
259 Fut: std::future::Future<Output = Result<T>> + Send,
260 T: Send;
261
262 fn state(&self, name: &str) -> CircuitState;
264
265 fn stats(&self, name: &str) -> CircuitStats;
267
268 async fn trip(&self, name: &str, reason: &str);
270 async fn reset(&self, name: &str);
271}
272
273#[async_trait]
275pub trait RetryStrategyTrait: Send + Sync {
278 async fn execute<F, T, Fut>(&self, operation: &str, f: F) -> Result<T>
280 where
281 F: Fn() -> Fut + Send + Sync,
282 Fut: std::future::Future<Output = Result<T>> + Send,
283 T: Send;
284
285 fn should_retry(&self, error: &anyhow::Error, context: &RetryContext) -> RetryDecision;
287
288 fn stats(&self) -> RetryStats;
290}
291
292pub trait ResilienceFactory: Send + Sync {
294 fn create_circuit_breaker(
296 &self,
297 config: &crate::config::Config,
298 ) -> Result<Arc<dyn DynCircuitBreaker>>;
299
300 fn create_retry_strategy(
302 &self,
303 config: &crate::config::Config,
304 ) -> Result<Arc<dyn DynRetryStrategy>>;
305
306 fn create_health_checker(
308 &self,
309 config: &crate::config::Config,
310 ) -> Result<Arc<dyn HealthCheckTrait>>;
311
312 fn create_recovery_strategy(
314 &self,
315 config: &crate::config::Config,
316 ) -> Result<Arc<dyn RecoveryStrategyTrait>>;
317
318 fn create_bulkhead(
320 &self,
321 config: &crate::config::Config,
322 ) -> Result<Arc<dyn crate::resilience::DynBulkhead>>;
323}
324
325#[derive(Debug, thiserror::Error, Clone)]
327pub enum CircuitBreakerError {
328 #[error("Circuit breaker is open")]
329 CircuitOpen,
330
331 #[error("Circuit breaker is throttled")]
332 Throttled,
333
334 #[error("Service call failed: {0}")]
335 ServiceError(String),
336
337 #[error("Timeout after {0:?}")]
338 Timeout(Duration),
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
343pub enum CircuitState {
344 Closed,
346 Throttled,
348 HalfOpen,
350 Open,
352}
353
354#[derive(Debug, Clone, Serialize, Deserialize)]
356pub struct CircuitStats {
357 pub state: CircuitState,
358 pub failure_count: u32,
359 pub success_count: u32,
360 pub total_requests: u64,
361 pub last_failure_time: Option<u64>,
362 pub tokens_available: f64,
363}
364
365#[derive(Debug, Clone)]
367pub struct RetryContext {
368 pub attempts: u32,
369 pub error_category: ErrorCategory,
370 pub total_elapsed: Duration,
371}
372
373#[derive(Debug, Clone, Copy)]
375pub struct ErrorCategory {
376 pub is_retryable: bool,
377 pub error_type: ErrorType,
378}
379
380#[derive(Debug, Clone, Copy, PartialEq, Eq)]
382pub enum ErrorType {
383 Network,
384 Timeout,
385 RateLimit,
386 Authentication,
387 ServerError,
388 ClientError,
389 Unknown,
390}
391
392#[derive(Debug, Clone)]
394pub struct RetryDecision {
395 pub should_retry: bool,
396 pub delay: Option<Duration>,
397 pub reason: String,
398}
399
400#[derive(Debug, Clone, Serialize, Deserialize)]
402pub struct RetryStats {
403 pub total_attempts: u64,
404 pub successful_retries: u64,
405 pub failed_retries: u64,
406 pub retry_budget_remaining: u32,
407}
408
409#[async_trait]
411pub trait HealthCheckTrait: Send + Sync {
414 async fn check(&self) -> Result<HealthStatus>;
416
417 async fn detailed_check(&self) -> Result<HealthReport>;
419
420 fn register_dependency(&self, name: String, checker: Arc<dyn HealthCheckTrait>);
422
423 fn metadata(&self) -> HealthCheckMetadata;
425}
426
427#[async_trait]
429pub trait RecoveryStrategyTrait: Send + Sync {
432 async fn recover(
434 &self,
435 context: &RecoveryContext,
436 operation_name: &str,
437 ) -> Result<serde_json::Value>;
438
439 fn can_recover(&self, error: &anyhow::Error) -> bool;
441
442 fn stats(&self) -> RecoveryStats;
444
445 async fn update_state(&self, state: RecoveryState);
447}
448
449#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
451pub enum HealthStatus {
452 Healthy,
454 Degraded,
456 Unhealthy,
458}
459
460#[derive(Debug, Clone, Serialize, Deserialize)]
462pub struct HealthReport {
463 pub status: HealthStatus,
464 pub checks: Vec<HealthCheckResult>,
465 pub timestamp: u64,
466 pub latency_ms: u64,
467}
468
469#[derive(Debug, Clone, Serialize, Deserialize)]
471pub struct HealthCheckResult {
472 pub name: String,
473 pub status: HealthStatus,
474 pub message: Option<String>,
475 pub metadata: serde_json::Value,
476}
477
478#[derive(Debug, Clone, Serialize, Deserialize)]
480pub struct HealthCheckMetadata {
481 pub name: String,
482 pub check_type: HealthCheckType,
483 pub timeout: Duration,
484 pub critical: bool,
485}
486
487#[cfg_attr(any(test, feature = "test-utils"), automock)]
489pub trait MetricsProvider: Send + Sync {
490 fn counter(&self, name: &str, help: &str) -> Arc<dyn CounterTrait>;
492
493 fn gauge(&self, name: &str, help: &str) -> Arc<dyn GaugeTrait>;
495
496 fn histogram(&self, name: &str, help: &str, buckets: Vec<f64>) -> Arc<dyn HistogramTrait>;
498
499 fn export_prometheus(&self) -> String;
501
502 fn export_json(&self) -> serde_json::Value;
504
505 fn uptime_seconds(&self) -> u64;
507}
508
509pub trait CounterTrait: Send + Sync {
511 fn inc(&self);
513
514 fn inc_by(&self, amount: u64);
516
517 fn value(&self) -> u64;
519}
520
521pub trait GaugeTrait: Send + Sync {
523 fn set(&self, value: i64);
525
526 fn inc(&self);
528
529 fn dec(&self);
531
532 fn value(&self) -> i64;
534}
535
536pub trait HistogramTrait: Send + Sync {
538 fn observe(&self, value: f64);
540
541 fn stats(&self) -> HistogramStats;
543}
544
545#[derive(Debug, Clone, Serialize, Deserialize)]
547pub struct HistogramStats {
548 pub count: u64,
549 pub sum: f64,
550 pub average: f64,
551}
552
553#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
555pub enum HealthCheckType {
556 Liveness,
557 Readiness,
558 Startup,
559 Dependency,
560}
561
562#[derive(Debug, Clone)]
564pub struct RecoveryContext {
565 pub failure_count: u32,
566 pub last_error: String,
567 pub recovery_attempts: u32,
568 pub service_name: String,
569}
570
571#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
573pub enum RecoveryState {
574 Normal,
576 Recovering,
578 Fallback,
580 Failed,
582}
583
584#[derive(Debug, Clone, Serialize, Deserialize)]
586pub struct RecoveryStats {
587 pub recoveries_attempted: u64,
588 pub recoveries_succeeded: u64,
589 pub fallbacks_used: u64,
590 pub current_state: RecoveryState,
591}
592
593#[cfg_attr(any(test, feature = "test-utils"), automock)]
595pub trait SecurityScannerTrait: Send + Sync {
596 fn scan_text(&self, text: &str) -> Vec<crate::scanner::Threat>;
598
599 fn scan_json(&self, value: &serde_json::Value) -> Vec<crate::scanner::Threat>;
601
602 fn scan_with_depth(&self, text: &str, max_depth: usize) -> Vec<crate::scanner::Threat>;
604
605 fn get_stats(&self) -> ScannerStats;
607
608 fn reset_stats(&self);
610}
611
612#[derive(Debug, Clone, Serialize, Deserialize)]
614pub struct ScannerStats {
615 pub texts_scanned: u64,
616 pub threats_found: u64,
617 pub unicode_threats: u64,
618 pub injection_threats: u64,
619 pub pattern_threats: u64,
620 pub avg_scan_time_us: u64,
621}
622
623#[async_trait]
625pub trait DynCircuitBreaker: Send + Sync {
626 async fn call_json(
628 &self,
629 name: &str,
630 request: serde_json::Value,
631 ) -> Result<serde_json::Value, CircuitBreakerError>;
632
633 fn state(&self, name: &str) -> CircuitState;
635
636 fn stats(&self, name: &str) -> CircuitStats;
638
639 async fn trip(&self, name: &str, reason: &str);
641 async fn reset(&self, name: &str);
642}
643
644#[async_trait]
646pub trait DynRetryStrategy: Send + Sync {
647 async fn execute_json(
649 &self,
650 operation: &str,
651 request: serde_json::Value,
652 ) -> Result<serde_json::Value>;
653
654 fn should_retry(&self, error: &anyhow::Error, context: &RetryContext) -> RetryDecision;
656
657 fn stats(&self) -> RetryStats;
659}
660
661pub struct CircuitBreakerWrapper<T: CircuitBreakerTrait> {
663 inner: T,
664}
665
666impl<T: CircuitBreakerTrait> CircuitBreakerWrapper<T> {
667 pub const fn new(inner: T) -> Self {
668 Self { inner }
669 }
670}
671
672#[async_trait]
673impl<T: CircuitBreakerTrait> DynCircuitBreaker for CircuitBreakerWrapper<T> {
674 async fn call_json(
675 &self,
676 name: &str,
677 request: serde_json::Value,
678 ) -> Result<serde_json::Value, CircuitBreakerError> {
679 self.inner
680 .call(name, || async {
681 Ok(serde_json::json!({
683 "result": "processed",
684 "request": request
685 }))
686 })
687 .await
688 }
689
690 fn state(&self, name: &str) -> CircuitState {
691 self.inner.state(name)
692 }
693
694 fn stats(&self, name: &str) -> CircuitStats {
695 self.inner.stats(name)
696 }
697
698 async fn trip(&self, name: &str, reason: &str) {
699 self.inner.trip(name, reason).await;
700 }
701
702 async fn reset(&self, name: &str) {
703 self.inner.reset(name).await;
704 }
705}
706
707pub struct RetryStrategyWrapper<T: RetryStrategyTrait> {
709 inner: T,
710}
711
712impl<T: RetryStrategyTrait> RetryStrategyWrapper<T> {
713 pub const fn new(inner: T) -> Self {
714 Self { inner }
715 }
716}
717
718#[async_trait]
719impl<T: RetryStrategyTrait> DynRetryStrategy for RetryStrategyWrapper<T> {
720 async fn execute_json(
721 &self,
722 operation: &str,
723 request: serde_json::Value,
724 ) -> Result<serde_json::Value> {
725 self.inner
726 .execute(operation, || async {
727 Ok(serde_json::json!({
729 "result": "processed",
730 "request": request
731 }))
732 })
733 .await
734 }
735
736 fn should_retry(&self, error: &anyhow::Error, context: &RetryContext) -> RetryDecision {
737 self.inner.should_retry(error, context)
738 }
739
740 fn stats(&self) -> RetryStats {
741 self.inner.stats()
742 }
743}