use std::path::Path;
use thiserror::Error;
use crate::PluginMetadata;
#[derive(Error, Debug)]
pub enum ValidationError {
#[error("Signature verification failed: {0}")]
SignatureInvalid(String),
#[error("Platform not supported: {0}")]
PlatformIncompatible(String),
#[error("Resource limit exceeded: {0}")]
ResourceLimitExceeded(String),
#[error("Sandbox constraint violation: {0}")]
SandboxViolation(String),
#[error("Invalid metadata: {0}")]
InvalidMetadata(String),
}
pub type ValidationResult = Result<(), ValidationError>;
#[derive(Debug)]
pub struct PluginValidator {
pub max_memory: usize,
pub strict_signatures: bool,
pub enforce_sandbox: bool,
}
impl Default for PluginValidator {
fn default() -> Self {
Self::new()
}
}
impl PluginValidator {
pub fn new() -> Self {
Self {
max_memory: 100 * 1024 * 1024, strict_signatures: true,
enforce_sandbox: true,
}
}
pub fn with_max_memory(mut self, max_bytes: usize) -> Self {
self.max_memory = max_bytes;
self
}
pub fn with_strict_signatures(mut self, strict: bool) -> Self {
self.strict_signatures = strict;
self
}
pub fn with_sandbox(mut self, enforce: bool) -> Self {
self.enforce_sandbox = enforce;
self
}
pub async fn validate_plugin(
&self,
binary_path: &Path,
metadata: &PluginMetadata,
) -> ValidationResult {
self.validate_metadata(metadata)?;
if self.strict_signatures {
self.verify_signature(binary_path)?;
}
self.check_platform_compatibility(metadata)?;
self.validate_resources(binary_path)?;
if self.enforce_sandbox {
self.check_sandbox_constraints(binary_path)?;
}
Ok(())
}
fn validate_metadata(&self, metadata: &PluginMetadata) -> ValidationResult {
if metadata.name.is_empty() {
return Err(ValidationError::InvalidMetadata("name is required".into()));
}
if metadata.version.is_empty() {
return Err(ValidationError::InvalidMetadata(
"version is required".into(),
));
}
Ok(())
}
fn verify_signature(&self, _binary_path: &Path) -> ValidationResult {
Ok(())
}
fn check_platform_compatibility(&self, _metadata: &PluginMetadata) -> ValidationResult {
Ok(())
}
fn validate_resources(&self, _binary_path: &Path) -> ValidationResult {
Ok(())
}
fn check_sandbox_constraints(&self, _binary_path: &Path) -> ValidationResult {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
fn create_test_metadata() -> PluginMetadata {
PluginMetadata {
name: "test-plugin".to_string(),
version: "1.0.0".to_string(),
description: "Test Plugin".to_string(),
author: "Test Author".to_string(),
min_vanguard_version: Some("0.1.0".to_string()),
max_vanguard_version: Some("2.0.0".to_string()),
dependencies: vec![],
}
}
#[tokio::test]
async fn test_validator_configuration() {
let validator = PluginValidator::new()
.with_max_memory(50 * 1024 * 1024)
.with_strict_signatures(false)
.with_sandbox(true);
assert_eq!(validator.max_memory, 50 * 1024 * 1024);
assert!(!validator.strict_signatures);
assert!(validator.enforce_sandbox);
}
#[tokio::test]
async fn test_metadata_validation() {
let validator = PluginValidator::new();
let metadata = create_test_metadata();
assert!(validator.validate_metadata(&metadata).is_ok());
let invalid_metadata = PluginMetadata {
name: "".to_string(),
..metadata.clone()
};
assert!(matches!(
validator.validate_metadata(&invalid_metadata),
Err(ValidationError::InvalidMetadata(_))
));
}
#[tokio::test]
async fn test_full_validation() {
let validator = PluginValidator::new();
let metadata = create_test_metadata();
let binary_path = PathBuf::from("test-binary");
let result = validator.validate_plugin(&binary_path, &metadata).await;
assert!(result.is_ok());
}
}