rustant_tools/sandbox/
mod.rs1pub mod config;
28pub mod executor;
29pub mod host;
30pub mod runtime;
31
32pub use config::{Capability, ResourceLimits, SandboxConfig};
34pub use executor::{SandboxExecution, SandboxedExecutor};
35pub use runtime::{ExecutionResult, SandboxError, WasmRuntime};
36
37use std::sync::Arc;
38
39pub fn create_sandbox() -> SandboxedExecutor {
44 SandboxedExecutor::with_defaults()
45}
46
47pub fn create_sandbox_with_config(config: SandboxConfig) -> SandboxedExecutor {
49 let runtime = Arc::new(WasmRuntime::new());
50 SandboxedExecutor::new(runtime, config)
51}
52
53pub fn validate_module(wasm_bytes: &[u8]) -> Result<(), SandboxError> {
58 let runtime = WasmRuntime::new();
59 runtime.validate_module(wasm_bytes)
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_create_sandbox() {
68 let executor = create_sandbox();
69 assert_eq!(
70 executor.default_config().resource_limits.max_fuel,
71 ResourceLimits::default().max_fuel
72 );
73 }
74
75 #[test]
76 fn test_create_sandbox_with_config() {
77 let config = SandboxConfig::new().with_fuel_limit(42);
78 let executor = create_sandbox_with_config(config);
79 assert_eq!(executor.default_config().resource_limits.max_fuel, 42);
80 }
81
82 #[test]
83 fn test_validate_valid_module() {
84 let wat = br#"(module (func (export "_start")))"#;
85 assert!(validate_module(wat).is_ok());
86 }
87
88 #[test]
89 fn test_validate_invalid_module() {
90 assert!(validate_module(b"garbage data").is_err());
91 }
92
93 #[test]
94 fn test_end_to_end_simple_execution() {
95 let executor = create_sandbox();
96 let wat = br#"(module (func (export "_start")))"#;
97 let result = executor.execute(wat, b"").unwrap();
98 assert!(result.output().is_empty());
99 assert!(result.fuel_consumed() > 0);
100 }
101
102 #[test]
103 fn test_end_to_end_with_output() {
104 let executor = create_sandbox();
105 let wat = br#"
106 (module
107 (import "env" "host_write_output" (func $write (param i32 i32)))
108 (memory (export "memory") 1)
109 (data (i32.const 0) "sandboxed")
110 (func (export "_start")
111 i32.const 0
112 i32.const 9
113 call $write
114 )
115 )
116 "#;
117 let result = executor.execute(wat, b"").unwrap();
118 assert_eq!(result.output_str(), Some("sandboxed"));
119 }
120
121 #[test]
122 fn test_end_to_end_fuel_exhaustion() {
123 let config = SandboxConfig::new().with_fuel_limit(50);
124 let executor = create_sandbox_with_config(config);
125 let wat = br#"
126 (module
127 (func (export "_start")
128 (local $i i32)
129 (loop $loop
130 (local.set $i (i32.add (local.get $i) (i32.const 1)))
131 (br_if $loop (i32.lt_u (local.get $i) (i32.const 999999)))
132 )
133 )
134 )
135 "#;
136 let err = executor.execute(wat, b"").unwrap_err();
137 assert!(matches!(err, SandboxError::OutOfFuel));
138 }
139
140 #[test]
141 fn test_end_to_end_input_output() {
142 let executor = create_sandbox();
143 let wat = br#"
144 (module
145 (import "env" "host_get_input_len" (func $input_len (result i32)))
146 (import "env" "host_read_input" (func $read (param i32 i32) (result i32)))
147 (import "env" "host_write_output" (func $write (param i32 i32)))
148 (memory (export "memory") 1)
149 (func (export "_start")
150 (local $len i32)
151 (local.set $len (call $input_len))
152 (drop (call $read (i32.const 0) (local.get $len)))
153 (call $write (i32.const 0) (local.get $len))
154 )
155 )
156 "#;
157 let result = executor.execute(wat, b"echo-test").unwrap();
158 assert_eq!(result.output_str(), Some("echo-test"));
159 }
160
161 #[test]
162 fn test_capabilities_in_config() {
163 let config = SandboxConfig::new()
164 .with_capability(Capability::Stdout)
165 .with_capability(Capability::Stderr)
166 .with_capability(Capability::FileRead(vec!["/tmp".into()]));
167
168 let executor = create_sandbox_with_config(config);
169 assert_eq!(executor.default_config().capabilities.len(), 3);
170 }
171
172 #[test]
173 fn test_resource_limits_applied() {
174 let config = SandboxConfig::new()
175 .with_fuel_limit(100_000)
176 .with_memory_limit(4 * 1024 * 1024);
177
178 let executor = create_sandbox_with_config(config);
179
180 let wat = br#"(module (func (export "_start")))"#;
181 let result = executor.execute(wat, b"").unwrap();
182 assert!(result.within_limits());
183 }
184}