### Run Basic Scan Example Source: https://github.com/dotdon/scanbridge/blob/main/README.md Execute the basic scan example using Cargo. This demonstrates the fundamental scanning functionality. ```bash # Basic scanning cargo run --example basic_scan ``` -------------------------------- ### Run Custom Backend Example Source: https://github.com/dotdon/scanbridge/blob/main/README.md Execute the custom backend implementation example using Cargo. This is useful for demonstrating custom scanner integrations. ```bash # Custom backend implementation cargo run --example custom_backend ``` -------------------------------- ### Run Circuit Breaker Example Source: https://github.com/dotdon/scanbridge/blob/main/README.md Execute the circuit breaker demonstration example using Cargo. This showcases how the circuit breaker pattern is applied. ```bash # Circuit breaker demonstration cargo run --example with_circuit_breaker ``` -------------------------------- ### Create Backend Module Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Create a new Rust file for the backend module. This example creates 'src/backends/threat_intel.rs'. ```rust #[cfg(feature = "threat-intel")] pub mod threat_intel; #[cfg(feature = "threat-intel")] pub use threat_intel::ThreatIntelScanner; ``` -------------------------------- ### Basic Scanbridge Usage with MockScanner Source: https://github.com/dotdon/scanbridge/blob/main/README.md Demonstrates how to initialize Scanbridge with a mock scanner, build a scan manager, and perform a scan on a file. This example shows how to check if a file is clean or infected. ```rust use scanbridge::prelude::*; use scanbridge::backends::MockScanner; #[tokio::main] async fn main() -> Result<(), Box> { // Create a scanner let scanner = MockScanner::new_clean(); // Build the scan manager let manager = ScanManager::builder() .add_scanner(scanner) .build()?; // Scan a file let input = FileInput::from_bytes(b"file content".to_vec()); let context = ScanContext::new().with_tenant_id("my-tenant"); let report = manager.scan(input, context).await?; if report.is_clean() { println!("File is clean!"); } else if report.is_infected() { println!("Threats detected: {:?}", report.all_threats()); } Ok(()) } ``` -------------------------------- ### Configure Log Rotation Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Example configuration for daily log rotation, keeping 365 days of compressed logs. Ensure logs are not rotated if empty. ```bash # Example log rotation config /var/log/scanbridge/audit.json { daily rotate 365 compress notifempty missingok } ``` -------------------------------- ### Policy Rule for FailOpen Source Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Example of a policy rule to block files when the circuit breaker is in FailOpen mode and the source is 'failopen'. ```rust PolicyRule::new("block-fallback", PolicyAction::require_review()) .with_condition(Condition::SourceEquals { source: "failopen".into() }) ``` -------------------------------- ### Implement Custom S3 Quarantine Storage Backend Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Example implementation of the `QuarantineStore` trait for storing quarantine records in AWS S3. This includes methods for storing, retrieving, deleting, and listing records. ```rust use scanbridge::quarantine::{QuarantineStore, QuarantineRecord, QuarantineId, QuarantineFilter}; use scanbridge::core::{FileInput, QuarantineError}; use async_trait::async_trait; #[derive(Debug)] pub struct S3QuarantineStore { bucket: String, client: aws_sdk_s3::Client, } #[async_trait] impl QuarantineStore for S3QuarantineStore { async fn store( &self, input: &FileInput, record: QuarantineRecord, ) -> Result { // Upload to S3 with metadata todo!() } async fn retrieve( &self, id: &QuarantineId, ) -> Result<(Vec, QuarantineRecord), QuarantineError> { // Download from S3 todo!() } async fn delete(&self, id: &QuarantineId) -> Result<(), QuarantineError> { // Delete from S3 todo!() } async fn list( &self, filter: QuarantineFilter, ) -> Result, QuarantineError> { // Query DynamoDB/metadata store todo!() } } ``` -------------------------------- ### Integrate FilesystemQuarantine with ScanManager Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Configures ScanManager to use FilesystemQuarantine for storing quarantined files. This setup automatically handles file storage and audit events when a scan policy dictates quarantine. ```rust use scanbridge::quarantine::FilesystemQuarantine; let quarantine = FilesystemQuarantine::new("/var/quarantine")?; let manager = ScanManager::builder() .add_scanner(scanner) .with_quarantine(quarantine) .build()?; ``` -------------------------------- ### Add Feature Flag in Cargo.toml Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Define a new feature flag in Cargo.toml to enable the backend. This example uses 'threat-intel' and depends on the 'reqwest' crate. ```toml [features] threat-intel = ["reqwest"] ``` -------------------------------- ### Scan Started Event Structure Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md This JSON structure represents an audit log event emitted when a scan begins. It includes identifiers for the scan, tenant, user, and source. ```json { "event_type": "scan_started", "scan_id": "550e8400-e29b-41d4-a716-446655440000", "file_hash_blake3": "abc123...", "tenant_id": "customer-123", "user_id": "user-456", "source": "upload" } ``` -------------------------------- ### Perform Periodic Cleanup of Expired Quarantine Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Execute a cleanup operation to remove expired quarantine records. This function should be run periodically, for example, as a daily cron job. ```rust // Run periodically (e.g., daily cron job) let deleted = quarantine.cleanup_expired().await?; tracing::info!(deleted = deleted, "Quarantine cleanup complete"); ``` -------------------------------- ### Create FilesystemQuarantine Storage Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Initializes a new FilesystemQuarantine instance. Ensure the specified directory exists and has appropriate permissions. ```rust use scanbridge::quarantine::FilesystemQuarantine; // Create quarantine storage let quarantine = FilesystemQuarantine::new("/var/lib/scanbridge/quarantine")?; ``` -------------------------------- ### Initialize Filesystem Quarantine Source: https://github.com/dotdon/scanbridge/blob/main/README.md Create a FilesystemQuarantine instance to store infected files. Files are stored with integrity verification. ```rust use scanbridge::quarantine::FilesystemQuarantine; let quarantine = FilesystemQuarantine::new("/var/quarantine")?; // Files are stored with integrity verification // and can be retrieved, listed, or deleted ``` -------------------------------- ### Basic Circuit Breaker Usage Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Demonstrates how to initialize and use a circuit breaker to protect a scanner. This snippet shows setting up a mock scanner, configuring the circuit breaker with custom thresholds and durations, and then using the protected scanner. ```rust use scanbridge::backends::MockScanner; use scanbridge::circuit_breaker::{CircuitBreaker, CircuitBreakerConfig}; use std::time::Duration; // Create a scanner let scanner = MockScanner::new_clean(); // Configure the circuit breaker let config = CircuitBreakerConfig::default() .with_failure_threshold(5) .with_open_duration(Duration::from_secs(30)) .with_success_threshold(3); // Wrap the scanner let protected = CircuitBreaker::new(scanner, config); // Use protected just like a regular scanner let result = protected.scan(&input).await; ``` -------------------------------- ### Basic Stdout Logging Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Initializes simple logging to standard output with INFO level verbosity. ```rust use tracing_subscriber::fmt; // Simple stdout logging tracing_subscriber::fmt() .with_max_level(tracing::Level::INFO) .init(); ``` -------------------------------- ### Multiple Log Outputs (File and Console) Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Sets up two distinct logging layers: one for JSON audit logs to a file, and another for general INFO level logs to the console. ```rust use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use tracing_subscriber::fmt; // File output for audit logs let audit_file = std::fs::File::create("/var/log/scanbridge/audit.json")?; let audit_layer = fmt::layer() .json() .with_writer(audit_file) .with_filter(tracing_subscriber::filter::filter_fn(|meta| { meta.target().starts_with("scanbridge::audit") })); // Console output for everything let console_layer = fmt::layer() .with_filter(tracing::Level::INFO); tracing_subscriber::registry() .with(audit_layer) .with(console_layer) .init(); ``` -------------------------------- ### Implement Threat Intel Scanner Helper Methods Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Provides implementations for reading file inputs (path or bytes) and querying a threat intelligence API. It handles API requests, response parsing, and specific error conditions like rate limiting or not found. ```rust impl ThreatIntelScanner { async fn read_file(&self, input: &FileInput) -> Result, ScanError> { match input { FileInput::Path(path) => { tokio::fs::read(path) .await .map_err(ScanError::Io) } FileInput::Bytes { data, .. } => Ok(data.clone()), FileInput::Stream { .. } => { Err(ScanError::internal("Streaming not supported")) } } } async fn query_api(&self, hash: &FileHash) -> Result { use secrecy::ExposeSecret; let sha256 = hash.sha256.as_ref().ok_or_else(|| { ScanError::internal("SHA256 required for threat intel API") })?; let url = format!("{}/lookup/{}", self.config.api_url, sha256); let response = self.client .get(&url) .header("X-API-Key", self.config.api_key.expose_secret()) .send() .await .map_err(|e| ScanError::connection_failed(self.name(), e.to_string()))?; match response.status() { s if s.is_success() => { let body: serde_json::Value = response.json().await .map_err(|e| ScanError::AmbiguousResponse { engine: self.name().into(), details: e.to_string(), })?; self.parse_response(&body) } reqwest::StatusCode::NOT_FOUND => { // Hash not in database = clean Ok(ScanOutcome::Clean) } reqwest::StatusCode::TOO_MANY_REQUESTS => { Err(ScanError::RateLimited { engine: self.name().into(), retry_after: Some(std::time::Duration::from_secs(60)), }) } s => { Err(ScanError::engine_unavailable( self.name(), format!("API returned {}", s), )) } } } fn parse_response(&self, json: &serde_json::Value) -> Result { let is_malicious = json.get("malicious") .and_then(|v| v.as_bool()) .unwrap_or(false); if is_malicious { let threat_name = json.get("threat_name") .and_then(|v| v.as_str()) .unwrap_or("Unknown"); let severity = match json.get("severity").and_then(|v| v.as_str()) { Some("critical") => ThreatSeverity::Critical, Some("high") => ThreatSeverity::High, Some("medium") => ThreatSeverity::Medium, _ => ThreatSeverity::Low, }; Ok(ScanOutcome::Infected { threats: vec![ ThreatInfo::new(threat_name, severity, self.name()) ], }) } else { Ok(ScanOutcome::Clean) } } } ``` -------------------------------- ### Elasticsearch/OpenSearch Logging with Bunyan Format Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Integrates with Elasticsearch or OpenSearch by formatting logs using the Bunyan format and writing them to a rolling daily file. ```rust use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; use tracing_subscriber::Registry; let app_name = "scanbridge-service"; let (non_blocking, _guard) = tracing_appender::non_blocking( tracing_appender::rolling::daily("/var/log/scanbridge", "audit") ); let bunyan_layer = BunyanFormattingLayer::new(app_name.into(), non_blocking); Registry::default() .with(JsonStorageLayer) .with(bunyan_layer) .init(); ``` -------------------------------- ### Fail Open Fallback Behavior Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Configure the circuit breaker to allow files through when the circuit is open. Use with caution as this may allow potentially infected files to pass. ```rust .with_fallback_behavior(FallbackBehavior::FailOpen) ``` -------------------------------- ### Include Context in Scan Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Add tenant, user, request, and source information to the scan context. This is crucial for detailed audit trails. ```rust let context = ScanContext::new() .with_tenant_id(&tenant_id) .with_user_id(&user_id) .with_request_id(&request_id) .with_source("api-upload"); ``` -------------------------------- ### Quarantine File Recovery Workflow Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md This Rust code demonstrates the workflow for recovering a file determined to be a false positive from quarantine. It includes retrieving, optionally re-scanning, returning the file, deleting from quarantine, and logging the action. ```rust // 1. Retrieve the file let (data, record) = quarantine.retrieve(&id).await?; // 2. Re-scan with updated signatures (optional) let input = FileInput::from_bytes(data.clone()); let new_result = manager.scan(input, context).await?; if new_result.is_clean() { // 3. Return to user/original location tokio::fs::write(&original_path, &data).await?; // 4. Delete from quarantine quarantine.delete(&id).await?; // 5. Log the recovery tracing::info!( quarantine_id = %id, file_hash = %record.file_hash.blake3, "False positive recovered from quarantine" ); } ``` -------------------------------- ### Add Scanbridge to Cargo.toml Source: https://github.com/dotdon/scanbridge/blob/main/README.md Include Scanbridge and Tokio as dependencies in your project's Cargo.toml file. Ensure Tokio is configured with the 'full' feature set. ```toml [dependencies] scanbridge = "0.1" tokio = { version = "1", features = ["full"] } ``` -------------------------------- ### Configure JSON Audit Logging Subscriber Source: https://github.com/dotdon/scanbridge/blob/main/README.md Set up a tracing subscriber to output audit events in JSON format. This is useful for compliance logging. ```rust use tracing_subscriber::fmt::format::FmtSpan; // Configure a JSON subscriber for compliance logging tracing_subscriber::fmt() .json() .with_target(true) .init(); ``` -------------------------------- ### Configure Non-Blocking File Writer for Tracing Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Configure a non-blocking writer for the tracing subscriber to improve audit logging performance in high-volume scenarios. This prevents blocking I/O on the critical path. ```rust use tracing_appender::non_blocking; let (non_blocking_writer, _guard) = non_blocking(file); tracing_subscriber::fmt() .with_writer(non_blocking_writer) .init(); ``` -------------------------------- ### Apply Various Filtering Options for Quarantine Records Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Construct a QuarantineFilter to specify criteria for listing records, including tenant ID, file hash, date range, and pagination. Optionally include expired records. ```rust let filter = QuarantineFilter::new() // By tenant .with_tenant_id("tenant-123") // By file hash .with_file_hash("abc123...") // By date range .with_date_range( Some(Utc::now() - chrono::Duration::days(7)), None, ) // Pagination .with_pagination(20, 0) // limit, offset // Include expired records .with_include_expired(true); ``` -------------------------------- ### Store a File in Quarantine Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Create a QuarantineRecord with file details and store it using the quarantine system. This is used after a scan identifies an infected file. ```rust use scanbridge::quarantine::{QuarantineRecord, FilesystemQuarantine}; // After a scan with infected result... let record = QuarantineRecord::new( result.file_hash().clone(), result.file_metadata.size, "Malware detected: Trojan.GenericKD", result.clone(), ) .with_original_filename("suspicious.exe") .with_tenant_id("customer-123") .with_metadata("source", "email-attachment"); let id = quarantine.store(&input, record).await?; println!("File quarantined with ID: {}", id); ``` -------------------------------- ### CloudWatch Logs Configuration Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Sets up JSON logging for CloudWatch. Disables ANSI color codes for compatibility with CloudWatch's text-based log streams. ```rust // Use tracing-subscriber with JSON formatting // Forward stdout/stderr to CloudWatch via container logging driver tracing_subscriber::fmt() .json() .with_target(true) .with_ansi(false) // No color codes .init(); ``` -------------------------------- ### JSON Output Logging Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Configures logging to output in JSON format for machine readability. Includes target information but disables current span tracking. ```rust use tracing_subscriber::fmt::format::FmtSpan; tracing_subscriber::fmt() .json() .with_target(true) .with_current_span(false) .init(); ``` -------------------------------- ### Configure Half-Open Max Probes Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Limits the number of concurrent probe requests allowed when the circuit is in the half-open state. This prevents overwhelming a recovering service. ```rust .with_half_open_max_probes(1) // Default: 1 ``` -------------------------------- ### Datadog JSON Logging Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Configures JSON logging suitable for Datadog, including target information and current span tracking. Alternatively, suggests using the `datadog-tracing` crate for native integration. ```rust // Datadog expects specific JSON format // Use custom formatting or datadog-tracing crate tracing_subscriber::fmt() .json() .with_target(true) .with_current_span(true) .init(); // Or use datadog-tracing for native integration ``` -------------------------------- ### ThreatIntelScanner Constructor Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Creates a new ThreatIntelScanner instance, initializing the HTTP client with a specified timeout. ```rust impl ThreatIntelScanner { pub fn new(config: ThreatIntelConfig) -> Result { let client = reqwest::Client::builder() .timeout(config.timeout) .build() .map_err(|e| ScanError::configuration(format!( "Failed to create HTTP client: {}", e )))?; Ok(Self { config, client, // Enable SHA256 for API compatibility hasher: FileHasher::new().with_sha256(true), }) } } ``` -------------------------------- ### Implement a Custom Scanner Backend Source: https://github.com/dotdon/scanbridge/blob/main/README.md Implement the Scanner trait to create a custom backend for Scanbridge. This involves defining the scanner's name, scan logic, and health check. ```rust use scanbridge::prelude::*; use async_trait::async_trait; #[derive(Debug)] struct MyScanner { /* ... */ } #[async_trait] impl Scanner for MyScanner { fn name(&self) -> &str { "my-scanner" } async fn scan(&self, input: &FileInput) -> Result { // Your scanning logic here todo!() } async fn health_check(&self) -> Result<(), ScanError> { // Verify scanner is operational Ok(()) } } ``` -------------------------------- ### Fallback Scanner Configuration Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Set up an alternate scanner to be used when the primary scanner's circuit breaker is open. This ensures scans continue using a fallback mechanism. ```rust use std::sync::Arc; let primary = ClamAvScanner::new(config)?; let fallback: Arc = Arc::new(MockScanner::new_clean()); let config = CircuitBreakerConfig::default() .with_fallback_behavior(FallbackBehavior::Fallback(fallback)); let protected = CircuitBreaker::new(primary, config); ``` -------------------------------- ### Strict Circuit Breaker Configuration Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Use this configuration for security-critical paths. It opens quickly and recovers slowly. ```rust let config = CircuitBreakerConfig::strict(); // failure_threshold: 3 // success_threshold: 5 // open_duration: 60s // fallback: FailClosed ``` -------------------------------- ### OpenTelemetry Logging with Jaeger Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Configures logging to send traces to Jaeger via OpenTelemetry. Includes standard console logging alongside the OpenTelemetry layer. ```rust use tracing_opentelemetry::OpenTelemetryLayer; use opentelemetry::global; let tracer = opentelemetry_jaeger::new_pipeline() .with_service_name("scanbridge") .install_simple()?; tracing_subscriber::registry() .with(tracing_subscriber::fmt::layer()) .with(OpenTelemetryLayer::new(tracer)) .init(); ``` -------------------------------- ### Access Circuit Breaker Metrics Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Retrieve and print various performance metrics of the circuit breaker, such as request counts, rejection counts, and success rate. ```rust let metrics = protected.metrics(); println!("Total requests: {}", metrics.total_requests); println!("Successful: {}", metrics.successful_requests); println!("Failed: {}", metrics.failed_requests); println!("Rejected (circuit open): {}", metrics.rejected_requests); println!("Times opened: {}", metrics.times_opened); println!("Times closed: {}", metrics.times_closed); println!("Success rate: {:.1}%", metrics.success_rate() * 100.0); ``` -------------------------------- ### Define Policy Rules for Scan Results Source: https://github.com/dotdon/scanbridge/blob/main/README.md Use PolicyEngine to define rules with conditions and actions for handling scan results. Rules can be prioritized. ```rust use scanbridge::policy::{PolicyEngine, PolicyRule, Condition, PolicyAction}; let policy = PolicyEngine::new() .with_rule( PolicyRule::new("block-infected", PolicyAction::block("Malware detected")) .with_condition(Condition::is_infected()) .with_priority(100) ) .with_rule( PolicyRule::new("quarantine-suspicious", PolicyAction::quarantine("Review needed")) .with_condition(Condition::is_suspicious()) .with_priority(90) ); ``` -------------------------------- ### Built-in Failure Policies Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Utilize predefined failure policies for common scenarios. Options include the default policy, counting all errors, or only connection-related failures. ```rust // Default: timeouts, connections, unavailable let policy = FailurePolicy::default(); ``` ```rust // Count all errors as failures let policy = FailurePolicy::all_errors(); ``` ```rust // Only connection-related failures let policy = FailurePolicy::connection_only(); ``` -------------------------------- ### List Quarantine Records with Filter Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Retrieve a list of quarantine records based on specified filters, such as tenant ID. This is useful for auditing or managing quarantined items. ```rust use scanbridge::quarantine::QuarantineFilter; // List all records for a tenant let filter = QuarantineFilter::new() .with_tenant_id("customer-123"); let records = quarantine.list(filter).await?; for record in records { println!("{}: {} ({})", record.id, record.original_filename.unwrap_or_default(), record.quarantined_at); } ``` -------------------------------- ### Integrate Scanner with Circuit Breaker Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Demonstrates how to wrap a ThreatIntelScanner instance with a CircuitBreaker for enhanced resilience. This protected instance can then be added to the ScanManager. ```rust use scanbridge::circuit_breaker::{CircuitBreaker, CircuitBreakerConfig}; let scanner = ThreatIntelScanner::new(config)?; let protected = CircuitBreaker::new( scanner, CircuitBreakerConfig::default(), ); // Now protected can be used with ScanManager let manager = ScanManager::builder() .add_scanner(protected) .build()?; ``` -------------------------------- ### Retrieve a File from Quarantine Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Fetch quarantined file data and its associated record using a unique ID. Handle retrieved files with extreme caution as they may be malicious. ```rust let (file_data, record) = quarantine.retrieve(&id).await?; println!("Original filename: {:?}", record.original_filename); println!("Quarantined at: {}", record.quarantined_at); println!("Reason: {}", record.reason); println!("File size: {} bytes", file_data.len()); ``` -------------------------------- ### ThreatIntelConfig Struct Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Configuration for the threat intel scanner, including API details and timeouts. ```rust use scanbridge::prelude::*; use async_trait::async_trait; /// Configuration for the threat intel scanner. #[derive(Debug, Clone)] pub struct ThreatIntelConfig { pub api_url: String, pub api_key: secrecy::SecretString, pub timeout: std::time::Duration, pub max_file_size: u64, } impl Default for ThreatIntelConfig { fn default() -> Self { Self { api_url: "https://api.threatintel.example.com/v1".into(), api_key: secrecy::SecretString::new("".into()), timeout: std::time::Duration::from_secs(30), max_file_size: 100 * 1024 * 1024, // 100 MB } } } ``` -------------------------------- ### Emit Custom Audit Event Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Use this snippet to log application-specific events within the audit log. Ensure the `tracing` crate is included and the target filter is set correctly. ```rust use tracing::info; // After processing a scan result info!( target: "scanbridge::audit", event_type = "file_processed", file_hash_blake3 = %report.file_hash.blake3, outcome = ?report.aggregated_outcome, storage_path = %final_path, processing_duration_ms = processing_time.as_millis(), "File processing completed" ); ``` -------------------------------- ### Fail Closed Fallback Behavior Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Configure the circuit breaker to reject all scans when the circuit is open. This is the safest default option. ```rust use scanbridge::circuit_breaker::FallbackBehavior; let config = CircuitBreakerConfig::default() .with_fallback_behavior(FallbackBehavior::FailClosed); ``` -------------------------------- ### Configure Success Threshold Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Determines the number of successful probes needed in the half-open state to close the circuit. A higher threshold ensures the service is stable before resuming normal traffic. ```rust .with_success_threshold(3) // Default: 3 ``` -------------------------------- ### Integrate Circuit Breaker Scanners with ScanManager Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Wrap scanners with circuit breakers and add them to a ScanManager. Each scanner will have its own independent circuit breaker state. ```rust use std::sync::Arc; let clamav = ClamAvScanner::new(clamav_config)?; let clamav_cb = CircuitBreaker::new(clamav, CircuitBreakerConfig::strict()); let vt = VirusTotalScanner::new(vt_config)?; let vt_cb = CircuitBreaker::new(vt, CircuitBreakerConfig::high_availability()); let manager = ScanManager::builder() .add_arc_scanner(Arc::new(clamav_cb)) .add_arc_scanner(Arc::new(vt_cb)) .build()?; ``` -------------------------------- ### Integration Test for Real API Scan Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Tests the scanner's ability to interact with a real API by scanning the EICAR test file. Requires the THREAT_INTEL_API_KEY environment variable to be set. ```rust #[tokio::test] #[ignore] // Run with: cargo test -- --ignored async fn test_real_api() { let config = ThreatIntelConfig { api_key: std::env::var("THREAT_INTEL_API_KEY") .expect("Set THREAT_INTEL_API_KEY") .into(), ..Default::default() }; let scanner = ThreatIntelScanner::new(config).unwrap(); // Test with EICAR test file let eicar = b"X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"; let input = FileInput::from_bytes(eicar.to_vec()); let result = scanner.scan(&input).await.unwrap(); assert!(result.is_infected()); } ``` -------------------------------- ### Configure Open Duration Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Specifies how long the circuit breaker remains in the open state before transitioning to half-open. This duration allows the protected service time to recover. ```rust .with_open_duration(Duration::from_secs(30)) // Default: 30s ``` -------------------------------- ### Configure Circuit Breaker Source: https://github.com/dotdon/scanbridge/blob/main/README.md Configure the circuit breaker with failure and success thresholds, and the duration the circuit remains open. This helps prevent cascading failures by temporarily blocking requests to an unhealthy scanner. ```rust use scanbridge::circuit_breaker::{CircuitBreaker, CircuitBreakerConfig}; use std::time::Duration; let config = CircuitBreakerConfig::default() .with_failure_threshold(5) // Open after 5 failures .with_open_duration(Duration::from_secs(30)) // Stay open 30s .with_success_threshold(3); // Close after 3 successes let protected = CircuitBreaker::new(scanner, config); ``` -------------------------------- ### Policy Rule Structure Source: https://github.com/dotdon/scanbridge/blob/main/docs/architecture.md Defines a policy rule for the policy engine, specifying conditions and actions. Higher priority rules are evaluated first. ```rust PolicyRule { id: "block-infected", name: "Block Infected Files", conditions: [Condition::is_infected()], action: PolicyAction::Block { reason: "Malware detected" }, priority: 100, // Higher = evaluated first } ``` -------------------------------- ### Custom Failure Policy Configuration Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Configure which error types are counted as failures for the circuit breaker. Set specific boolean flags for timeouts, connection failures, engine unavailability, rate limiting, and all other errors. ```rust use scanbridge::circuit_breaker::FailurePolicy; let policy = FailurePolicy { count_timeouts: true, // Connection/scan timeouts count_connection_failures: true, // Network errors count_engine_unavailable: true, // Service down count_rate_limited: false, // Rate limiting (expected) count_all_errors: false, // Everything else }; let config = CircuitBreakerConfig::default() .with_failure_policy(policy); ``` -------------------------------- ### Implement Scanner Trait for ThreatIntelScanner Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Implements the Scanner trait for ThreatIntelScanner, defining how it scans files and performs health checks. ```rust @async_trait impl Scanner for ThreatIntelScanner { fn name(&self) -> &str { "threat-intel" } async fn scan(&self, input: &FileInput) -> Result { use std::time::Instant; let start = Instant::now(); // 1. Read and hash the file let data = self.read_file(input).await?; if data.len() as u64 > self.config.max_file_size { return Err(ScanError::FileTooLarge { size: data.len() as u64, max: self.config.max_file_size, }); } let hash = self.hasher.hash_bytes(&data); // 2. Query the threat intel API let outcome = self.query_api(&hash).await?; // 3. Build the result let duration = start.elapsed(); let metadata = FileMetadata::new(data.len() as u64, hash) .with_filename(input.filename().unwrap_or("unknown").to_string()); Ok(ScanResult::new( outcome, metadata, self.name(), duration, ScanContext::new(), )) } async fn health_check(&self) -> Result<(), ScanError> { // Check API is reachable with a simple request let url = format!("{}/health", self.config.api_url); let response = self.client .get(&url) .header("X-API-Key", self.config.api_key.expose_secret()) .send() .await .map_err(|e| ScanError::connection_failed(self.name(), e.to_string()))?; if response.status().is_success() { Ok(()) } else { Err(ScanError::engine_unavailable( self.name(), format!("Health check failed: {}", response.status()), )) } } fn max_file_size(&self) -> Option { Some(self.config.max_file_size) } } ``` -------------------------------- ### QuarantineStore Trait Interface Source: https://github.com/dotdon/scanbridge/blob/main/docs/architecture.md Defines the asynchronous interface for interacting with the quarantine storage system. Implement this trait for custom storage backends. ```rust pub trait QuarantineStore: Send + Sync { async fn store(&self, input: &FileInput, record: QuarantineRecord) -> Result; async fn retrieve(&self, id: &QuarantineId) -> Result<(Vec, QuarantineRecord), QuarantineError>; async fn delete(&self, id: &QuarantineId) -> Result<(), QuarantineError>; async fn list(&self, filter: QuarantineFilter) -> Result, QuarantineError>; } ``` -------------------------------- ### High Availability Circuit Breaker Configuration Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md This configuration is tolerant of failures with quick recovery, suitable for non-critical scans. ```rust let config = CircuitBreakerConfig::high_availability(); // failure_threshold: 10 // success_threshold: 2 // open_duration: 10s // fallback: FailClosed ``` -------------------------------- ### ThreatIntelScanner Struct Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Represents a scanner that queries a threat intelligence API. ```rust /// A scanner that checks file hashes against a threat intelligence API. #[derive(Debug)] pub struct ThreatIntelScanner { config: ThreatIntelConfig, client: reqwest::Client, hasher: FileHasher, } ``` -------------------------------- ### Filter to Audit Events Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md Configures JSON logging to filter and only display events from the 'scanbridge::audit' target at INFO level or higher. ```rust use tracing_subscriber::EnvFilter; tracing_subscriber::fmt() .json() .with_env_filter( EnvFilter::new("scanbridge::audit=info") ) .init(); ``` -------------------------------- ### Increment Quarantine Metrics Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Use this snippet to increment metrics after quarantine operations, such as adding a file or updating storage usage. ```rust // After quarantine operations metrics.quarantine_files_total.inc(); metrics.quarantine_storage_bytes.add(record.file_size as f64); ``` -------------------------------- ### Scanner Trait Definition Source: https://github.com/dotdon/scanbridge/blob/main/docs/architecture.md Defines the core interface for all scanning backends. Implementations must handle sending data and parsing results asynchronously. ```rust #[async_trait] pub trait Scanner: Send + Sync + Debug { fn name(&self) -> &str; async fn scan(&self, input: &FileInput) -> Result; async fn health_check(&self) -> Result<(), ScanError>; } ``` -------------------------------- ### Quarantine Operation Event Structure Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md This JSON structure details an audit log event for quarantine actions. It includes the quarantine ID, file hash, operation type, reason, and file size. ```json { "event_type": "quarantine_operation", "quarantine_id": "770e8400-e29b-41d4-a716-446655440002", "file_hash_blake3": "abc123...", "operation": "store", "reason": "Malware detected", "tenant_id": "customer-123", "file_size": 15234 } ``` -------------------------------- ### Scan Completed Event Structure Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md This JSON structure details an audit log event for a completed scan by a single engine. It includes file hashes, scan outcome, engine used, and duration. ```json { "event_type": "scan_completed", "scan_id": "550e8400-e29b-41d4-a716-446655440000", "file_hash_blake3": "abc123...", "file_hash_sha256": "def456...", "outcome": "clean", "engine": "clamav", "duration_ms": 150, "tenant_id": "customer-123", "cached": false } ``` -------------------------------- ### Configure Failure Threshold Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Sets the number of consecutive failures required to open the circuit. Lower values are stricter, while higher values are more tolerant of temporary issues. ```rust .with_failure_threshold(5) // Default: 5 ``` -------------------------------- ### Inspect Circuit Breaker State Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Retrieve and print the current state of the circuit breaker, including details specific to each state (Closed, Open, HalfOpen). ```rust let state = protected.state(); println!("Current state: {:?}", state.name()); // "closed", "open", or "half_open" match state { BreakerState::Closed { failure_count } => { println!("Failures so far: {}", failure_count); } BreakerState::Open { opened_at, until } => { println!("Opened at: {:?}", opened_at); println!("Will transition at: {:?}", until); } BreakerState::HalfOpen { success_count, probe_count } => { println!("Successes: {}/{}", success_count, config.success_threshold); } } ``` -------------------------------- ### Unit Test for Health Check Source: https://github.com/dotdon/scanbridge/blob/main/docs/adding-backends.md Tests the health check functionality of a scanner using a mock server. Ensures the scanner correctly reports a healthy status. ```rust #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_health_check_success() { // Set up mock server let mock_server = mockito::Server::new(); let _m = mock_server.mock("GET", "/health") .with_status(200) .create(); let config = ThreatIntelConfig { api_url: mock_server.url(), ..Default::default() }; let scanner = ThreatIntelScanner::new(config).unwrap(); assert!(scanner.health_check().await.is_ok()); } #[tokio::test] async fn test_scan_clean_file() { // Test scanning returns Clean for unknown hash } #[tokio::test] async fn test_scan_malicious_file() { // Test scanning returns Infected for known-bad hash } } ``` -------------------------------- ### Policy Decision Event Structure Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md This JSON structure represents an audit log event when a policy decision is made. It details the file hash, the action taken, and the matched rule. ```json { "event_type": "policy_decision", "file_hash_blake3": "abc123...", "action": "block", "matched_rule_id": "block-infected", "matched_rule_name": "Block Infected Files", "reason": "Matched rule: Block Infected Files", "tenant_id": "customer-123" } ``` -------------------------------- ### Scan Report Event Structure Source: https://github.com/dotdon/scanbridge/blob/main/docs/audit-logging.md This JSON structure represents an audit log event for a complete scan report, aggregating results from multiple engines. It includes aggregated outcome, engine details, and threat information. ```json { "event_type": "scan_report", "report_id": "660e8400-e29b-41d4-a716-446655440001", "file_hash_blake3": "abc123...", "aggregated_outcome": "infected", "engines": ["clamav", "virustotal"], "engine_count": 2, "total_duration_ms": 1250, "tenant_id": "customer-123", "threat_count": 1, "threats": [ {"name": "Trojan.GenericKD", "severity": "high", "engine": "clamav"} ] } ``` -------------------------------- ### Manually Control Circuit Breaker State Source: https://github.com/dotdon/scanbridge/blob/main/docs/circuit-breaker.md Manually force the circuit breaker into an open or closed state, or reset its state and metrics. ```rust // Force circuit open (e.g., during maintenance) protected.force_open(); // Force circuit closed protected.force_close(); // Reset state and metrics protected.reset(); ``` -------------------------------- ### Delete and Cleanup Quarantine Records Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Remove a specific quarantine record by its ID or clean up all expired records from the quarantine system. The cleanup operation returns the count of deleted records. ```rust // Delete a specific record quarantine.delete(&id).await?; // Clean up expired records let deleted_count = quarantine.cleanup_expired().await?; println!("Cleaned up {} expired records", deleted_count); ``` -------------------------------- ### Set Expiration for Quarantined Records Source: https://github.com/dotdon/scanbridge/blob/main/docs/quarantine.md Set an expiration date for a quarantined record using chrono::Duration. This is useful for automatically removing old quarantine entries. ```rust use chrono::{Utc, Duration}; let record = QuarantineRecord::new(...) .with_expires_at(Utc::now() + Duration::days(90)); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.