use mockforge_plugin_loader::{
generate_ed25519_keypair, sign_plugin_ed25519, LoaderResult, PluginLoaderConfig,
PluginLoaderError, SignatureVerifier,
};
use std::collections::HashMap;
use std::fs;
use tempfile::TempDir;
fn create_test_plugin(dir: &TempDir) -> LoaderResult<()> {
let manifest_content = r#"
[info]
id = "test-plugin"
name = "Test Plugin"
version = "1.0.0"
description = "A test plugin for signature verification"
author = "Test Author"
[capabilities]
http = false
database = false
file_system = false
network = false
"#;
fs::write(dir.path().join("plugin.toml"), manifest_content)
.map_err(|e| PluginLoaderError::fs(format!("Failed to write manifest: {}", e)))?;
Ok(())
}
#[test]
fn test_signature_verification_success() {
let plugin_dir = TempDir::new().unwrap();
create_test_plugin(&plugin_dir).unwrap();
let (private_key, public_key) = generate_ed25519_keypair().unwrap();
let key_id = "test-key";
let signature = sign_plugin_ed25519(plugin_dir.path(), key_id, &private_key).unwrap();
assert!(plugin_dir.path().join("plugin.sig").exists());
assert_eq!(signature.key_id, key_id);
let mut key_data = HashMap::new();
key_data.insert(key_id.to_string(), public_key);
let config = PluginLoaderConfig {
trusted_keys: vec![key_id.to_string()],
key_data,
allow_unsigned: false,
..Default::default()
};
let verifier = SignatureVerifier::new(&config);
let result = verifier.verify_plugin_signature(plugin_dir.path());
assert!(result.is_ok(), "Signature verification should succeed");
}
#[test]
fn test_signature_verification_tampered_manifest() {
let plugin_dir = TempDir::new().unwrap();
create_test_plugin(&plugin_dir).unwrap();
let (private_key, public_key) = generate_ed25519_keypair().unwrap();
let key_id = "test-key";
sign_plugin_ed25519(plugin_dir.path(), key_id, &private_key).unwrap();
let tampered_content = r#"
[info]
id = "malicious-plugin"
name = "Malicious Plugin"
version = "1.0.0"
description = "Tampered plugin"
author = "Attacker"
[capabilities]
http = true
database = true
file_system = true
network = true
"#;
fs::write(plugin_dir.path().join("plugin.toml"), tampered_content).unwrap();
let mut key_data = HashMap::new();
key_data.insert(key_id.to_string(), public_key);
let config = PluginLoaderConfig {
trusted_keys: vec![key_id.to_string()],
key_data,
allow_unsigned: false,
..Default::default()
};
let verifier = SignatureVerifier::new(&config);
let result = verifier.verify_plugin_signature(plugin_dir.path());
assert!(result.is_err(), "Signature verification should fail for tampered manifest");
let error = result.unwrap_err();
assert!(matches!(error, PluginLoaderError::SecurityViolation { .. }));
}
#[test]
fn test_signature_verification_untrusted_key() {
let plugin_dir = TempDir::new().unwrap();
create_test_plugin(&plugin_dir).unwrap();
let (private_key, public_key) = generate_ed25519_keypair().unwrap();
let signing_key_id = "attacker-key";
sign_plugin_ed25519(plugin_dir.path(), signing_key_id, &private_key).unwrap();
let mut key_data = HashMap::new();
key_data.insert(signing_key_id.to_string(), public_key);
let config = PluginLoaderConfig {
trusted_keys: vec!["trusted-key".to_string()], key_data,
allow_unsigned: false,
..Default::default()
};
let verifier = SignatureVerifier::new(&config);
let result = verifier.verify_plugin_signature(plugin_dir.path());
assert!(result.is_err(), "Signature verification should fail for untrusted key");
let error = result.unwrap_err();
assert!(matches!(error, PluginLoaderError::SecurityViolation { .. }));
}
#[test]
fn test_signature_verification_missing_signature() {
let plugin_dir = TempDir::new().unwrap();
create_test_plugin(&plugin_dir).unwrap();
let config = PluginLoaderConfig {
allow_unsigned: false,
..Default::default()
};
let verifier = SignatureVerifier::new(&config);
let result = verifier.verify_plugin_signature(plugin_dir.path());
assert!(result.is_err(), "Signature verification should fail when signature is missing");
let error = result.unwrap_err();
assert!(matches!(error, PluginLoaderError::SecurityViolation { .. }));
}
#[test]
fn test_signature_verification_allow_unsigned() {
let plugin_dir = TempDir::new().unwrap();
create_test_plugin(&plugin_dir).unwrap();
let config = PluginLoaderConfig {
allow_unsigned: true,
..Default::default()
};
let verifier = SignatureVerifier::new(&config);
let result = verifier.verify_plugin_signature(plugin_dir.path());
assert!(result.is_ok(), "Verification should succeed when unsigned plugins are allowed");
}
#[test]
fn test_signature_verification_missing_public_key_data() {
let plugin_dir = TempDir::new().unwrap();
create_test_plugin(&plugin_dir).unwrap();
let (private_key, _public_key) = generate_ed25519_keypair().unwrap();
let key_id = "test-key";
sign_plugin_ed25519(plugin_dir.path(), key_id, &private_key).unwrap();
let config = PluginLoaderConfig {
trusted_keys: vec![key_id.to_string()],
key_data: HashMap::new(), allow_unsigned: false,
..Default::default()
};
let verifier = SignatureVerifier::new(&config);
let result = verifier.verify_plugin_signature(plugin_dir.path());
assert!(result.is_err(), "Verification should fail when public key data is missing");
let error = result.unwrap_err();
assert!(matches!(error, PluginLoaderError::SecurityViolation { .. }));
}
#[test]
fn test_signature_verification_wrong_public_key() {
let plugin_dir = TempDir::new().unwrap();
create_test_plugin(&plugin_dir).unwrap();
let (private_key1, _public_key1) = generate_ed25519_keypair().unwrap();
let (_private_key2, public_key2) = generate_ed25519_keypair().unwrap();
let key_id = "test-key";
sign_plugin_ed25519(plugin_dir.path(), key_id, &private_key1).unwrap();
let mut key_data = HashMap::new();
key_data.insert(key_id.to_string(), public_key2);
let config = PluginLoaderConfig {
trusted_keys: vec![key_id.to_string()],
key_data,
allow_unsigned: false,
..Default::default()
};
let verifier = SignatureVerifier::new(&config);
let result = verifier.verify_plugin_signature(plugin_dir.path());
assert!(result.is_err(), "Verification should fail with wrong public key");
let error = result.unwrap_err();
assert!(matches!(error, PluginLoaderError::SecurityViolation { .. }));
}