#![cfg_attr(coverage_nightly, coverage(off))]
use super::types::Severity;
use crate::models::unified_ast::AstDag;
use anyhow::Result;
#[derive(Debug, Clone)]
pub struct SecurityValidation {
pub passed: bool,
pub issues: Vec<SecurityIssue>,
}
#[derive(Debug, Clone)]
pub struct SecurityIssue {
pub severity: Severity,
pub description: String,
pub category: SecurityCategory,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SecurityCategory {
InvalidFormat,
MemorySafety,
ResourceExhaustion,
CodeInjection,
Other,
}
pub struct WasmSecurityValidator;
impl WasmSecurityValidator {
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new() -> Self {
Self
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn validate(&self, data: &[u8]) -> Result<SecurityValidation> {
let mut issues = Vec::new();
if data.len() < 8 {
issues.push(SecurityIssue {
severity: Severity::Critical,
description: "File too small to be valid WASM".to_string(),
category: SecurityCategory::InvalidFormat,
});
} else if &data[0..4] != b"\0asm" {
issues.push(SecurityIssue {
severity: Severity::Critical,
description: "Invalid WASM magic number".to_string(),
category: SecurityCategory::InvalidFormat,
});
}
if data.len() > 100 * 1024 * 1024 {
issues.push(SecurityIssue {
severity: Severity::High,
description: "File size exceeds safe limit (100MB)".to_string(),
category: SecurityCategory::ResourceExhaustion,
});
}
Ok(SecurityValidation {
passed: issues.is_empty(),
issues,
})
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn validate_ast(&self, _ast: &AstDag) -> Result<()> {
Ok(())
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn validate_text(&self, _content: &str) -> Result<()> {
Ok(())
}
}
impl Default for WasmSecurityValidator {
fn default() -> Self {
Self::new()
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_security_validator_new() {
let validator = WasmSecurityValidator::new();
let _ = validator;
}
#[test]
fn test_security_validator_default() {
let validator = WasmSecurityValidator;
let _ = validator;
}
#[test]
fn test_validate_valid_wasm_header() {
let validator = WasmSecurityValidator::new();
let data = b"\0asm\x01\x00\x00\x00";
let result = validator.validate(data).unwrap();
assert!(result.passed);
assert!(result.issues.is_empty());
}
#[test]
fn test_validate_too_small() {
let validator = WasmSecurityValidator::new();
let data = b"\0asm"; let result = validator.validate(data).unwrap();
assert!(!result.passed);
assert_eq!(result.issues.len(), 1);
assert!(matches!(
result.issues[0].category,
SecurityCategory::InvalidFormat
));
}
#[test]
fn test_validate_invalid_magic() {
let validator = WasmSecurityValidator::new();
let data = b"invalid\x00"; let result = validator.validate(data).unwrap();
assert!(!result.passed);
assert_eq!(result.issues.len(), 1);
assert!(result.issues[0].description.contains("magic number"));
}
#[test]
fn test_validate_ast() {
let validator = WasmSecurityValidator::new();
let dag = AstDag::new();
let result = validator.validate_ast(&dag);
assert!(result.is_ok());
}
#[test]
fn test_validate_text() {
let validator = WasmSecurityValidator::new();
let result = validator.validate_text("(module)");
assert!(result.is_ok());
}
#[test]
fn test_security_category_eq() {
assert_eq!(
SecurityCategory::InvalidFormat,
SecurityCategory::InvalidFormat
);
assert_ne!(
SecurityCategory::InvalidFormat,
SecurityCategory::MemorySafety
);
}
#[test]
fn test_security_category_debug() {
let category = SecurityCategory::MemorySafety;
let debug_str = format!("{:?}", category);
assert!(debug_str.contains("MemorySafety"));
}
#[test]
fn test_security_issue_clone() {
let issue = SecurityIssue {
severity: Severity::High,
description: "test issue".to_string(),
category: SecurityCategory::Other,
};
let cloned = issue.clone();
assert_eq!(issue.description, cloned.description);
}
#[test]
fn test_security_validation_clone() {
let validation = SecurityValidation {
passed: true,
issues: vec![],
};
let cloned = validation.clone();
assert_eq!(validation.passed, cloned.passed);
}
#[test]
fn test_all_security_categories() {
let _ = SecurityCategory::InvalidFormat;
let _ = SecurityCategory::MemorySafety;
let _ = SecurityCategory::ResourceExhaustion;
let _ = SecurityCategory::CodeInjection;
let _ = SecurityCategory::Other;
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}