use crate::scanner::Threat;
use anyhow::Result;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use std::time::Duration;
#[cfg(any(test, feature = "test-utils"))]
use mockall::{automock, predicate::*};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Priority {
Normal,
Urgent,
}
#[derive(Debug, Clone)]
pub struct EndpointStats {
pub success_count: u64,
pub failure_count: u64,
pub circuit_state: CircuitState,
pub available_tokens: u32,
}
pub trait EventBufferTrait: Send + Sync {
fn enqueue_event(&self, endpoint_id: u32, data: &[u8], priority: Priority) -> Result<u64>;
fn get_endpoint_stats(&self, endpoint_id: u32) -> Result<EndpointStats>;
}
#[async_trait]
#[cfg_attr(any(test, feature = "test-utils"), automock)]
pub trait SecurityEventProcessor: Send + Sync {
async fn process_event(&self, event: SecurityEvent) -> Result<EventHandle>;
fn get_stats(&self) -> ProcessorStats;
fn is_monitored(&self, endpoint: &str) -> bool;
async fn get_insights(&self, client_id: &str) -> Result<SecurityInsights>;
async fn cleanup(&self) -> Result<()>;
}
#[cfg_attr(any(test, feature = "test-utils"), automock)]
pub trait EnhancedScanner: Send + Sync {
fn enhanced_scan(&self, data: &[u8]) -> Result<Vec<Threat>>;
fn get_metrics(&self) -> ScannerMetrics;
fn preload_patterns(&self, patterns: &[String]) -> Result<()>;
}
#[async_trait]
#[cfg_attr(any(test, feature = "test-utils"), automock)]
pub trait CorrelationEngine: Send + Sync {
async fn correlate(&self, events: &[SecurityEvent]) -> Result<Vec<ThreatPattern>>;
async fn update_rules(&self, rules: CorrelationRules) -> Result<()>;
fn get_correlation_stats(&self) -> CorrelationStats;
}
#[async_trait]
#[cfg_attr(any(test, feature = "test-utils"), automock)]
pub trait RateLimiter: Send + Sync {
async fn check_rate_limit(&self, key: &RateLimitKey) -> Result<RateLimitDecision>;
async fn record_request(&self, key: &RateLimitKey) -> Result<()>;
async fn apply_penalty(&self, client_id: &str, factor: f32) -> Result<()>;
fn get_stats(&self) -> RateLimiterStats;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityEvent {
pub event_type: String,
pub client_id: String,
pub timestamp: u64,
pub metadata: serde_json::Value,
}
#[derive(Debug, Clone)]
pub struct EventHandle {
pub event_id: u64,
pub processed: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessorStats {
pub events_processed: u64,
pub events_per_second: f64,
pub buffer_utilization: f64,
pub correlation_hits: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityInsights {
pub risk_score: f32,
pub detected_patterns: Vec<String>,
pub recommendations: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScannerMetrics {
pub scans_performed: u64,
pub threats_detected: u64,
pub avg_scan_time_us: u64,
pub pattern_cache_hits: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThreatPattern {
pub pattern_type: String,
pub confidence: f32,
pub events: Vec<u64>,
pub description: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CorrelationRules {
pub time_window: std::time::Duration,
pub min_events: usize,
pub patterns: Vec<PatternRule>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PatternRule {
pub name: String,
pub event_types: Vec<String>,
pub threshold: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CorrelationStats {
pub patterns_detected: u64,
pub false_positives: u64,
pub avg_correlation_time_ms: u64,
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct RateLimitKey {
pub client_id: String,
pub method: Option<String>,
}
#[derive(Debug, Clone)]
pub struct RateLimitDecision {
pub allowed: bool,
pub tokens_remaining: f64,
pub reset_after: std::time::Duration,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RateLimiterStats {
pub requests_allowed: u64,
pub requests_denied: u64,
pub active_buckets: usize,
}
pub trait SecurityComponentFactory: Send + Sync {
fn create_event_processor(
&self,
config: &crate::config::Config,
storage: Arc<dyn crate::storage::StorageProvider>,
) -> Result<Arc<dyn SecurityEventProcessor>>;
fn create_scanner(&self, config: &crate::config::Config) -> Result<Arc<dyn EnhancedScanner>>;
fn create_correlation_engine(
&self,
config: &crate::config::Config,
storage: Arc<dyn crate::storage::StorageProvider>,
) -> Result<Arc<dyn CorrelationEngine>>;
fn create_rate_limiter(
&self,
config: &crate::config::Config,
storage: Arc<dyn crate::storage::StorageProvider>,
) -> Result<Arc<dyn RateLimiter>>;
fn create_security_scanner(
&self,
config: &crate::config::Config,
) -> Result<Arc<dyn SecurityScannerTrait>>;
}
#[async_trait]
pub trait CircuitBreakerTrait: Send + Sync {
async fn call<F, T, Fut>(&self, name: &str, f: F) -> Result<T, CircuitBreakerError>
where
F: FnOnce() -> Fut + Send,
Fut: std::future::Future<Output = Result<T>> + Send,
T: Send;
fn state(&self, name: &str) -> CircuitState;
fn stats(&self, name: &str) -> CircuitStats;
async fn trip(&self, name: &str, reason: &str);
async fn reset(&self, name: &str);
}
#[async_trait]
pub trait RetryStrategyTrait: Send + Sync {
async fn execute<F, T, Fut>(&self, operation: &str, f: F) -> Result<T>
where
F: Fn() -> Fut + Send + Sync,
Fut: std::future::Future<Output = Result<T>> + Send,
T: Send;
fn should_retry(&self, error: &anyhow::Error, context: &RetryContext) -> RetryDecision;
fn stats(&self) -> RetryStats;
}
pub trait ResilienceFactory: Send + Sync {
fn create_circuit_breaker(
&self,
config: &crate::config::Config,
) -> Result<Arc<dyn DynCircuitBreaker>>;
fn create_retry_strategy(
&self,
config: &crate::config::Config,
) -> Result<Arc<dyn DynRetryStrategy>>;
fn create_health_checker(
&self,
config: &crate::config::Config,
) -> Result<Arc<dyn HealthCheckTrait>>;
fn create_recovery_strategy(
&self,
config: &crate::config::Config,
) -> Result<Arc<dyn RecoveryStrategyTrait>>;
fn create_bulkhead(
&self,
config: &crate::config::Config,
) -> Result<Arc<dyn crate::resilience::DynBulkhead>>;
}
#[derive(Debug, thiserror::Error, Clone)]
pub enum CircuitBreakerError {
#[error("Circuit breaker is open")]
CircuitOpen,
#[error("Circuit breaker is throttled")]
Throttled,
#[error("Service call failed: {0}")]
ServiceError(String),
#[error("Timeout after {0:?}")]
Timeout(Duration),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CircuitState {
Closed,
Throttled,
HalfOpen,
Open,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CircuitStats {
pub state: CircuitState,
pub failure_count: u32,
pub success_count: u32,
pub total_requests: u64,
pub last_failure_time: Option<u64>,
pub tokens_available: f64,
}
#[derive(Debug, Clone)]
pub struct RetryContext {
pub attempts: u32,
pub error_category: ErrorCategory,
pub total_elapsed: Duration,
}
#[derive(Debug, Clone, Copy)]
pub struct ErrorCategory {
pub is_retryable: bool,
pub error_type: ErrorType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorType {
Network,
Timeout,
RateLimit,
Authentication,
ServerError,
ClientError,
Unknown,
}
#[derive(Debug, Clone)]
pub struct RetryDecision {
pub should_retry: bool,
pub delay: Option<Duration>,
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RetryStats {
pub total_attempts: u64,
pub successful_retries: u64,
pub failed_retries: u64,
pub retry_budget_remaining: u32,
}
#[async_trait]
pub trait HealthCheckTrait: Send + Sync {
async fn check(&self) -> Result<HealthStatus>;
async fn detailed_check(&self) -> Result<HealthReport>;
fn register_dependency(&self, name: String, checker: Arc<dyn HealthCheckTrait>);
fn metadata(&self) -> HealthCheckMetadata;
}
#[async_trait]
pub trait RecoveryStrategyTrait: Send + Sync {
async fn recover(
&self,
context: &RecoveryContext,
operation_name: &str,
) -> Result<serde_json::Value>;
fn can_recover(&self, error: &anyhow::Error) -> bool;
fn stats(&self) -> RecoveryStats;
async fn update_state(&self, state: RecoveryState);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum HealthStatus {
Healthy,
Degraded,
Unhealthy,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthReport {
pub status: HealthStatus,
pub checks: Vec<HealthCheckResult>,
pub timestamp: u64,
pub latency_ms: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthCheckResult {
pub name: String,
pub status: HealthStatus,
pub message: Option<String>,
pub metadata: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthCheckMetadata {
pub name: String,
pub check_type: HealthCheckType,
pub timeout: Duration,
pub critical: bool,
}
#[cfg_attr(any(test, feature = "test-utils"), automock)]
pub trait MetricsProvider: Send + Sync {
fn counter(&self, name: &str, help: &str) -> Arc<dyn CounterTrait>;
fn gauge(&self, name: &str, help: &str) -> Arc<dyn GaugeTrait>;
fn histogram(&self, name: &str, help: &str, buckets: Vec<f64>) -> Arc<dyn HistogramTrait>;
fn export_prometheus(&self) -> String;
fn export_json(&self) -> serde_json::Value;
fn uptime_seconds(&self) -> u64;
}
pub trait CounterTrait: Send + Sync {
fn inc(&self);
fn inc_by(&self, amount: u64);
fn value(&self) -> u64;
}
pub trait GaugeTrait: Send + Sync {
fn set(&self, value: i64);
fn inc(&self);
fn dec(&self);
fn value(&self) -> i64;
}
pub trait HistogramTrait: Send + Sync {
fn observe(&self, value: f64);
fn stats(&self) -> HistogramStats;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistogramStats {
pub count: u64,
pub sum: f64,
pub average: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum HealthCheckType {
Liveness,
Readiness,
Startup,
Dependency,
}
#[derive(Debug, Clone)]
pub struct RecoveryContext {
pub failure_count: u32,
pub last_error: String,
pub recovery_attempts: u32,
pub service_name: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RecoveryState {
Normal,
Recovering,
Fallback,
Failed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RecoveryStats {
pub recoveries_attempted: u64,
pub recoveries_succeeded: u64,
pub fallbacks_used: u64,
pub current_state: RecoveryState,
}
#[cfg_attr(any(test, feature = "test-utils"), automock)]
pub trait SecurityScannerTrait: Send + Sync {
fn scan_text(&self, text: &str) -> Vec<crate::scanner::Threat>;
fn scan_json(&self, value: &serde_json::Value) -> Vec<crate::scanner::Threat>;
fn scan_with_depth(&self, text: &str, max_depth: usize) -> Vec<crate::scanner::Threat>;
fn get_stats(&self) -> ScannerStats;
fn reset_stats(&self);
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScannerStats {
pub texts_scanned: u64,
pub threats_found: u64,
pub unicode_threats: u64,
pub injection_threats: u64,
pub pattern_threats: u64,
pub avg_scan_time_us: u64,
}
#[async_trait]
pub trait DynCircuitBreaker: Send + Sync {
async fn call_json(
&self,
name: &str,
request: serde_json::Value,
) -> Result<serde_json::Value, CircuitBreakerError>;
fn state(&self, name: &str) -> CircuitState;
fn stats(&self, name: &str) -> CircuitStats;
async fn trip(&self, name: &str, reason: &str);
async fn reset(&self, name: &str);
}
#[async_trait]
pub trait DynRetryStrategy: Send + Sync {
async fn execute_json(
&self,
operation: &str,
request: serde_json::Value,
) -> Result<serde_json::Value>;
fn should_retry(&self, error: &anyhow::Error, context: &RetryContext) -> RetryDecision;
fn stats(&self) -> RetryStats;
}
pub struct CircuitBreakerWrapper<T: CircuitBreakerTrait> {
inner: T,
}
impl<T: CircuitBreakerTrait> CircuitBreakerWrapper<T> {
pub const fn new(inner: T) -> Self {
Self { inner }
}
}
#[async_trait]
impl<T: CircuitBreakerTrait> DynCircuitBreaker for CircuitBreakerWrapper<T> {
async fn call_json(
&self,
name: &str,
request: serde_json::Value,
) -> Result<serde_json::Value, CircuitBreakerError> {
self.inner
.call(name, || async {
Ok(serde_json::json!({
"result": "processed",
"request": request
}))
})
.await
}
fn state(&self, name: &str) -> CircuitState {
self.inner.state(name)
}
fn stats(&self, name: &str) -> CircuitStats {
self.inner.stats(name)
}
async fn trip(&self, name: &str, reason: &str) {
self.inner.trip(name, reason).await;
}
async fn reset(&self, name: &str) {
self.inner.reset(name).await;
}
}
pub struct RetryStrategyWrapper<T: RetryStrategyTrait> {
inner: T,
}
impl<T: RetryStrategyTrait> RetryStrategyWrapper<T> {
pub const fn new(inner: T) -> Self {
Self { inner }
}
}
#[async_trait]
impl<T: RetryStrategyTrait> DynRetryStrategy for RetryStrategyWrapper<T> {
async fn execute_json(
&self,
operation: &str,
request: serde_json::Value,
) -> Result<serde_json::Value> {
self.inner
.execute(operation, || async {
Ok(serde_json::json!({
"result": "processed",
"request": request
}))
})
.await
}
fn should_retry(&self, error: &anyhow::Error, context: &RetryContext) -> RetryDecision {
self.inner.should_retry(error, context)
}
fn stats(&self) -> RetryStats {
self.inner.stats()
}
}