use adk_code::{
BackendCapabilities, CodeExecutor, ExecutionError, ExecutionIsolation, ExecutionLanguage,
ExecutionPayload, ExecutionRequest, ExecutionStatus, GuestModuleFormat, SandboxPolicy,
WasmGuestExecutor, validate_wasm_bytes,
};
use proptest::prelude::*;
#[allow(dead_code)]
fn minimal_wasm_module() -> Vec<u8> {
vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00]
}
fn arb_non_wasm_bytes() -> impl Strategy<Value = Vec<u8>> {
prop::collection::vec(any::<u8>(), 0..64).prop_filter("must not be valid WASM", |bytes| {
!(bytes.len() >= 8 && bytes.starts_with(b"\0asm"))
})
}
fn arb_valid_wasm_module() -> impl Strategy<Value = Vec<u8>> {
prop::collection::vec(any::<u8>(), 0..128).prop_map(|extra| {
let mut module = vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00];
module.extend(extra);
module
})
}
fn arb_non_wasm_language() -> impl Strategy<Value = ExecutionLanguage> {
prop_oneof![
Just(ExecutionLanguage::Rust),
Just(ExecutionLanguage::JavaScript),
Just(ExecutionLanguage::Python),
Just(ExecutionLanguage::Command),
]
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn prop_invalid_wasm_bytes_are_rejected(bytes in arb_non_wasm_bytes()) {
let result = validate_wasm_bytes(&bytes);
prop_assert!(result.is_err(), "non-WASM bytes should be rejected: {:?}", &bytes[..bytes.len().min(16)]);
match result.unwrap_err() {
ExecutionError::InvalidRequest(msg) => {
prop_assert!(
msg.contains("too small") || msg.contains("magic number"),
"error should mention size or magic: {msg}"
);
}
other => prop_assert!(false, "expected InvalidRequest, got: {other}"),
}
}
#[test]
fn prop_valid_wasm_bytes_are_accepted(bytes in arb_valid_wasm_module()) {
let result = validate_wasm_bytes(&bytes);
prop_assert!(result.is_ok(), "valid WASM module should be accepted, got: {:?}", result);
}
#[test]
fn prop_wasm_executor_rejects_non_wasm_languages(lang in arb_non_wasm_language()) {
let executor = WasmGuestExecutor::new();
prop_assert!(
!executor.supports_language(&lang),
"WasmGuestExecutor should not support {lang}"
);
}
#[test]
fn prop_wasm_executor_rejects_source_payloads(code in "[a-zA-Z0-9 ]{1,100}") {
let executor = WasmGuestExecutor::new();
let request = ExecutionRequest {
language: ExecutionLanguage::Wasm,
payload: ExecutionPayload::Source { code },
argv: vec![],
stdin: None,
input: None,
sandbox: SandboxPolicy::strict_rust(),
identity: None,
};
let rt = tokio::runtime::Runtime::new().unwrap();
let result = rt.block_on(executor.execute(request));
prop_assert!(result.is_err(), "Source payloads should be rejected for Wasm");
match result.unwrap_err() {
ExecutionError::InvalidRequest(msg) => {
prop_assert!(
msg.contains("GuestModule") || msg.contains("Source"),
"error should mention payload type: {msg}"
);
}
other => prop_assert!(false, "expected InvalidRequest, got: {other}"),
}
}
#[test]
fn prop_wasm_executor_accepts_valid_guest_modules(bytes in arb_valid_wasm_module()) {
let executor = WasmGuestExecutor::new();
let request = ExecutionRequest {
language: ExecutionLanguage::Wasm,
payload: ExecutionPayload::GuestModule {
format: GuestModuleFormat::Wasm,
bytes: bytes.clone(),
},
argv: vec![],
stdin: None,
input: None,
sandbox: SandboxPolicy::strict_rust(),
identity: None,
};
let rt = tokio::runtime::Runtime::new().unwrap();
let result = rt.block_on(executor.execute(request));
prop_assert!(result.is_ok(), "valid WASM module should be accepted");
let result = result.unwrap();
prop_assert_eq!(result.status, ExecutionStatus::Success);
let output = result.output.as_ref().unwrap();
prop_assert_eq!(&output["validated"], true);
prop_assert_eq!(&output["module_size_bytes"], bytes.len());
}
}
#[test]
fn wasm_executor_is_not_a_javascript_executor() {
let executor = WasmGuestExecutor::new();
assert!(!executor.supports_language(&ExecutionLanguage::JavaScript));
assert!(executor.supports_language(&ExecutionLanguage::Wasm));
assert_eq!(executor.name(), "wasm-guest");
}
#[test]
fn wasm_executor_capabilities_are_truthful() {
let executor = WasmGuestExecutor::new();
let caps = executor.capabilities();
assert_eq!(caps.isolation, ExecutionIsolation::InProcess);
assert!(caps.enforce_network_policy);
assert!(caps.enforce_filesystem_policy);
assert!(caps.enforce_environment_policy);
assert!(caps.enforce_timeout);
assert!(caps.supports_structured_output);
assert!(!caps.supports_process_execution);
}
#[test]
fn wasm_executor_isolation_differs_from_container() {
let wasm_caps = WasmGuestExecutor::new().capabilities();
let container_caps = BackendCapabilities {
isolation: ExecutionIsolation::ContainerEphemeral,
enforce_network_policy: true,
enforce_filesystem_policy: true,
enforce_environment_policy: true,
enforce_timeout: true,
supports_structured_output: true,
supports_process_execution: true,
supports_persistent_workspace: false,
supports_interactive_sessions: false,
};
assert_ne!(wasm_caps.isolation, container_caps.isolation);
assert_ne!(wasm_caps.supports_process_execution, container_caps.supports_process_execution);
}