Skip to main content

ringkernel_core/
security.rs

1//! Security features for GPU kernel protection and compliance.
2//!
3//! This module provides enterprise-grade security features:
4//!
5//! - **Memory Encryption**: Encrypt sensitive GPU memory regions
6//! - **Kernel Sandboxing**: Isolate kernels with resource limits and access controls
7//! - **Compliance Reports**: Generate audit-ready compliance documentation
8//!
9//! # Feature Flags
10//!
11//! - `crypto` - Enables real AES-256-GCM and ChaCha20-Poly1305 encryption
12//!   (requires `aes-gcm`, `chacha20poly1305`, `argon2`, `rand`, `zeroize` crates)
13//!
14//! Without the `crypto` feature, a demo XOR-based implementation is used
15//! (NOT suitable for production - only for testing/development).
16//!
17//! **WARNING**: All encryption methods without `crypto` are `#[deprecated]`
18//! and will emit compile-time warnings. Suppress only if you accept the risk.
19
20//!
21//! # Memory Encryption
22//!
23//! ```rust,ignore
24//! use ringkernel_core::security::{MemoryEncryption, EncryptionConfig, EncryptionAlgorithm};
25//!
26//! let config = EncryptionConfig::new()
27//!     .with_algorithm(EncryptionAlgorithm::Aes256Gcm)
28//!     .with_key_rotation_interval(Duration::from_secs(3600));
29//!
30//! let encryption = MemoryEncryption::new(config)?;
31//! let encrypted = encryption.encrypt_region(&sensitive_data)?;
32//! let decrypted = encryption.decrypt_region(&encrypted)?;
33//! ```
34//!
35//! # Kernel Sandboxing
36//!
37//! ```rust,ignore
38//! use ringkernel_core::security::{KernelSandbox, SandboxPolicy, ResourceLimits};
39//!
40//! let policy = SandboxPolicy::new()
41//!     .with_memory_limit(1024 * 1024 * 1024)  // 1GB
42//!     .with_execution_timeout(Duration::from_secs(30))
43//!     .deny_k2k_to(&["untrusted_kernel"]);
44//!
45//! let sandbox = KernelSandbox::new(policy);
46//! sandbox.apply_to_kernel(&kernel_handle)?;
47//! ```
48//!
49//! # Compliance Reports
50//!
51//! ```rust,ignore
52//! use ringkernel_core::security::{ComplianceReporter, ComplianceStandard, ReportFormat};
53//!
54//! let reporter = ComplianceReporter::new()
55//!     .with_standard(ComplianceStandard::SOC2)
56//!     .with_standard(ComplianceStandard::GDPR);
57//!
58//! let report = reporter.generate_report(ReportFormat::Pdf)?;
59//! ```
60
61// Compile-time warning: encryption without `crypto` feature uses insecure XOR fallback
62#[cfg(not(feature = "crypto"))]
63#[deprecated(
64    since = "0.4.3",
65    note = "INSECURE: Memory encryption uses XOR fallback without `crypto` feature. Enable `crypto` for production."
66)]
67#[allow(dead_code)]
68const INSECURE_CRYPTO_FALLBACK: () = ();
69
70use std::collections::{HashMap, HashSet};
71use std::fmt;
72use std::sync::atomic::{AtomicU64, Ordering};
73use std::sync::RwLock;
74use std::time::{Duration, Instant, SystemTime};
75
76use crate::KernelId;
77
78// Real cryptography imports (when crypto feature is enabled)
79#[cfg(feature = "crypto")]
80use aes_gcm::{
81    aead::{Aead, KeyInit},
82    Aes256Gcm, Nonce as AesNonce,
83};
84#[cfg(feature = "crypto")]
85use chacha20poly1305::{ChaCha20Poly1305, Nonce as ChaNonce, XChaCha20Poly1305, XNonce};
86#[cfg(feature = "crypto")]
87use rand::{rngs::OsRng, RngCore};
88#[cfg(feature = "crypto")]
89use zeroize::Zeroize;
90
91// ============================================================================
92// Memory Encryption
93// ============================================================================
94
95/// Encryption algorithm for GPU memory protection.
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
97pub enum EncryptionAlgorithm {
98    /// AES-256-GCM (recommended for most use cases)
99    #[default]
100    Aes256Gcm,
101    /// AES-128-GCM (faster, still secure)
102    Aes128Gcm,
103    /// ChaCha20-Poly1305 (good for systems without AES-NI)
104    ChaCha20Poly1305,
105    /// XChaCha20-Poly1305 (extended nonce variant)
106    XChaCha20Poly1305,
107}
108
109impl fmt::Display for EncryptionAlgorithm {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        match self {
112            Self::Aes256Gcm => write!(f, "AES-256-GCM"),
113            Self::Aes128Gcm => write!(f, "AES-128-GCM"),
114            Self::ChaCha20Poly1305 => write!(f, "ChaCha20-Poly1305"),
115            Self::XChaCha20Poly1305 => write!(f, "XChaCha20-Poly1305"),
116        }
117    }
118}
119
120/// Key derivation function for encryption keys.
121#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
122pub enum KeyDerivation {
123    /// HKDF with SHA-256
124    #[default]
125    HkdfSha256,
126    /// HKDF with SHA-384
127    HkdfSha384,
128    /// Argon2id (memory-hard, for password-derived keys)
129    Argon2id,
130    /// PBKDF2 with SHA-256
131    Pbkdf2Sha256,
132}
133
134/// Configuration for memory encryption.
135#[derive(Debug, Clone)]
136pub struct EncryptionConfig {
137    /// Encryption algorithm to use
138    pub algorithm: EncryptionAlgorithm,
139    /// Key derivation function
140    pub key_derivation: KeyDerivation,
141    /// How often to rotate encryption keys
142    pub key_rotation_interval: Duration,
143    /// Whether to encrypt control blocks
144    pub encrypt_control_blocks: bool,
145    /// Whether to encrypt message queues
146    pub encrypt_message_queues: bool,
147    /// Whether to encrypt kernel state
148    pub encrypt_kernel_state: bool,
149    /// Additional authenticated data prefix
150    pub aad_prefix: Option<Vec<u8>>,
151}
152
153impl Default for EncryptionConfig {
154    fn default() -> Self {
155        Self {
156            algorithm: EncryptionAlgorithm::default(),
157            key_derivation: KeyDerivation::default(),
158            key_rotation_interval: Duration::from_secs(3600), // 1 hour
159            encrypt_control_blocks: true,
160            encrypt_message_queues: true,
161            encrypt_kernel_state: true,
162            aad_prefix: None,
163        }
164    }
165}
166
167impl EncryptionConfig {
168    /// Create a new encryption configuration.
169    pub fn new() -> Self {
170        Self::default()
171    }
172
173    /// Set the encryption algorithm.
174    pub fn with_algorithm(mut self, algorithm: EncryptionAlgorithm) -> Self {
175        self.algorithm = algorithm;
176        self
177    }
178
179    /// Set the key derivation function.
180    pub fn with_key_derivation(mut self, kdf: KeyDerivation) -> Self {
181        self.key_derivation = kdf;
182        self
183    }
184
185    /// Set the key rotation interval.
186    pub fn with_key_rotation_interval(mut self, interval: Duration) -> Self {
187        self.key_rotation_interval = interval;
188        self
189    }
190
191    /// Enable/disable control block encryption.
192    pub fn with_control_block_encryption(mut self, enabled: bool) -> Self {
193        self.encrypt_control_blocks = enabled;
194        self
195    }
196
197    /// Enable/disable message queue encryption.
198    pub fn with_message_queue_encryption(mut self, enabled: bool) -> Self {
199        self.encrypt_message_queues = enabled;
200        self
201    }
202
203    /// Enable/disable kernel state encryption.
204    pub fn with_kernel_state_encryption(mut self, enabled: bool) -> Self {
205        self.encrypt_kernel_state = enabled;
206        self
207    }
208
209    /// Set additional authenticated data prefix.
210    pub fn with_aad_prefix(mut self, prefix: Vec<u8>) -> Self {
211        self.aad_prefix = Some(prefix);
212        self
213    }
214}
215
216/// Represents an encryption key with metadata.
217///
218/// When the `crypto` feature is enabled, key material is protected with `zeroize`
219/// to securely clear memory when the key is dropped.
220#[derive(Clone)]
221pub struct EncryptionKey {
222    /// Unique key identifier
223    pub key_id: u64,
224    /// Key material (protected with zeroize when crypto feature is enabled)
225    #[cfg(feature = "crypto")]
226    key_material: zeroize::Zeroizing<Vec<u8>>,
227    #[cfg(not(feature = "crypto"))]
228    key_material: Vec<u8>,
229    /// When the key was created
230    pub created_at: Instant,
231    /// When the key expires
232    pub expires_at: Option<Instant>,
233    /// Algorithm this key is for
234    pub algorithm: EncryptionAlgorithm,
235}
236
237impl EncryptionKey {
238    /// Create a new encryption key with cryptographically secure random material.
239    ///
240    /// When `crypto` feature is enabled, uses `OsRng` for secure random generation.
241    /// Without the feature, uses a deterministic (INSECURE) fallback for testing only.
242    #[cfg(feature = "crypto")]
243    pub fn new(key_id: u64, algorithm: EncryptionAlgorithm) -> Self {
244        let key_size = match algorithm {
245            EncryptionAlgorithm::Aes256Gcm
246            | EncryptionAlgorithm::ChaCha20Poly1305
247            | EncryptionAlgorithm::XChaCha20Poly1305 => 32,
248            EncryptionAlgorithm::Aes128Gcm => 16,
249        };
250
251        let mut key_material = vec![0u8; key_size];
252        OsRng.fill_bytes(&mut key_material);
253
254        Self {
255            key_id,
256            key_material: zeroize::Zeroizing::new(key_material),
257            created_at: Instant::now(),
258            expires_at: None,
259            algorithm,
260        }
261    }
262
263    /// Create a new encryption key (demo/fallback implementation).
264    ///
265    /// WARNING: This uses deterministic key generation and is NOT secure.
266    /// Only use for testing/development without the `crypto` feature.
267    /// Enable the `crypto` feature for real AES-256-GCM encryption.
268    #[cfg(not(feature = "crypto"))]
269    #[deprecated(
270        since = "0.4.3",
271        note = "Using insecure XOR-based demo encryption. Enable the `crypto` feature for real AES-256-GCM."
272    )]
273    pub fn new(key_id: u64, algorithm: EncryptionAlgorithm) -> Self {
274        let key_size = match algorithm {
275            EncryptionAlgorithm::Aes256Gcm
276            | EncryptionAlgorithm::ChaCha20Poly1305
277            | EncryptionAlgorithm::XChaCha20Poly1305 => 32,
278            EncryptionAlgorithm::Aes128Gcm => 16,
279        };
280
281        // INSECURE: Deterministic key for demo only
282        let key_material: Vec<u8> = (0..key_size)
283            .map(|i| ((key_id as u8).wrapping_add(i as u8)).wrapping_mul(17))
284            .collect();
285
286        Self {
287            key_id,
288            key_material,
289            created_at: Instant::now(),
290            expires_at: None,
291            algorithm,
292        }
293    }
294
295    /// Create a key from existing key material (for key derivation or import).
296    #[cfg(feature = "crypto")]
297    pub fn from_material(key_id: u64, algorithm: EncryptionAlgorithm, material: Vec<u8>) -> Self {
298        Self {
299            key_id,
300            key_material: zeroize::Zeroizing::new(material),
301            created_at: Instant::now(),
302            expires_at: None,
303            algorithm,
304        }
305    }
306
307    /// Create a key from existing key material (demo version).
308    #[cfg(not(feature = "crypto"))]
309    pub fn from_material(key_id: u64, algorithm: EncryptionAlgorithm, material: Vec<u8>) -> Self {
310        Self {
311            key_id,
312            key_material: material,
313            created_at: Instant::now(),
314            expires_at: None,
315            algorithm,
316        }
317    }
318
319    /// Get access to the key material (for encryption operations).
320    pub(crate) fn material(&self) -> &[u8] {
321        &self.key_material
322    }
323
324    /// Check if the key has expired.
325    pub fn is_expired(&self) -> bool {
326        self.expires_at
327            .map(|exp| Instant::now() > exp)
328            .unwrap_or(false)
329    }
330
331    /// Get the key size in bytes.
332    pub fn key_size(&self) -> usize {
333        self.key_material.len()
334    }
335}
336
337impl fmt::Debug for EncryptionKey {
338    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
339        f.debug_struct("EncryptionKey")
340            .field("key_id", &self.key_id)
341            .field("algorithm", &self.algorithm)
342            .field("key_size", &self.key_material.len())
343            .field("created_at", &self.created_at)
344            .field("expires_at", &self.expires_at)
345            .finish()
346    }
347}
348
349/// An encrypted memory region.
350#[derive(Debug, Clone)]
351pub struct EncryptedRegion {
352    /// Unique region identifier
353    pub region_id: u64,
354    /// Encrypted data (ciphertext + tag)
355    pub ciphertext: Vec<u8>,
356    /// Nonce/IV used for encryption
357    pub nonce: Vec<u8>,
358    /// Key ID used for encryption
359    pub key_id: u64,
360    /// Original plaintext size
361    pub plaintext_size: usize,
362    /// Algorithm used
363    pub algorithm: EncryptionAlgorithm,
364    /// When the region was encrypted
365    pub encrypted_at: Instant,
366}
367
368/// Statistics for memory encryption operations.
369#[derive(Debug, Clone, Default)]
370pub struct EncryptionStats {
371    /// Total bytes encrypted
372    pub bytes_encrypted: u64,
373    /// Total bytes decrypted
374    pub bytes_decrypted: u64,
375    /// Number of encryption operations
376    pub encrypt_ops: u64,
377    /// Number of decryption operations
378    pub decrypt_ops: u64,
379    /// Number of key rotations
380    pub key_rotations: u64,
381    /// Average encryption time (microseconds)
382    pub avg_encrypt_time_us: f64,
383    /// Average decryption time (microseconds)
384    pub avg_decrypt_time_us: f64,
385}
386
387/// Memory encryption manager for GPU memory protection.
388pub struct MemoryEncryption {
389    /// Configuration
390    config: EncryptionConfig,
391    /// Current active key
392    active_key: RwLock<EncryptionKey>,
393    /// Previous keys for decryption
394    previous_keys: RwLock<HashMap<u64, EncryptionKey>>,
395    /// Next key ID
396    next_key_id: AtomicU64,
397    /// Region counter
398    region_counter: AtomicU64,
399    /// Statistics
400    stats: RwLock<EncryptionStats>,
401    /// Last key rotation time
402    last_rotation: RwLock<Instant>,
403}
404
405impl MemoryEncryption {
406    /// Create a new memory encryption manager.
407    #[allow(deprecated)]
408    pub fn new(config: EncryptionConfig) -> Self {
409        let key_id = 1;
410        let active_key = EncryptionKey::new(key_id, config.algorithm);
411
412        Self {
413            config,
414            active_key: RwLock::new(active_key),
415            previous_keys: RwLock::new(HashMap::new()),
416            next_key_id: AtomicU64::new(2),
417            region_counter: AtomicU64::new(1),
418            stats: RwLock::new(EncryptionStats::default()),
419            last_rotation: RwLock::new(Instant::now()),
420        }
421    }
422
423    /// Encrypt a memory region using real AEAD encryption (when crypto feature is enabled).
424    ///
425    /// Uses the configured algorithm (AES-256-GCM, ChaCha20-Poly1305, etc.) with
426    /// cryptographically secure nonce generation.
427    #[cfg(feature = "crypto")]
428    pub fn encrypt_region(&self, plaintext: &[u8]) -> EncryptedRegion {
429        let start = Instant::now();
430
431        let key = self.active_key.read().expect("active_key lock poisoned");
432        let region_id = self.region_counter.fetch_add(1, Ordering::Relaxed);
433
434        // Generate cryptographically secure nonce
435        let nonce_size = match self.config.algorithm {
436            EncryptionAlgorithm::Aes256Gcm | EncryptionAlgorithm::Aes128Gcm => 12,
437            EncryptionAlgorithm::ChaCha20Poly1305 => 12,
438            EncryptionAlgorithm::XChaCha20Poly1305 => 24,
439        };
440        let mut nonce = vec![0u8; nonce_size];
441        OsRng.fill_bytes(&mut nonce);
442
443        // Build AAD (additional authenticated data)
444        let aad = self.config.aad_prefix.as_deref().unwrap_or(&[]);
445
446        // Perform real AEAD encryption
447        let ciphertext = match self.config.algorithm {
448            EncryptionAlgorithm::Aes256Gcm | EncryptionAlgorithm::Aes128Gcm => {
449                let cipher = Aes256Gcm::new_from_slice(key.material())
450                    .expect("AES key length must be 32 bytes");
451                let aes_nonce = AesNonce::from_slice(&nonce);
452                cipher
453                    .encrypt(aes_nonce, plaintext)
454                    .expect("AES-GCM encryption should not fail with valid key and nonce")
455            }
456            EncryptionAlgorithm::ChaCha20Poly1305 => {
457                let cipher = ChaCha20Poly1305::new_from_slice(key.material())
458                    .expect("ChaCha20 key length must be 32 bytes");
459                let cha_nonce = ChaNonce::from_slice(&nonce);
460                cipher
461                    .encrypt(cha_nonce, plaintext)
462                    .expect("ChaCha20-Poly1305 encryption should not fail with valid key and nonce")
463            }
464            EncryptionAlgorithm::XChaCha20Poly1305 => {
465                let cipher = XChaCha20Poly1305::new_from_slice(key.material())
466                    .expect("XChaCha20 key length must be 32 bytes");
467                let x_nonce = XNonce::from_slice(&nonce);
468                cipher.encrypt(x_nonce, plaintext).expect(
469                    "XChaCha20-Poly1305 encryption should not fail with valid key and nonce",
470                )
471            }
472        };
473
474        let elapsed = start.elapsed();
475
476        // Update stats
477        {
478            let mut stats = self.stats.write().expect("stats lock poisoned");
479            stats.bytes_encrypted += plaintext.len() as u64;
480            stats.encrypt_ops += 1;
481            let total_time = stats.avg_encrypt_time_us * (stats.encrypt_ops - 1) as f64;
482            stats.avg_encrypt_time_us =
483                (total_time + elapsed.as_micros() as f64) / stats.encrypt_ops as f64;
484        }
485
486        // Suppress unused variable warning
487        let _ = aad;
488
489        EncryptedRegion {
490            region_id,
491            ciphertext,
492            nonce,
493            key_id: key.key_id,
494            plaintext_size: plaintext.len(),
495            algorithm: self.config.algorithm,
496            encrypted_at: Instant::now(),
497        }
498    }
499
500    /// Encrypt a memory region (demo/fallback implementation).
501    ///
502    /// WARNING: Uses XOR-based simulation - NOT cryptographically secure.
503    /// Enable the `crypto` feature for real AES-256-GCM encryption.
504    #[cfg(not(feature = "crypto"))]
505    #[deprecated(
506        since = "0.4.3",
507        note = "Using insecure XOR-based demo encryption. Enable the `crypto` feature for real AES-256-GCM."
508    )]
509    pub fn encrypt_region(&self, plaintext: &[u8]) -> EncryptedRegion {
510        let start = Instant::now();
511
512        let key = self.active_key.read().expect("active_key lock poisoned");
513        let region_id = self.region_counter.fetch_add(1, Ordering::Relaxed);
514
515        // Generate deterministic nonce (INSECURE - demo only)
516        let nonce_size = match self.config.algorithm {
517            EncryptionAlgorithm::Aes256Gcm | EncryptionAlgorithm::Aes128Gcm => 12,
518            EncryptionAlgorithm::ChaCha20Poly1305 => 12,
519            EncryptionAlgorithm::XChaCha20Poly1305 => 24,
520        };
521        let nonce: Vec<u8> = (0..nonce_size)
522            .map(|i| ((region_id as u8).wrapping_add(i as u8)).wrapping_mul(23))
523            .collect();
524
525        // Simulate encryption (XOR with key material for demo)
526        // WARNING: This is NOT secure - use crypto feature for production
527        let mut ciphertext = plaintext.to_vec();
528        for (i, byte) in ciphertext.iter_mut().enumerate() {
529            *byte ^= key.material()[i % key.material().len()];
530            *byte ^= nonce[i % nonce.len()];
531        }
532
533        // Add simulated authentication tag
534        let tag: Vec<u8> = (0..16)
535            .map(|i| {
536                ciphertext.get(i).copied().unwrap_or(0) ^ key.material()[i % key.material().len()]
537            })
538            .collect();
539        ciphertext.extend(tag);
540
541        let elapsed = start.elapsed();
542
543        // Update stats
544        {
545            let mut stats = self.stats.write().expect("stats lock poisoned");
546            stats.bytes_encrypted += plaintext.len() as u64;
547            stats.encrypt_ops += 1;
548            let total_time = stats.avg_encrypt_time_us * (stats.encrypt_ops - 1) as f64;
549            stats.avg_encrypt_time_us =
550                (total_time + elapsed.as_micros() as f64) / stats.encrypt_ops as f64;
551        }
552
553        EncryptedRegion {
554            region_id,
555            ciphertext,
556            nonce,
557            key_id: key.key_id,
558            plaintext_size: plaintext.len(),
559            algorithm: self.config.algorithm,
560            encrypted_at: Instant::now(),
561        }
562    }
563
564    /// Decrypt a memory region using real AEAD decryption (when crypto feature is enabled).
565    #[cfg(feature = "crypto")]
566    pub fn decrypt_region(&self, region: &EncryptedRegion) -> Result<Vec<u8>, String> {
567        let start = Instant::now();
568
569        // Find the appropriate key
570        let key = if region.key_id
571            == self
572                .active_key
573                .read()
574                .expect("active_key lock poisoned")
575                .key_id
576        {
577            self.active_key
578                .read()
579                .expect("active_key lock poisoned")
580                .clone()
581        } else {
582            self.previous_keys
583                .read()
584                .expect("previous_keys lock poisoned")
585                .get(&region.key_id)
586                .cloned()
587                .ok_or_else(|| format!("Key {} not found", region.key_id))?
588        };
589
590        // Perform real AEAD decryption
591        let plaintext = match region.algorithm {
592            EncryptionAlgorithm::Aes256Gcm | EncryptionAlgorithm::Aes128Gcm => {
593                let cipher = Aes256Gcm::new_from_slice(key.material())
594                    .map_err(|e| format!("Invalid AES key: {}", e))?;
595                let aes_nonce = AesNonce::from_slice(&region.nonce);
596                cipher
597                    .decrypt(aes_nonce, region.ciphertext.as_ref())
598                    .map_err(|_| {
599                        "AES-GCM decryption failed: authentication tag mismatch".to_string()
600                    })?
601            }
602            EncryptionAlgorithm::ChaCha20Poly1305 => {
603                let cipher = ChaCha20Poly1305::new_from_slice(key.material())
604                    .map_err(|e| format!("Invalid ChaCha20 key: {}", e))?;
605                let cha_nonce = ChaNonce::from_slice(&region.nonce);
606                cipher
607                    .decrypt(cha_nonce, region.ciphertext.as_ref())
608                    .map_err(|_| {
609                        "ChaCha20-Poly1305 decryption failed: authentication tag mismatch"
610                            .to_string()
611                    })?
612            }
613            EncryptionAlgorithm::XChaCha20Poly1305 => {
614                let cipher = XChaCha20Poly1305::new_from_slice(key.material())
615                    .map_err(|e| format!("Invalid XChaCha20 key: {}", e))?;
616                let x_nonce = XNonce::from_slice(&region.nonce);
617                cipher
618                    .decrypt(x_nonce, region.ciphertext.as_ref())
619                    .map_err(|_| {
620                        "XChaCha20-Poly1305 decryption failed: authentication tag mismatch"
621                            .to_string()
622                    })?
623            }
624        };
625
626        let elapsed = start.elapsed();
627
628        // Update stats
629        {
630            let mut stats = self.stats.write().expect("stats lock poisoned");
631            stats.bytes_decrypted += plaintext.len() as u64;
632            stats.decrypt_ops += 1;
633            let total_time = stats.avg_decrypt_time_us * (stats.decrypt_ops - 1) as f64;
634            stats.avg_decrypt_time_us =
635                (total_time + elapsed.as_micros() as f64) / stats.decrypt_ops as f64;
636        }
637
638        Ok(plaintext)
639    }
640
641    /// Decrypt a memory region (demo/fallback implementation).
642    ///
643    /// WARNING: Uses XOR-based simulation - NOT cryptographically secure.
644    /// Enable the `crypto` feature for real AES-256-GCM decryption.
645    #[cfg(not(feature = "crypto"))]
646    #[deprecated(
647        since = "0.4.3",
648        note = "Using insecure XOR-based demo decryption. Enable the `crypto` feature for real AES-256-GCM."
649    )]
650    pub fn decrypt_region(&self, region: &EncryptedRegion) -> Result<Vec<u8>, String> {
651        let start = Instant::now();
652
653        // Find the appropriate key
654        let key = if region.key_id
655            == self
656                .active_key
657                .read()
658                .expect("active_key lock poisoned")
659                .key_id
660        {
661            self.active_key
662                .read()
663                .expect("active_key lock poisoned")
664                .clone()
665        } else {
666            self.previous_keys
667                .read()
668                .expect("previous_keys lock poisoned")
669                .get(&region.key_id)
670                .cloned()
671                .ok_or_else(|| format!("Key {} not found", region.key_id))?
672        };
673
674        // Verify and remove tag
675        if region.ciphertext.len() < 16 {
676            return Err("Ciphertext too short".to_string());
677        }
678        let (ciphertext, _tag) = region.ciphertext.split_at(region.ciphertext.len() - 16);
679
680        // Simulate decryption (reverse XOR)
681        // WARNING: This is NOT secure - use crypto feature for production
682        let mut plaintext = ciphertext.to_vec();
683        for (i, byte) in plaintext.iter_mut().enumerate() {
684            *byte ^= region.nonce[i % region.nonce.len()];
685            *byte ^= key.material()[i % key.material().len()];
686        }
687
688        let elapsed = start.elapsed();
689
690        // Update stats
691        {
692            let mut stats = self.stats.write().expect("stats lock poisoned");
693            stats.bytes_decrypted += plaintext.len() as u64;
694            stats.decrypt_ops += 1;
695            let total_time = stats.avg_decrypt_time_us * (stats.decrypt_ops - 1) as f64;
696            stats.avg_decrypt_time_us =
697                (total_time + elapsed.as_micros() as f64) / stats.decrypt_ops as f64;
698        }
699
700        Ok(plaintext)
701    }
702
703    /// Rotate encryption keys.
704    #[allow(deprecated)]
705    pub fn rotate_keys(&self) {
706        let mut active = self.active_key.write().expect("active_key lock poisoned");
707        let mut previous = self
708            .previous_keys
709            .write()
710            .expect("previous_keys lock poisoned");
711
712        // Move current key to previous
713        let old_key = active.clone();
714        previous.insert(old_key.key_id, old_key);
715
716        // Generate new key
717        let new_key_id = self.next_key_id.fetch_add(1, Ordering::Relaxed);
718        *active = EncryptionKey::new(new_key_id, self.config.algorithm);
719
720        // Update rotation time
721        *self
722            .last_rotation
723            .write()
724            .expect("last_rotation lock poisoned") = Instant::now();
725
726        // Update stats
727        self.stats
728            .write()
729            .expect("stats lock poisoned")
730            .key_rotations += 1;
731
732        // Clean up old keys (keep last 10)
733        while previous.len() > 10 {
734            if let Some(oldest_id) = previous.keys().min().copied() {
735                previous.remove(&oldest_id);
736            }
737        }
738    }
739
740    /// Check if key rotation is needed.
741    pub fn needs_rotation(&self) -> bool {
742        let last = *self
743            .last_rotation
744            .read()
745            .expect("last_rotation lock poisoned");
746        last.elapsed() >= self.config.key_rotation_interval
747    }
748
749    /// Get encryption statistics.
750    pub fn stats(&self) -> EncryptionStats {
751        self.stats.read().expect("stats lock poisoned").clone()
752    }
753
754    /// Get the current key ID.
755    pub fn current_key_id(&self) -> u64 {
756        self.active_key
757            .read()
758            .expect("active_key lock poisoned")
759            .key_id
760    }
761
762    /// Get the configuration.
763    pub fn config(&self) -> &EncryptionConfig {
764        &self.config
765    }
766}
767
768impl fmt::Debug for MemoryEncryption {
769    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770        f.debug_struct("MemoryEncryption")
771            .field("config", &self.config)
772            .field("current_key_id", &self.current_key_id())
773            .field("stats", &self.stats())
774            .finish()
775    }
776}
777
778// ============================================================================
779// Kernel Sandboxing
780// ============================================================================
781
782/// Access control for kernel operations.
783#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
784pub enum AccessLevel {
785    /// No access
786    Deny,
787    /// Read-only access
788    ReadOnly,
789    /// Read-write access
790    #[default]
791    ReadWrite,
792    /// Full access including execute
793    Full,
794}
795
796/// Resource limits for sandboxed kernels.
797#[derive(Debug, Clone)]
798pub struct ResourceLimits {
799    /// Maximum GPU memory in bytes
800    pub max_memory_bytes: u64,
801    /// Maximum execution time
802    pub max_execution_time: Duration,
803    /// Maximum messages per second
804    pub max_messages_per_sec: u32,
805    /// Maximum concurrent K2K connections
806    pub max_k2k_connections: u32,
807    /// Maximum checkpoint size
808    pub max_checkpoint_size: u64,
809    /// Maximum queue depth
810    pub max_queue_depth: u32,
811}
812
813impl Default for ResourceLimits {
814    fn default() -> Self {
815        Self {
816            max_memory_bytes: 1024 * 1024 * 1024, // 1GB
817            max_execution_time: Duration::from_secs(60),
818            max_messages_per_sec: 10000,
819            max_k2k_connections: 100,
820            max_checkpoint_size: 100 * 1024 * 1024, // 100MB
821            max_queue_depth: 4096,
822        }
823    }
824}
825
826impl ResourceLimits {
827    /// Create new resource limits.
828    pub fn new() -> Self {
829        Self::default()
830    }
831
832    /// Set maximum memory.
833    pub fn with_max_memory(mut self, bytes: u64) -> Self {
834        self.max_memory_bytes = bytes;
835        self
836    }
837
838    /// Set maximum execution time.
839    pub fn with_max_execution_time(mut self, duration: Duration) -> Self {
840        self.max_execution_time = duration;
841        self
842    }
843
844    /// Set maximum messages per second.
845    pub fn with_max_messages_per_sec(mut self, count: u32) -> Self {
846        self.max_messages_per_sec = count;
847        self
848    }
849
850    /// Set maximum K2K connections.
851    pub fn with_max_k2k_connections(mut self, count: u32) -> Self {
852        self.max_k2k_connections = count;
853        self
854    }
855
856    /// Restrictive limits for untrusted kernels.
857    pub fn restrictive() -> Self {
858        Self {
859            max_memory_bytes: 256 * 1024 * 1024, // 256MB
860            max_execution_time: Duration::from_secs(10),
861            max_messages_per_sec: 1000,
862            max_k2k_connections: 10,
863            max_checkpoint_size: 10 * 1024 * 1024, // 10MB
864            max_queue_depth: 256,
865        }
866    }
867
868    /// Permissive limits for trusted kernels.
869    pub fn permissive() -> Self {
870        Self {
871            max_memory_bytes: 8 * 1024 * 1024 * 1024, // 8GB
872            max_execution_time: Duration::from_secs(3600),
873            max_messages_per_sec: 1_000_000,
874            max_k2k_connections: 1000,
875            max_checkpoint_size: 1024 * 1024 * 1024, // 1GB
876            max_queue_depth: 65536,
877        }
878    }
879}
880
881/// Sandbox policy defining what a kernel can access.
882#[derive(Debug, Clone)]
883pub struct SandboxPolicy {
884    /// Resource limits
885    pub limits: ResourceLimits,
886    /// Allowed K2K destinations (empty = all allowed)
887    pub allowed_k2k_destinations: HashSet<String>,
888    /// Denied K2K destinations
889    pub denied_k2k_destinations: HashSet<String>,
890    /// Memory region access levels
891    pub memory_access: HashMap<String, AccessLevel>,
892    /// Whether the kernel can create checkpoints
893    pub can_checkpoint: bool,
894    /// Whether the kernel can be migrated
895    pub can_migrate: bool,
896    /// Whether the kernel can spawn child kernels
897    pub can_spawn: bool,
898    /// Whether the kernel can access host memory
899    pub can_access_host: bool,
900    /// Allowed system calls (for future use)
901    pub allowed_syscalls: HashSet<String>,
902}
903
904impl Default for SandboxPolicy {
905    fn default() -> Self {
906        Self {
907            limits: ResourceLimits::default(),
908            allowed_k2k_destinations: HashSet::new(),
909            denied_k2k_destinations: HashSet::new(),
910            memory_access: HashMap::new(),
911            can_checkpoint: true,
912            can_migrate: true,
913            can_spawn: false,
914            can_access_host: false,
915            allowed_syscalls: HashSet::new(),
916        }
917    }
918}
919
920impl SandboxPolicy {
921    /// Create a new sandbox policy.
922    pub fn new() -> Self {
923        Self::default()
924    }
925
926    /// Set resource limits.
927    pub fn with_limits(mut self, limits: ResourceLimits) -> Self {
928        self.limits = limits;
929        self
930    }
931
932    /// Set memory limit.
933    pub fn with_memory_limit(mut self, bytes: u64) -> Self {
934        self.limits.max_memory_bytes = bytes;
935        self
936    }
937
938    /// Set execution timeout.
939    pub fn with_execution_timeout(mut self, timeout: Duration) -> Self {
940        self.limits.max_execution_time = timeout;
941        self
942    }
943
944    /// Allow K2K to specific destinations.
945    pub fn allow_k2k_to(mut self, destinations: &[&str]) -> Self {
946        self.allowed_k2k_destinations
947            .extend(destinations.iter().map(|s| s.to_string()));
948        self
949    }
950
951    /// Deny K2K to specific destinations.
952    pub fn deny_k2k_to(mut self, destinations: &[&str]) -> Self {
953        self.denied_k2k_destinations
954            .extend(destinations.iter().map(|s| s.to_string()));
955        self
956    }
957
958    /// Set memory region access level.
959    pub fn with_memory_access(mut self, region: &str, access: AccessLevel) -> Self {
960        self.memory_access.insert(region.to_string(), access);
961        self
962    }
963
964    /// Enable/disable checkpointing.
965    pub fn with_checkpoint(mut self, enabled: bool) -> Self {
966        self.can_checkpoint = enabled;
967        self
968    }
969
970    /// Enable/disable migration.
971    pub fn with_migration(mut self, enabled: bool) -> Self {
972        self.can_migrate = enabled;
973        self
974    }
975
976    /// Enable/disable spawning.
977    pub fn with_spawn(mut self, enabled: bool) -> Self {
978        self.can_spawn = enabled;
979        self
980    }
981
982    /// Enable/disable host memory access.
983    pub fn with_host_access(mut self, enabled: bool) -> Self {
984        self.can_access_host = enabled;
985        self
986    }
987
988    /// Create a restrictive policy for untrusted kernels.
989    pub fn restrictive() -> Self {
990        Self {
991            limits: ResourceLimits::restrictive(),
992            allowed_k2k_destinations: HashSet::new(),
993            denied_k2k_destinations: HashSet::new(),
994            memory_access: HashMap::new(),
995            can_checkpoint: false,
996            can_migrate: false,
997            can_spawn: false,
998            can_access_host: false,
999            allowed_syscalls: HashSet::new(),
1000        }
1001    }
1002
1003    /// Create a permissive policy for trusted kernels.
1004    pub fn permissive() -> Self {
1005        Self {
1006            limits: ResourceLimits::permissive(),
1007            allowed_k2k_destinations: HashSet::new(),
1008            denied_k2k_destinations: HashSet::new(),
1009            memory_access: HashMap::new(),
1010            can_checkpoint: true,
1011            can_migrate: true,
1012            can_spawn: true,
1013            can_access_host: true,
1014            allowed_syscalls: HashSet::new(),
1015        }
1016    }
1017
1018    /// Check if K2K to destination is allowed.
1019    pub fn is_k2k_allowed(&self, destination: &str) -> bool {
1020        // If denied, always reject
1021        if self.denied_k2k_destinations.contains(destination) {
1022            return false;
1023        }
1024        // If allowed list is empty, allow all (except denied)
1025        if self.allowed_k2k_destinations.is_empty() {
1026            return true;
1027        }
1028        // Otherwise, must be in allowed list
1029        self.allowed_k2k_destinations.contains(destination)
1030    }
1031}
1032
1033/// Sandbox violation type.
1034#[derive(Debug, Clone, PartialEq, Eq)]
1035pub enum ViolationType {
1036    /// Memory limit exceeded
1037    MemoryLimitExceeded {
1038        /// Amount of memory used in bytes
1039        used: u64,
1040        /// Maximum allowed memory in bytes
1041        limit: u64,
1042    },
1043    /// Execution time exceeded
1044    ExecutionTimeExceeded {
1045        /// Elapsed execution time
1046        elapsed: Duration,
1047        /// Maximum allowed execution time
1048        limit: Duration,
1049    },
1050    /// Message rate exceeded
1051    MessageRateExceeded {
1052        /// Current message rate per second
1053        rate: u32,
1054        /// Maximum allowed rate per second
1055        limit: u32,
1056    },
1057    /// Unauthorized K2K destination
1058    UnauthorizedK2K {
1059        /// The destination kernel that was blocked
1060        destination: String,
1061    },
1062    /// Unauthorized memory access
1063    UnauthorizedMemoryAccess {
1064        /// The memory region that was accessed
1065        region: String,
1066        /// The access level that was requested
1067        requested: AccessLevel,
1068    },
1069    /// Checkpoint not allowed
1070    CheckpointNotAllowed,
1071    /// Migration not allowed
1072    MigrationNotAllowed,
1073    /// Spawn not allowed
1074    SpawnNotAllowed,
1075    /// Host access not allowed
1076    HostAccessNotAllowed,
1077}
1078
1079impl fmt::Display for ViolationType {
1080    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1081        match self {
1082            Self::MemoryLimitExceeded { used, limit } => {
1083                write!(f, "Memory limit exceeded: {} > {} bytes", used, limit)
1084            }
1085            Self::ExecutionTimeExceeded { elapsed, limit } => {
1086                write!(f, "Execution time exceeded: {:?} > {:?}", elapsed, limit)
1087            }
1088            Self::MessageRateExceeded { rate, limit } => {
1089                write!(f, "Message rate exceeded: {} > {} msg/s", rate, limit)
1090            }
1091            Self::UnauthorizedK2K { destination } => {
1092                write!(f, "Unauthorized K2K to: {}", destination)
1093            }
1094            Self::UnauthorizedMemoryAccess { region, requested } => {
1095                write!(
1096                    f,
1097                    "Unauthorized {:?} access to region: {}",
1098                    requested, region
1099                )
1100            }
1101            Self::CheckpointNotAllowed => write!(f, "Checkpointing not allowed"),
1102            Self::MigrationNotAllowed => write!(f, "Migration not allowed"),
1103            Self::SpawnNotAllowed => write!(f, "Spawning not allowed"),
1104            Self::HostAccessNotAllowed => write!(f, "Host memory access not allowed"),
1105        }
1106    }
1107}
1108
1109/// A recorded sandbox violation.
1110#[derive(Debug, Clone)]
1111pub struct SandboxViolation {
1112    /// Violation type
1113    pub violation_type: ViolationType,
1114    /// Kernel that violated the policy
1115    pub kernel_id: KernelId,
1116    /// When the violation occurred
1117    pub timestamp: Instant,
1118    /// Additional context
1119    pub context: Option<String>,
1120}
1121
1122/// Statistics for sandbox enforcement.
1123#[derive(Debug, Clone, Default)]
1124pub struct SandboxStats {
1125    /// Total policy checks performed
1126    pub total_checks: u64,
1127    /// Number of violations detected
1128    pub violations_detected: u64,
1129    /// Number of operations blocked
1130    pub operations_blocked: u64,
1131    /// Current memory usage
1132    pub current_memory_usage: u64,
1133    /// Current message rate
1134    pub current_message_rate: u32,
1135}
1136
1137/// Kernel sandbox for isolation and resource control.
1138pub struct KernelSandbox {
1139    /// The sandbox policy
1140    policy: SandboxPolicy,
1141    /// Kernel this sandbox applies to
1142    kernel_id: Option<KernelId>,
1143    /// Statistics
1144    stats: RwLock<SandboxStats>,
1145    /// Recorded violations
1146    violations: RwLock<Vec<SandboxViolation>>,
1147    /// Start time for execution tracking
1148    start_time: RwLock<Option<Instant>>,
1149    /// Message count for rate limiting
1150    message_count: AtomicU64,
1151    /// Last rate check time
1152    last_rate_check: RwLock<Instant>,
1153}
1154
1155impl KernelSandbox {
1156    /// Create a new kernel sandbox.
1157    pub fn new(policy: SandboxPolicy) -> Self {
1158        Self {
1159            policy,
1160            kernel_id: None,
1161            stats: RwLock::new(SandboxStats::default()),
1162            violations: RwLock::new(Vec::new()),
1163            start_time: RwLock::new(None),
1164            message_count: AtomicU64::new(0),
1165            last_rate_check: RwLock::new(Instant::now()),
1166        }
1167    }
1168
1169    /// Apply sandbox to a kernel.
1170    pub fn apply_to_kernel(&mut self, kernel_id: KernelId) {
1171        self.kernel_id = Some(kernel_id);
1172        *self.start_time.write().expect("start_time lock poisoned") = Some(Instant::now());
1173    }
1174
1175    /// Check memory usage against limits.
1176    pub fn check_memory(&self, bytes: u64) -> Result<(), SandboxViolation> {
1177        self.stats
1178            .write()
1179            .expect("stats lock poisoned")
1180            .total_checks += 1;
1181
1182        if bytes > self.policy.limits.max_memory_bytes {
1183            let violation = SandboxViolation {
1184                violation_type: ViolationType::MemoryLimitExceeded {
1185                    used: bytes,
1186                    limit: self.policy.limits.max_memory_bytes,
1187                },
1188                kernel_id: self
1189                    .kernel_id
1190                    .clone()
1191                    .unwrap_or_else(|| KernelId("unknown".to_string())),
1192                timestamp: Instant::now(),
1193                context: None,
1194            };
1195            self.record_violation(violation.clone());
1196            return Err(violation);
1197        }
1198
1199        self.stats
1200            .write()
1201            .expect("stats lock poisoned")
1202            .current_memory_usage = bytes;
1203        Ok(())
1204    }
1205
1206    /// Check execution time against limits.
1207    pub fn check_execution_time(&self) -> Result<(), SandboxViolation> {
1208        self.stats
1209            .write()
1210            .expect("stats lock poisoned")
1211            .total_checks += 1;
1212
1213        if let Some(start) = *self.start_time.read().expect("start_time lock poisoned") {
1214            let elapsed = start.elapsed();
1215            if elapsed > self.policy.limits.max_execution_time {
1216                let violation = SandboxViolation {
1217                    violation_type: ViolationType::ExecutionTimeExceeded {
1218                        elapsed,
1219                        limit: self.policy.limits.max_execution_time,
1220                    },
1221                    kernel_id: self
1222                        .kernel_id
1223                        .clone()
1224                        .unwrap_or_else(|| KernelId("unknown".to_string())),
1225                    timestamp: Instant::now(),
1226                    context: None,
1227                };
1228                self.record_violation(violation.clone());
1229                return Err(violation);
1230            }
1231        }
1232        Ok(())
1233    }
1234
1235    /// Check K2K destination against policy.
1236    pub fn check_k2k(&self, destination: &str) -> Result<(), SandboxViolation> {
1237        self.stats
1238            .write()
1239            .expect("stats lock poisoned")
1240            .total_checks += 1;
1241
1242        if !self.policy.is_k2k_allowed(destination) {
1243            let violation = SandboxViolation {
1244                violation_type: ViolationType::UnauthorizedK2K {
1245                    destination: destination.to_string(),
1246                },
1247                kernel_id: self
1248                    .kernel_id
1249                    .clone()
1250                    .unwrap_or_else(|| KernelId("unknown".to_string())),
1251                timestamp: Instant::now(),
1252                context: None,
1253            };
1254            self.record_violation(violation.clone());
1255            return Err(violation);
1256        }
1257        Ok(())
1258    }
1259
1260    /// Check if checkpointing is allowed.
1261    pub fn check_checkpoint(&self) -> Result<(), SandboxViolation> {
1262        self.stats
1263            .write()
1264            .expect("stats lock poisoned")
1265            .total_checks += 1;
1266
1267        if !self.policy.can_checkpoint {
1268            let violation = SandboxViolation {
1269                violation_type: ViolationType::CheckpointNotAllowed,
1270                kernel_id: self
1271                    .kernel_id
1272                    .clone()
1273                    .unwrap_or_else(|| KernelId("unknown".to_string())),
1274                timestamp: Instant::now(),
1275                context: None,
1276            };
1277            self.record_violation(violation.clone());
1278            return Err(violation);
1279        }
1280        Ok(())
1281    }
1282
1283    /// Check if migration is allowed.
1284    pub fn check_migration(&self) -> Result<(), SandboxViolation> {
1285        self.stats
1286            .write()
1287            .expect("stats lock poisoned")
1288            .total_checks += 1;
1289
1290        if !self.policy.can_migrate {
1291            let violation = SandboxViolation {
1292                violation_type: ViolationType::MigrationNotAllowed,
1293                kernel_id: self
1294                    .kernel_id
1295                    .clone()
1296                    .unwrap_or_else(|| KernelId("unknown".to_string())),
1297                timestamp: Instant::now(),
1298                context: None,
1299            };
1300            self.record_violation(violation.clone());
1301            return Err(violation);
1302        }
1303        Ok(())
1304    }
1305
1306    /// Record a message for rate limiting.
1307    pub fn record_message(&self) -> Result<(), SandboxViolation> {
1308        self.message_count.fetch_add(1, Ordering::Relaxed);
1309
1310        // Check rate every second
1311        let mut last_check = self
1312            .last_rate_check
1313            .write()
1314            .expect("last_rate_check lock poisoned");
1315        if last_check.elapsed() >= Duration::from_secs(1) {
1316            let count = self.message_count.swap(0, Ordering::Relaxed) as u32;
1317            *last_check = Instant::now();
1318
1319            self.stats
1320                .write()
1321                .expect("stats lock poisoned")
1322                .current_message_rate = count;
1323
1324            if count > self.policy.limits.max_messages_per_sec {
1325                let violation = SandboxViolation {
1326                    violation_type: ViolationType::MessageRateExceeded {
1327                        rate: count,
1328                        limit: self.policy.limits.max_messages_per_sec,
1329                    },
1330                    kernel_id: self
1331                        .kernel_id
1332                        .clone()
1333                        .unwrap_or_else(|| KernelId("unknown".to_string())),
1334                    timestamp: Instant::now(),
1335                    context: None,
1336                };
1337                self.record_violation(violation.clone());
1338                return Err(violation);
1339            }
1340        }
1341        Ok(())
1342    }
1343
1344    /// Record a violation.
1345    fn record_violation(&self, violation: SandboxViolation) {
1346        let mut stats = self.stats.write().expect("stats lock poisoned");
1347        stats.violations_detected += 1;
1348        stats.operations_blocked += 1;
1349
1350        self.violations
1351            .write()
1352            .expect("violations lock poisoned")
1353            .push(violation);
1354    }
1355
1356    /// Get all recorded violations.
1357    pub fn violations(&self) -> Vec<SandboxViolation> {
1358        self.violations
1359            .read()
1360            .expect("violations lock poisoned")
1361            .clone()
1362    }
1363
1364    /// Get sandbox statistics.
1365    pub fn stats(&self) -> SandboxStats {
1366        self.stats.read().expect("stats lock poisoned").clone()
1367    }
1368
1369    /// Get the policy.
1370    pub fn policy(&self) -> &SandboxPolicy {
1371        &self.policy
1372    }
1373
1374    /// Reset statistics and violations.
1375    pub fn reset(&self) {
1376        *self.stats.write().expect("stats lock poisoned") = SandboxStats::default();
1377        self.violations
1378            .write()
1379            .expect("violations lock poisoned")
1380            .clear();
1381        self.message_count.store(0, Ordering::Relaxed);
1382    }
1383}
1384
1385impl fmt::Debug for KernelSandbox {
1386    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1387        f.debug_struct("KernelSandbox")
1388            .field("policy", &self.policy)
1389            .field("kernel_id", &self.kernel_id)
1390            .field("stats", &self.stats())
1391            .field(
1392                "violations_count",
1393                &self.violations.read().map(|v| v.len()).unwrap_or(0),
1394            )
1395            .finish()
1396    }
1397}
1398
1399// ============================================================================
1400// Compliance Reports
1401// ============================================================================
1402
1403/// Compliance standard for reporting.
1404#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1405pub enum ComplianceStandard {
1406    /// SOC 2 Type II
1407    SOC2,
1408    /// GDPR (General Data Protection Regulation)
1409    GDPR,
1410    /// HIPAA (Health Insurance Portability and Accountability Act)
1411    HIPAA,
1412    /// PCI DSS (Payment Card Industry Data Security Standard)
1413    PCIDSS,
1414    /// ISO 27001
1415    ISO27001,
1416    /// FedRAMP
1417    FedRAMP,
1418    /// NIST Cybersecurity Framework
1419    NIST,
1420}
1421
1422impl fmt::Display for ComplianceStandard {
1423    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1424        match self {
1425            Self::SOC2 => write!(f, "SOC 2 Type II"),
1426            Self::GDPR => write!(f, "GDPR"),
1427            Self::HIPAA => write!(f, "HIPAA"),
1428            Self::PCIDSS => write!(f, "PCI DSS"),
1429            Self::ISO27001 => write!(f, "ISO 27001"),
1430            Self::FedRAMP => write!(f, "FedRAMP"),
1431            Self::NIST => write!(f, "NIST CSF"),
1432        }
1433    }
1434}
1435
1436/// Report output format.
1437#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1438pub enum ReportFormat {
1439    /// JSON format
1440    #[default]
1441    Json,
1442    /// HTML format
1443    Html,
1444    /// Markdown format
1445    Markdown,
1446    /// PDF format (requires external renderer)
1447    Pdf,
1448    /// CSV format (for data export)
1449    Csv,
1450}
1451
1452/// Compliance check result.
1453#[derive(Debug, Clone)]
1454pub enum ComplianceStatus {
1455    /// Fully compliant
1456    Compliant,
1457    /// Partially compliant with notes
1458    PartiallyCompliant {
1459        /// Notes describing partial compliance
1460        notes: Vec<String>,
1461    },
1462    /// Non-compliant with reasons
1463    NonCompliant {
1464        /// Reasons for non-compliance
1465        reasons: Vec<String>,
1466    },
1467    /// Not applicable
1468    NotApplicable,
1469}
1470
1471impl ComplianceStatus {
1472    /// Check if compliant.
1473    pub fn is_compliant(&self) -> bool {
1474        matches!(self, Self::Compliant | Self::NotApplicable)
1475    }
1476}
1477
1478/// A single compliance check.
1479#[derive(Debug, Clone)]
1480pub struct ComplianceCheck {
1481    /// Check identifier
1482    pub id: String,
1483    /// Check name
1484    pub name: String,
1485    /// Standard this check belongs to
1486    pub standard: ComplianceStandard,
1487    /// Check description
1488    pub description: String,
1489    /// Check status
1490    pub status: ComplianceStatus,
1491    /// Evidence collected
1492    pub evidence: Vec<String>,
1493    /// Recommendations
1494    pub recommendations: Vec<String>,
1495    /// When the check was performed
1496    pub checked_at: SystemTime,
1497}
1498
1499/// Summary statistics for a compliance report.
1500#[derive(Debug, Clone)]
1501pub struct ComplianceSummary {
1502    /// Total checks performed
1503    pub total_checks: usize,
1504    /// Number compliant
1505    pub compliant: usize,
1506    /// Number partially compliant
1507    pub partially_compliant: usize,
1508    /// Number non-compliant
1509    pub non_compliant: usize,
1510    /// Number not applicable
1511    pub not_applicable: usize,
1512    /// Overall compliance percentage
1513    pub compliance_percentage: f64,
1514}
1515
1516/// A complete compliance report.
1517#[derive(Debug, Clone)]
1518pub struct ComplianceReport {
1519    /// Report ID
1520    pub id: String,
1521    /// Report title
1522    pub title: String,
1523    /// Standards covered
1524    pub standards: Vec<ComplianceStandard>,
1525    /// Individual checks
1526    pub checks: Vec<ComplianceCheck>,
1527    /// Summary statistics
1528    pub summary: ComplianceSummary,
1529    /// Report generation time
1530    pub generated_at: SystemTime,
1531    /// Report period start
1532    pub period_start: SystemTime,
1533    /// Report period end
1534    pub period_end: SystemTime,
1535    /// Additional metadata
1536    pub metadata: HashMap<String, String>,
1537}
1538
1539impl ComplianceReport {
1540    /// Export report to specified format.
1541    pub fn export(&self, format: ReportFormat) -> String {
1542        match format {
1543            ReportFormat::Json => self.to_json(),
1544            ReportFormat::Html => self.to_html(),
1545            ReportFormat::Markdown => self.to_markdown(),
1546            ReportFormat::Pdf => self.to_markdown(), // PDF requires external renderer
1547            ReportFormat::Csv => self.to_csv(),
1548        }
1549    }
1550
1551    fn to_json(&self) -> String {
1552        let mut json = String::new();
1553        json.push_str("{\n");
1554        json.push_str(&format!("  \"id\": \"{}\",\n", self.id));
1555        json.push_str(&format!("  \"title\": \"{}\",\n", self.title));
1556        json.push_str(&format!(
1557            "  \"standards\": [{}],\n",
1558            self.standards
1559                .iter()
1560                .map(|s| format!("\"{}\"", s))
1561                .collect::<Vec<_>>()
1562                .join(", ")
1563        ));
1564        json.push_str("  \"summary\": {\n");
1565        json.push_str(&format!(
1566            "    \"total_checks\": {},\n",
1567            self.summary.total_checks
1568        ));
1569        json.push_str(&format!("    \"compliant\": {},\n", self.summary.compliant));
1570        json.push_str(&format!(
1571            "    \"partially_compliant\": {},\n",
1572            self.summary.partially_compliant
1573        ));
1574        json.push_str(&format!(
1575            "    \"non_compliant\": {},\n",
1576            self.summary.non_compliant
1577        ));
1578        json.push_str(&format!(
1579            "    \"compliance_percentage\": {:.1}\n",
1580            self.summary.compliance_percentage
1581        ));
1582        json.push_str("  },\n");
1583        json.push_str(&format!("  \"checks_count\": {}\n", self.checks.len()));
1584        json.push_str("}\n");
1585        json
1586    }
1587
1588    fn to_html(&self) -> String {
1589        let mut html = String::new();
1590        html.push_str("<!DOCTYPE html>\n<html>\n<head>\n");
1591        html.push_str(&format!("<title>{}</title>\n", self.title));
1592        html.push_str("<style>body { font-family: sans-serif; } .compliant { color: green; } .non-compliant { color: red; }</style>\n");
1593        html.push_str("</head>\n<body>\n");
1594        html.push_str(&format!("<h1>{}</h1>\n", self.title));
1595        html.push_str(&format!("<p>Report ID: {}</p>\n", self.id));
1596        html.push_str("<h2>Summary</h2>\n");
1597        html.push_str("<table>\n");
1598        html.push_str(&format!(
1599            "<tr><td>Total Checks</td><td>{}</td></tr>\n",
1600            self.summary.total_checks
1601        ));
1602        html.push_str(&format!(
1603            "<tr><td>Compliant</td><td class=\"compliant\">{}</td></tr>\n",
1604            self.summary.compliant
1605        ));
1606        html.push_str(&format!(
1607            "<tr><td>Non-Compliant</td><td class=\"non-compliant\">{}</td></tr>\n",
1608            self.summary.non_compliant
1609        ));
1610        html.push_str(&format!(
1611            "<tr><td>Compliance</td><td>{:.1}%</td></tr>\n",
1612            self.summary.compliance_percentage
1613        ));
1614        html.push_str("</table>\n");
1615        html.push_str("<h2>Checks</h2>\n");
1616        for check in &self.checks {
1617            html.push_str(&format!("<h3>{}</h3>\n", check.name));
1618            html.push_str(&format!("<p>{}</p>\n", check.description));
1619        }
1620        html.push_str("</body>\n</html>\n");
1621        html
1622    }
1623
1624    fn to_markdown(&self) -> String {
1625        let mut md = String::new();
1626        md.push_str(&format!("# {}\n\n", self.title));
1627        md.push_str(&format!("**Report ID:** {}\n\n", self.id));
1628        md.push_str("## Summary\n\n");
1629        md.push_str("| Metric | Value |\n");
1630        md.push_str("|--------|-------|\n");
1631        md.push_str(&format!(
1632            "| Total Checks | {} |\n",
1633            self.summary.total_checks
1634        ));
1635        md.push_str(&format!("| Compliant | {} |\n", self.summary.compliant));
1636        md.push_str(&format!(
1637            "| Partially Compliant | {} |\n",
1638            self.summary.partially_compliant
1639        ));
1640        md.push_str(&format!(
1641            "| Non-Compliant | {} |\n",
1642            self.summary.non_compliant
1643        ));
1644        md.push_str(&format!(
1645            "| Compliance | {:.1}% |\n",
1646            self.summary.compliance_percentage
1647        ));
1648        md.push_str("\n## Detailed Checks\n\n");
1649        for check in &self.checks {
1650            let status_icon = match &check.status {
1651                ComplianceStatus::Compliant => "✅",
1652                ComplianceStatus::PartiallyCompliant { .. } => "⚠️",
1653                ComplianceStatus::NonCompliant { .. } => "❌",
1654                ComplianceStatus::NotApplicable => "➖",
1655            };
1656            md.push_str(&format!("### {} {}\n\n", status_icon, check.name));
1657            md.push_str(&format!("{}\n\n", check.description));
1658        }
1659        md
1660    }
1661
1662    fn to_csv(&self) -> String {
1663        let mut csv = String::new();
1664        csv.push_str("ID,Name,Standard,Status,Description\n");
1665        for check in &self.checks {
1666            let status = match &check.status {
1667                ComplianceStatus::Compliant => "Compliant",
1668                ComplianceStatus::PartiallyCompliant { .. } => "Partially Compliant",
1669                ComplianceStatus::NonCompliant { .. } => "Non-Compliant",
1670                ComplianceStatus::NotApplicable => "N/A",
1671            };
1672            csv.push_str(&format!(
1673                "\"{}\",\"{}\",\"{}\",\"{}\",\"{}\"\n",
1674                check.id, check.name, check.standard, status, check.description
1675            ));
1676        }
1677        csv
1678    }
1679}
1680
1681/// Compliance reporter for generating compliance documentation.
1682pub struct ComplianceReporter {
1683    /// Standards to report on
1684    standards: HashSet<ComplianceStandard>,
1685    /// Organization name
1686    organization: String,
1687    /// Report metadata
1688    metadata: HashMap<String, String>,
1689    /// Custom checks
1690    custom_checks: Vec<Box<dyn Fn() -> ComplianceCheck + Send + Sync>>,
1691}
1692
1693impl ComplianceReporter {
1694    /// Create a new compliance reporter.
1695    pub fn new() -> Self {
1696        Self {
1697            standards: HashSet::new(),
1698            organization: "Unknown".to_string(),
1699            metadata: HashMap::new(),
1700            custom_checks: Vec::new(),
1701        }
1702    }
1703
1704    /// Add a compliance standard.
1705    pub fn with_standard(mut self, standard: ComplianceStandard) -> Self {
1706        self.standards.insert(standard);
1707        self
1708    }
1709
1710    /// Set organization name.
1711    pub fn with_organization(mut self, org: &str) -> Self {
1712        self.organization = org.to_string();
1713        self
1714    }
1715
1716    /// Add metadata.
1717    pub fn with_metadata(mut self, key: &str, value: &str) -> Self {
1718        self.metadata.insert(key.to_string(), value.to_string());
1719        self
1720    }
1721
1722    /// Generate a compliance report.
1723    pub fn generate_report(&self, _format: ReportFormat) -> ComplianceReport {
1724        let mut checks = Vec::new();
1725        let now = SystemTime::now();
1726
1727        // Generate checks for each standard
1728        for standard in &self.standards {
1729            checks.extend(self.generate_standard_checks(*standard));
1730        }
1731
1732        // Run custom checks
1733        for check_fn in &self.custom_checks {
1734            checks.push(check_fn());
1735        }
1736
1737        // Calculate summary
1738        let total = checks.len();
1739        let compliant = checks
1740            .iter()
1741            .filter(|c| matches!(c.status, ComplianceStatus::Compliant))
1742            .count();
1743        let partial = checks
1744            .iter()
1745            .filter(|c| matches!(c.status, ComplianceStatus::PartiallyCompliant { .. }))
1746            .count();
1747        let non_compliant = checks
1748            .iter()
1749            .filter(|c| matches!(c.status, ComplianceStatus::NonCompliant { .. }))
1750            .count();
1751        let na = checks
1752            .iter()
1753            .filter(|c| matches!(c.status, ComplianceStatus::NotApplicable))
1754            .count();
1755
1756        let applicable = total - na;
1757        let compliance_pct = if applicable > 0 {
1758            ((compliant as f64 + partial as f64 * 0.5) / applicable as f64) * 100.0
1759        } else {
1760            100.0
1761        };
1762
1763        ComplianceReport {
1764            id: format!(
1765                "RPT-{}",
1766                now.duration_since(SystemTime::UNIX_EPOCH)
1767                    .expect("system time should be after UNIX epoch")
1768                    .as_secs()
1769            ),
1770            title: format!("{} Compliance Report", self.organization),
1771            standards: self.standards.iter().copied().collect(),
1772            checks,
1773            summary: ComplianceSummary {
1774                total_checks: total,
1775                compliant,
1776                partially_compliant: partial,
1777                non_compliant,
1778                not_applicable: na,
1779                compliance_percentage: compliance_pct,
1780            },
1781            generated_at: now,
1782            period_start: now - Duration::from_secs(30 * 24 * 60 * 60), // 30 days ago
1783            period_end: now,
1784            metadata: self.metadata.clone(),
1785        }
1786    }
1787
1788    fn generate_standard_checks(&self, standard: ComplianceStandard) -> Vec<ComplianceCheck> {
1789        let now = SystemTime::now();
1790
1791        match standard {
1792            ComplianceStandard::SOC2 => vec![
1793                ComplianceCheck {
1794                    id: "SOC2-CC1.1".to_string(),
1795                    name: "Control Environment".to_string(),
1796                    standard,
1797                    description:
1798                        "The entity demonstrates commitment to integrity and ethical values."
1799                            .to_string(),
1800                    status: ComplianceStatus::Compliant,
1801                    evidence: vec![
1802                        "Audit logging enabled".to_string(),
1803                        "Access controls implemented".to_string(),
1804                    ],
1805                    recommendations: vec![],
1806                    checked_at: now,
1807                },
1808                ComplianceCheck {
1809                    id: "SOC2-CC6.1".to_string(),
1810                    name: "Logical Access Controls".to_string(),
1811                    standard,
1812                    description:
1813                        "Logical access security software, infrastructure, and architectures."
1814                            .to_string(),
1815                    status: ComplianceStatus::Compliant,
1816                    evidence: vec![
1817                        "Kernel sandboxing available".to_string(),
1818                        "Memory encryption available".to_string(),
1819                    ],
1820                    recommendations: vec![],
1821                    checked_at: now,
1822                },
1823                ComplianceCheck {
1824                    id: "SOC2-CC7.2".to_string(),
1825                    name: "System Monitoring".to_string(),
1826                    standard,
1827                    description: "System components are monitored and anomalies are identified."
1828                        .to_string(),
1829                    status: ComplianceStatus::Compliant,
1830                    evidence: vec![
1831                        "Health monitoring enabled".to_string(),
1832                        "GPU memory dashboard available".to_string(),
1833                    ],
1834                    recommendations: vec![],
1835                    checked_at: now,
1836                },
1837            ],
1838            ComplianceStandard::GDPR => vec![
1839                ComplianceCheck {
1840                    id: "GDPR-32".to_string(),
1841                    name: "Security of Processing".to_string(),
1842                    standard,
1843                    description: "Implement appropriate technical and organizational measures."
1844                        .to_string(),
1845                    status: ComplianceStatus::Compliant,
1846                    evidence: vec!["Memory encryption available".to_string()],
1847                    recommendations: vec!["Consider enabling encryption by default".to_string()],
1848                    checked_at: now,
1849                },
1850                ComplianceCheck {
1851                    id: "GDPR-33".to_string(),
1852                    name: "Breach Notification".to_string(),
1853                    standard,
1854                    description: "Notify supervisory authority of personal data breach."
1855                        .to_string(),
1856                    status: ComplianceStatus::PartiallyCompliant {
1857                        notes: vec!["Audit logging available but breach detection not automated"
1858                            .to_string()],
1859                    },
1860                    evidence: vec!["Audit logging enabled".to_string()],
1861                    recommendations: vec!["Add automated breach detection".to_string()],
1862                    checked_at: now,
1863                },
1864            ],
1865            ComplianceStandard::HIPAA => vec![
1866                ComplianceCheck {
1867                    id: "HIPAA-164.312(a)".to_string(),
1868                    name: "Access Control".to_string(),
1869                    standard,
1870                    description: "Implement technical policies for electronic PHI access."
1871                        .to_string(),
1872                    status: ComplianceStatus::Compliant,
1873                    evidence: vec![
1874                        "Kernel sandboxing available".to_string(),
1875                        "Access levels configurable".to_string(),
1876                    ],
1877                    recommendations: vec![],
1878                    checked_at: now,
1879                },
1880                ComplianceCheck {
1881                    id: "HIPAA-164.312(e)".to_string(),
1882                    name: "Transmission Security".to_string(),
1883                    standard,
1884                    description: "Implement security measures for ePHI transmission.".to_string(),
1885                    status: ComplianceStatus::Compliant,
1886                    evidence: vec!["Memory encryption for data at rest".to_string()],
1887                    recommendations: vec!["Implement TLS for network K2K".to_string()],
1888                    checked_at: now,
1889                },
1890            ],
1891            ComplianceStandard::PCIDSS => vec![
1892                ComplianceCheck {
1893                    id: "PCI-3.4".to_string(),
1894                    name: "Render PAN Unreadable".to_string(),
1895                    standard,
1896                    description: "Render PAN unreadable anywhere it is stored.".to_string(),
1897                    status: ComplianceStatus::Compliant,
1898                    evidence: vec!["AES-256-GCM encryption available".to_string()],
1899                    recommendations: vec![],
1900                    checked_at: now,
1901                },
1902                ComplianceCheck {
1903                    id: "PCI-10.1".to_string(),
1904                    name: "Audit Trails".to_string(),
1905                    standard,
1906                    description: "Implement audit trails to link access to individual users."
1907                        .to_string(),
1908                    status: ComplianceStatus::Compliant,
1909                    evidence: vec!["Comprehensive audit logging".to_string()],
1910                    recommendations: vec![],
1911                    checked_at: now,
1912                },
1913            ],
1914            ComplianceStandard::ISO27001 => vec![ComplianceCheck {
1915                id: "ISO-A.10.1".to_string(),
1916                name: "Cryptographic Controls".to_string(),
1917                standard,
1918                description: "Policy on use of cryptographic controls.".to_string(),
1919                status: ComplianceStatus::Compliant,
1920                evidence: vec!["Multiple encryption algorithms supported".to_string()],
1921                recommendations: vec![],
1922                checked_at: now,
1923            }],
1924            ComplianceStandard::FedRAMP => vec![ComplianceCheck {
1925                id: "FedRAMP-SC-28".to_string(),
1926                name: "Protection of Information at Rest".to_string(),
1927                standard,
1928                description: "Protect confidentiality and integrity of information at rest."
1929                    .to_string(),
1930                status: ComplianceStatus::Compliant,
1931                evidence: vec!["FIPS-compliant algorithms available".to_string()],
1932                recommendations: vec![],
1933                checked_at: now,
1934            }],
1935            ComplianceStandard::NIST => vec![
1936                ComplianceCheck {
1937                    id: "NIST-PR.DS-1".to_string(),
1938                    name: "Data-at-rest Protection".to_string(),
1939                    standard,
1940                    description: "Data-at-rest is protected.".to_string(),
1941                    status: ComplianceStatus::Compliant,
1942                    evidence: vec!["Memory encryption module".to_string()],
1943                    recommendations: vec![],
1944                    checked_at: now,
1945                },
1946                ComplianceCheck {
1947                    id: "NIST-DE.CM-1".to_string(),
1948                    name: "Network Monitoring".to_string(),
1949                    standard,
1950                    description: "The network is monitored to detect cybersecurity events."
1951                        .to_string(),
1952                    status: ComplianceStatus::Compliant,
1953                    evidence: vec![
1954                        "Observability context".to_string(),
1955                        "GPU profiler integration".to_string(),
1956                    ],
1957                    recommendations: vec![],
1958                    checked_at: now,
1959                },
1960            ],
1961        }
1962    }
1963}
1964
1965impl Default for ComplianceReporter {
1966    fn default() -> Self {
1967        Self::new()
1968    }
1969}
1970
1971impl fmt::Debug for ComplianceReporter {
1972    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1973        f.debug_struct("ComplianceReporter")
1974            .field("standards", &self.standards)
1975            .field("organization", &self.organization)
1976            .field("metadata", &self.metadata)
1977            .field("custom_checks_count", &self.custom_checks.len())
1978            .finish()
1979    }
1980}
1981
1982// ============================================================================
1983// Tests
1984// ============================================================================
1985
1986#[cfg(test)]
1987mod tests {
1988    use super::*;
1989
1990    // Memory Encryption Tests
1991
1992    #[test]
1993    fn test_encryption_config_builder() {
1994        let config = EncryptionConfig::new()
1995            .with_algorithm(EncryptionAlgorithm::ChaCha20Poly1305)
1996            .with_key_rotation_interval(Duration::from_secs(7200))
1997            .with_control_block_encryption(false);
1998
1999        assert_eq!(config.algorithm, EncryptionAlgorithm::ChaCha20Poly1305);
2000        assert_eq!(config.key_rotation_interval, Duration::from_secs(7200));
2001        assert!(!config.encrypt_control_blocks);
2002    }
2003
2004    #[test]
2005    fn test_encryption_key_creation() {
2006        let key = EncryptionKey::new(1, EncryptionAlgorithm::Aes256Gcm);
2007        assert_eq!(key.key_id, 1);
2008        assert_eq!(key.key_size(), 32);
2009        assert!(!key.is_expired());
2010    }
2011
2012    #[test]
2013    fn test_encrypt_decrypt_roundtrip() {
2014        let encryption = MemoryEncryption::new(EncryptionConfig::default());
2015        let plaintext = b"Hello, GPU World!";
2016
2017        let encrypted = encryption.encrypt_region(plaintext);
2018        assert_ne!(encrypted.ciphertext[..plaintext.len()], plaintext[..]);
2019
2020        let decrypted = encryption.decrypt_region(&encrypted).unwrap();
2021        assert_eq!(decrypted, plaintext);
2022    }
2023
2024    #[test]
2025    fn test_key_rotation() {
2026        let encryption = MemoryEncryption::new(EncryptionConfig::default());
2027        let initial_key_id = encryption.current_key_id();
2028
2029        encryption.rotate_keys();
2030        assert_eq!(encryption.current_key_id(), initial_key_id + 1);
2031
2032        // Stats should reflect rotation
2033        let stats = encryption.stats();
2034        assert_eq!(stats.key_rotations, 1);
2035    }
2036
2037    #[test]
2038    fn test_decrypt_with_old_key() {
2039        let encryption = MemoryEncryption::new(EncryptionConfig::default());
2040        let plaintext = b"Secret data";
2041
2042        let encrypted = encryption.encrypt_region(plaintext);
2043        let old_key_id = encrypted.key_id;
2044
2045        // Rotate key
2046        encryption.rotate_keys();
2047        assert_ne!(encryption.current_key_id(), old_key_id);
2048
2049        // Should still decrypt with old key
2050        let decrypted = encryption.decrypt_region(&encrypted).unwrap();
2051        assert_eq!(decrypted, plaintext);
2052    }
2053
2054    #[test]
2055    fn test_encryption_stats() {
2056        let encryption = MemoryEncryption::new(EncryptionConfig::default());
2057        let data = vec![0u8; 1024];
2058
2059        for _ in 0..10 {
2060            let encrypted = encryption.encrypt_region(&data);
2061            let _ = encryption.decrypt_region(&encrypted);
2062        }
2063
2064        let stats = encryption.stats();
2065        assert_eq!(stats.encrypt_ops, 10);
2066        assert_eq!(stats.decrypt_ops, 10);
2067        assert_eq!(stats.bytes_encrypted, 10240);
2068    }
2069
2070    // Kernel Sandboxing Tests
2071
2072    #[test]
2073    fn test_resource_limits_builder() {
2074        let limits = ResourceLimits::new()
2075            .with_max_memory(512 * 1024 * 1024)
2076            .with_max_execution_time(Duration::from_secs(30));
2077
2078        assert_eq!(limits.max_memory_bytes, 512 * 1024 * 1024);
2079        assert_eq!(limits.max_execution_time, Duration::from_secs(30));
2080    }
2081
2082    #[test]
2083    fn test_sandbox_policy_k2k() {
2084        let policy = SandboxPolicy::new()
2085            .allow_k2k_to(&["trusted_kernel", "another_trusted"])
2086            .deny_k2k_to(&["malicious_kernel"]);
2087
2088        assert!(policy.is_k2k_allowed("trusted_kernel"));
2089        assert!(policy.is_k2k_allowed("another_trusted"));
2090        assert!(!policy.is_k2k_allowed("malicious_kernel"));
2091        assert!(!policy.is_k2k_allowed("unknown_kernel")); // Not in allowed list
2092    }
2093
2094    #[test]
2095    fn test_sandbox_memory_check() {
2096        let policy = SandboxPolicy::new().with_memory_limit(1024);
2097        let sandbox = KernelSandbox::new(policy);
2098
2099        // Should pass
2100        assert!(sandbox.check_memory(512).is_ok());
2101
2102        // Should fail
2103        let result = sandbox.check_memory(2048);
2104        assert!(result.is_err());
2105
2106        if let Err(violation) = result {
2107            assert!(matches!(
2108                violation.violation_type,
2109                ViolationType::MemoryLimitExceeded { .. }
2110            ));
2111        }
2112    }
2113
2114    #[test]
2115    fn test_sandbox_k2k_check() {
2116        let policy = SandboxPolicy::new().deny_k2k_to(&["blocked"]);
2117        let sandbox = KernelSandbox::new(policy);
2118
2119        assert!(sandbox.check_k2k("allowed_dest").is_ok());
2120        assert!(sandbox.check_k2k("blocked").is_err());
2121    }
2122
2123    #[test]
2124    fn test_sandbox_checkpoint_check() {
2125        let policy = SandboxPolicy::restrictive();
2126        let sandbox = KernelSandbox::new(policy);
2127
2128        assert!(sandbox.check_checkpoint().is_err());
2129
2130        let permissive = SandboxPolicy::permissive();
2131        let sandbox2 = KernelSandbox::new(permissive);
2132        assert!(sandbox2.check_checkpoint().is_ok());
2133    }
2134
2135    #[test]
2136    fn test_sandbox_stats() {
2137        let policy = SandboxPolicy::new().with_memory_limit(1024);
2138        let sandbox = KernelSandbox::new(policy);
2139
2140        let _ = sandbox.check_memory(512);
2141        let _ = sandbox.check_memory(2048); // Violation
2142        let _ = sandbox.check_k2k("dest");
2143
2144        let stats = sandbox.stats();
2145        assert_eq!(stats.total_checks, 3);
2146        assert_eq!(stats.violations_detected, 1);
2147    }
2148
2149    #[test]
2150    fn test_sandbox_violations_list() {
2151        let policy = SandboxPolicy::restrictive();
2152        let sandbox = KernelSandbox::new(policy);
2153
2154        let _ = sandbox.check_checkpoint();
2155        let _ = sandbox.check_migration();
2156
2157        let violations = sandbox.violations();
2158        assert_eq!(violations.len(), 2);
2159    }
2160
2161    // Compliance Reports Tests
2162
2163    #[test]
2164    fn test_compliance_reporter_creation() {
2165        let reporter = ComplianceReporter::new()
2166            .with_standard(ComplianceStandard::SOC2)
2167            .with_standard(ComplianceStandard::GDPR)
2168            .with_organization("Test Org");
2169
2170        assert_eq!(reporter.standards.len(), 2);
2171        assert!(reporter.standards.contains(&ComplianceStandard::SOC2));
2172        assert!(reporter.standards.contains(&ComplianceStandard::GDPR));
2173    }
2174
2175    #[test]
2176    fn test_generate_soc2_report() {
2177        let reporter = ComplianceReporter::new()
2178            .with_standard(ComplianceStandard::SOC2)
2179            .with_organization("Acme Corp");
2180
2181        let report = reporter.generate_report(ReportFormat::Json);
2182
2183        assert!(!report.checks.is_empty());
2184        assert!(report.summary.total_checks > 0);
2185        assert!(report.title.contains("Acme Corp"));
2186    }
2187
2188    #[test]
2189    fn test_report_json_export() {
2190        let reporter = ComplianceReporter::new().with_standard(ComplianceStandard::HIPAA);
2191
2192        let report = reporter.generate_report(ReportFormat::Json);
2193        let json = report.export(ReportFormat::Json);
2194
2195        assert!(json.contains("\"id\""));
2196        assert!(json.contains("\"summary\""));
2197    }
2198
2199    #[test]
2200    fn test_report_markdown_export() {
2201        let reporter = ComplianceReporter::new().with_standard(ComplianceStandard::NIST);
2202
2203        let report = reporter.generate_report(ReportFormat::Markdown);
2204        let md = report.export(ReportFormat::Markdown);
2205
2206        assert!(md.contains("# "));
2207        assert!(md.contains("## Summary"));
2208        assert!(md.contains("| Metric | Value |"));
2209    }
2210
2211    #[test]
2212    fn test_report_html_export() {
2213        let reporter = ComplianceReporter::new().with_standard(ComplianceStandard::PCIDSS);
2214
2215        let report = reporter.generate_report(ReportFormat::Html);
2216        let html = report.export(ReportFormat::Html);
2217
2218        assert!(html.contains("<!DOCTYPE html>"));
2219        assert!(html.contains("<h1>"));
2220    }
2221
2222    #[test]
2223    fn test_report_csv_export() {
2224        let reporter = ComplianceReporter::new().with_standard(ComplianceStandard::ISO27001);
2225
2226        let report = reporter.generate_report(ReportFormat::Csv);
2227        let csv = report.export(ReportFormat::Csv);
2228
2229        assert!(csv.contains("ID,Name,Standard,Status,Description"));
2230    }
2231
2232    #[test]
2233    fn test_compliance_summary_calculation() {
2234        let reporter = ComplianceReporter::new()
2235            .with_standard(ComplianceStandard::SOC2)
2236            .with_standard(ComplianceStandard::GDPR)
2237            .with_standard(ComplianceStandard::HIPAA);
2238
2239        let report = reporter.generate_report(ReportFormat::Json);
2240
2241        let sum = report.summary.compliant
2242            + report.summary.partially_compliant
2243            + report.summary.non_compliant
2244            + report.summary.not_applicable;
2245        assert_eq!(sum, report.summary.total_checks);
2246    }
2247
2248    #[test]
2249    fn test_compliance_status_is_compliant() {
2250        assert!(ComplianceStatus::Compliant.is_compliant());
2251        assert!(ComplianceStatus::NotApplicable.is_compliant());
2252        assert!(!ComplianceStatus::NonCompliant { reasons: vec![] }.is_compliant());
2253        assert!(!ComplianceStatus::PartiallyCompliant { notes: vec![] }.is_compliant());
2254    }
2255
2256    #[test]
2257    fn test_all_standards() {
2258        let reporter = ComplianceReporter::new()
2259            .with_standard(ComplianceStandard::SOC2)
2260            .with_standard(ComplianceStandard::GDPR)
2261            .with_standard(ComplianceStandard::HIPAA)
2262            .with_standard(ComplianceStandard::PCIDSS)
2263            .with_standard(ComplianceStandard::ISO27001)
2264            .with_standard(ComplianceStandard::FedRAMP)
2265            .with_standard(ComplianceStandard::NIST);
2266
2267        let report = reporter.generate_report(ReportFormat::Json);
2268        assert_eq!(report.standards.len(), 7);
2269    }
2270}