scanbridge 0.3.0

A unified, pluggable API for malware scanning with circuit breakers, policy enforcement, and audit logging
Documentation
# Quarantine Guide

Quarantine storage provides a secure way to isolate and track potentially malicious files. This is essential for compliance, forensic analysis, and false-positive recovery.

## Overview

When a file is quarantined:

1. Original file is moved/copied to secure storage
2. Metadata is recorded (hash, source, reason, scan results)
3. Original file can optionally be deleted
4. Files can be retrieved, listed, or permanently deleted

## Built-in Implementation

### Filesystem Quarantine

```rust
use scanbridge::quarantine::FilesystemQuarantine;

// Create quarantine storage
let quarantine = FilesystemQuarantine::new("/var/lib/scanbridge/quarantine")?;
```

Directory structure:
```
/var/lib/scanbridge/quarantine/
├── data/
│   ├── abc123-456.qdata    # Quarantined file (obfuscated)
│   └── def789-012.qdata
└── meta/
    ├── abc123-456.json     # Metadata
    └── def789-012.json
```

### Storage Features

- **Obfuscated Names**: Files renamed to prevent accidental execution
- **Integrity Verification**: BLAKE3 hash checked on store/retrieve
- **Metadata Tracking**: Full scan context preserved
- **Expiration Support**: Automatic cleanup of old records
- **Multi-tenant**: Filterable by tenant ID

## Integration with ScanManager

```rust
use scanbridge::quarantine::FilesystemQuarantine;

let quarantine = FilesystemQuarantine::new("/var/quarantine")?;

let manager = ScanManager::builder()
    .add_scanner(scanner)
    .with_quarantine(quarantine)
    .build()?;
```

When using `scan_with_policy()` and the policy returns `Quarantine`:
- The file is automatically stored
- Audit event is emitted
- QuarantineId is available in the result

## Manual Quarantine Operations

### Storing a 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);
```

### Retrieving a File

```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());
```

**Warning**: Retrieved files may be malicious. Handle with care:
- Don't execute retrieved files
- Scan before releasing
- Log all retrievals

### Listing Records

```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);
}
```

### Filtering Options

```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);
```

### Deleting 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);
```

## Expiration

Set expiration when quarantining:

```rust
use chrono::{Utc, Duration};

let record = QuarantineRecord::new(...)
    .with_expires_at(Utc::now() + Duration::days(90));
```

Periodic cleanup:

```rust
// Run periodically (e.g., daily cron job)
let deleted = quarantine.cleanup_expired().await?;
tracing::info!(deleted = deleted, "Quarantine cleanup complete");
```

## Custom Storage Backends

Implement `QuarantineStore` for custom backends:

```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<QuarantineId, QuarantineError> {
        // Upload to S3 with metadata
        todo!()
    }

    async fn retrieve(
        &self,
        id: &QuarantineId,
    ) -> Result<(Vec<u8>, 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<Vec<QuarantineRecord>, QuarantineError> {
        // Query DynamoDB/metadata store
        todo!()
    }
}
```

## Compliance Considerations

### HIPAA / Healthcare

- Encrypt quarantined files at rest
- Log all access to quarantine
- Maintain audit trail for 6+ years
- Ensure PHI in quarantined files is protected

### PCI-DSS / Financial

- Isolate quarantine storage from cardholder data
- Monitor quarantine access
- Include in vulnerability management program

### GDPR / Privacy

- Consider data retention limits
- Handle deletion requests that include quarantined files
- Document quarantine in privacy policy

### General Best Practices

1. **Encrypt at rest**: Use encrypted filesystem or object storage
2. **Access control**: Limit who can retrieve quarantined files
3. **Audit all operations**: Log store, retrieve, delete actions
4. **Retain appropriately**: Balance forensics needs vs storage costs
5. **Secure transfer**: Encrypt when moving quarantined files
6. **Test recovery**: Periodically verify files can be retrieved

## Monitoring

Track these metrics:

- `quarantine_storage_used_bytes`: Total storage consumed
- `quarantine_files_total`: Number of quarantined files
- `quarantine_files_by_tenant`: Per-tenant breakdown
- `quarantine_retrievals_total`: How often files are retrieved
- `quarantine_age_days`: Age distribution of quarantined files

Example with Prometheus:

```rust
// After quarantine operations
metrics.quarantine_files_total.inc();
metrics.quarantine_storage_bytes.add(record.file_size as f64);
```

## Recovery Workflow

When a file is determined to be a false positive:

```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"
    );
}
```