#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::super::security::*;
use super::super::types::Severity;
use proptest::prelude::*;
proptest! {
fn validator_never_panics_on_arbitrary_input(
data in prop::collection::vec(any::<u8>(), 0..10000)
) {
let validator = WasmSecurityValidator::new();
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
validator.validate(&data)
}));
prop_assert!(result.is_ok());
}
fn validation_result_is_consistent(
data in prop::collection::vec(any::<u8>(), 0..1000)
) {
let validator = WasmSecurityValidator::new();
let result = validator.validate(&data);
prop_assert!(result.is_ok());
if let Ok(validation) = result {
let has_critical = validation.issues.iter()
.any(|issue| issue.severity == Severity::Critical);
if has_critical {
prop_assert!(!validation.passed);
}
prop_assert_eq!(validation.passed, validation.issues.is_empty());
}
}
fn small_files_detected(
size in 0usize..8
) {
let data = vec![0u8; size];
let validator = WasmSecurityValidator::new();
let result = validator.validate(&data);
prop_assert!(result.is_ok());
let validation = result.unwrap();
prop_assert!(!validation.passed);
let has_size_issue = validation.issues.iter()
.any(|issue| issue.category == SecurityCategory::InvalidFormat &&
issue.description.contains("too small"));
prop_assert!(has_size_issue);
}
fn invalid_magic_detected(
magic in prop::collection::vec(any::<u8>().prop_filter("not wasm magic", |&b| b != 0x00), 4..4),
rest in prop::collection::vec(any::<u8>(), 4..100)
) {
let mut data = magic;
data.extend(rest);
let validator = WasmSecurityValidator::new();
let result = validator.validate(&data);
prop_assert!(result.is_ok());
let validation = result.unwrap();
prop_assert!(!validation.passed);
let has_magic_issue = validation.issues.iter()
.any(|issue| issue.category == SecurityCategory::InvalidFormat &&
issue.description.contains("magic number"));
prop_assert!(has_magic_issue);
}
fn large_files_flagged(
size_mb in 101usize..200
) {
let mut data = vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00];
data.resize(size_mb * 1024 * 1024, 0);
let validator = WasmSecurityValidator::new();
let result = validator.validate(&data);
prop_assert!(result.is_ok());
let validation = result.unwrap();
let has_size_issue = validation.issues.iter()
.any(|issue| issue.category == SecurityCategory::ResourceExhaustion &&
issue.severity == Severity::High);
prop_assert!(has_size_issue);
}
fn valid_wasm_passes_basic_checks(
data_size in 0usize..1000
) {
let mut data = vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00];
data.extend(vec![0u8; data_size]);
let validator = WasmSecurityValidator::new();
let result = validator.validate(&data);
prop_assert!(result.is_ok());
let validation = result.unwrap();
prop_assert!(validation.passed);
prop_assert!(validation.issues.is_empty());
}
fn severity_ordering_respected(
data in prop::collection::vec(any::<u8>(), 0..1000)
) {
let validator = WasmSecurityValidator::new();
let result = validator.validate(&data);
prop_assert!(result.is_ok());
if let Ok(validation) = result {
for issue in &validation.issues {
match issue.category {
SecurityCategory::InvalidFormat => {
prop_assert!(issue.severity == Severity::Critical ||
issue.severity == Severity::High);
}
SecurityCategory::ResourceExhaustion => {
prop_assert!(issue.severity == Severity::High ||
issue.severity == Severity::Medium);
}
_ => {
}
}
}
}
}
fn validate_text_never_panics(
text in ".*"
) {
let validator = WasmSecurityValidator::new();
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
validator.validate_text(&text)
}));
prop_assert!(result.is_ok());
}
fn ast_validation_never_panics(
node_count in 0usize..100
) {
use crate::models::unified_ast::{AstDag, UnifiedAstNode, AstKind, Language, FunctionKind};
let validator = WasmSecurityValidator::new();
let mut dag = AstDag::new();
for _i in 0..node_count {
let node = UnifiedAstNode::new(
AstKind::Function(FunctionKind::Regular),
Language::WebAssembly,
);
dag.add_node(node);
}
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
validator.validate_ast(&dag)
}));
prop_assert!(result.is_ok());
}
}
#[test]
fn edge_case_file_sizes() {
let validator = WasmSecurityValidator::new();
let min_valid = vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00];
let result = validator.validate(&min_valid).unwrap();
assert!(result.passed);
let too_small = vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00];
let result = validator.validate(&too_small).unwrap();
assert!(!result.passed);
let mut at_limit = vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00];
at_limit.resize(100 * 1024 * 1024, 0);
let result = validator.validate(&at_limit).unwrap();
assert!(result.passed);
let mut over_limit = vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00];
over_limit.resize(100 * 1024 * 1024 + 1, 0);
let result = validator.validate(&over_limit).unwrap();
assert!(!result.passed);
}
#[test]
fn multiple_issues_reported() {
let validator = WasmSecurityValidator::new();
let data = vec![0xFF, 0xFF, 0xFF];
let result = validator.validate(&data).unwrap();
assert!(!result.passed);
assert!(!result.issues.is_empty());
let large_invalid = vec![0xFF; 200 * 1024 * 1024];
let result = validator.validate(&large_invalid).unwrap();
assert!(!result.passed);
assert!(result.issues.len() >= 2); }
}