sklears_core/plugin/
validation.rs

1//! Plugin Validation Framework
2//!
3//! This module provides comprehensive validation capabilities for plugins,
4//! including security analysis, dependency checking, code safety validation,
5//! and trust verification. It ensures that plugins meet security and
6//! quality standards before being loaded and executed.
7
8use super::core_traits::Plugin;
9use super::security::{DigitalSignature, Permission, PublisherInfo, SecurityPolicy};
10use super::types_config::PluginMetadata;
11use crate::error::Result;
12use std::collections::HashMap;
13
14/// Advanced plugin validation framework with security analysis
15///
16/// The PluginValidator provides comprehensive validation of plugins including
17/// metadata validation, security analysis, dependency checking, code safety
18/// validation, and trust verification.
19///
20/// # Examples
21///
22/// ```rust,no_run
23/// use sklears_core::plugin::{PluginValidator, PluginManifest};
24///
25/// let validator = PluginValidator::new();
26///
27/// // Validate a plugin comprehensively
28/// // let report = validator.validate_comprehensive(&plugin, &manifest)?;
29/// //
30/// // Check validation results
31/// // if report.has_errors() {
32/// //     println!("Validation failed: {:?}", report.get_errors());
33/// // } else {
34/// //     println!("Plugin validation passed");
35/// // }
36/// # Ok::<(), Box<dyn std::error::Error>>(())
37/// ```
38#[derive(Debug)]
39pub struct PluginValidator {
40    /// Security policy configuration
41    security_policy: SecurityPolicy,
42    /// Dependency resolver for checking dependencies
43    dependency_resolver: DependencyResolver,
44    /// Code analyzer for security checks
45    #[allow(dead_code)]
46    code_analyzer: CodeAnalyzer,
47    /// Trust store for plugin verification
48    trust_store: TrustStore,
49}
50
51impl PluginValidator {
52    /// Create a new plugin validator
53    ///
54    /// Initializes a new validator with default security policies and
55    /// validation components.
56    pub fn new() -> Self {
57        Self {
58            security_policy: SecurityPolicy::default(),
59            dependency_resolver: DependencyResolver::new(),
60            code_analyzer: CodeAnalyzer::new(),
61            trust_store: TrustStore::new(),
62        }
63    }
64
65    /// Create a validator with custom security policy
66    ///
67    /// # Arguments
68    ///
69    /// * `security_policy` - Custom security policy to use
70    pub fn with_security_policy(security_policy: SecurityPolicy) -> Self {
71        Self {
72            security_policy,
73            dependency_resolver: DependencyResolver::new(),
74            code_analyzer: CodeAnalyzer::new(),
75            trust_store: TrustStore::new(),
76        }
77    }
78
79    /// Perform comprehensive plugin validation
80    ///
81    /// This method performs all validation checks including basic metadata
82    /// validation, security analysis, dependency checking, code safety
83    /// validation, and trust verification.
84    ///
85    /// # Arguments
86    ///
87    /// * `plugin` - The plugin to validate
88    /// * `manifest` - The plugin manifest with detailed information
89    ///
90    /// # Returns
91    ///
92    /// A validation report containing all findings, errors, and warnings.
93    pub fn validate_comprehensive(
94        &self,
95        plugin: &dyn Plugin,
96        manifest: &PluginManifest,
97    ) -> Result<ValidationReport> {
98        let mut report = ValidationReport::new();
99
100        // Basic validation
101        self.validate_basic(plugin, &mut report)?;
102
103        // Security validation
104        self.validate_security(manifest, &mut report)?;
105
106        // Dependency validation
107        self.validate_dependencies(manifest, &mut report)?;
108
109        // Code analysis
110        self.validate_code_safety(manifest, &mut report)?;
111
112        // Trust verification
113        self.validate_trust(manifest, &mut report)?;
114
115        Ok(report)
116    }
117
118    /// Validate basic plugin requirements
119    ///
120    /// Performs basic validation of plugin metadata and requirements.
121    fn validate_basic(&self, plugin: &dyn Plugin, report: &mut ValidationReport) -> Result<()> {
122        let metadata = plugin.metadata();
123
124        if metadata.name.is_empty() {
125            report.add_error(ValidationError::InvalidMetadata(
126                "Plugin name cannot be empty".to_string(),
127            ));
128        }
129
130        if metadata.version.is_empty() {
131            report.add_error(ValidationError::InvalidMetadata(
132                "Plugin version cannot be empty".to_string(),
133            ));
134        }
135
136        if metadata.author.is_empty() {
137            report.add_error(ValidationError::InvalidMetadata(
138                "Plugin author cannot be empty".to_string(),
139            ));
140        }
141
142        // Validate version format
143        if !self.is_valid_version(&metadata.version) {
144            report.add_error(ValidationError::InvalidVersion(metadata.version.clone()));
145        }
146
147        // Check required SDK version compatibility
148        if !self.is_compatible_sdk_version(&metadata.min_sdk_version) {
149            report.add_error(ValidationError::IncompatibleSdkVersion(
150                metadata.min_sdk_version.clone(),
151            ));
152        }
153
154        report.add_check(ValidationCheck::BasicMetadata, ValidationResult::Passed);
155        Ok(())
156    }
157
158    /// Validate security requirements
159    ///
160    /// Performs security validation including permission checks, API usage
161    /// validation, and unsafe code detection.
162    fn validate_security(
163        &self,
164        manifest: &PluginManifest,
165        report: &mut ValidationReport,
166    ) -> Result<()> {
167        // Check for dangerous permissions
168        for permission in &manifest.permissions {
169            if self.security_policy.is_dangerous_permission(permission) {
170                report.add_warning(ValidationWarning::DangerousPermission(permission.clone()));
171            }
172        }
173
174        // Validate API usage patterns
175        if let Some(ref api_usage) = manifest.api_usage {
176            for api_call in &api_usage.calls {
177                if self.security_policy.is_restricted_api(api_call) {
178                    report.add_error(ValidationError::RestrictedApiUsage(api_call.clone()));
179                }
180            }
181        }
182
183        // Check for unsafe code blocks
184        if manifest.contains_unsafe_code {
185            if !self.security_policy.allow_unsafe_code {
186                report.add_error(ValidationError::UnsafeCodeNotAllowed);
187            } else {
188                report.add_warning(ValidationWarning::UnsafeCodeDetected);
189            }
190        }
191
192        report.add_check(ValidationCheck::Security, ValidationResult::Passed);
193        Ok(())
194    }
195
196    /// Validate plugin dependencies
197    ///
198    /// Checks that all required dependencies are available, compatible,
199    /// and free from known vulnerabilities.
200    fn validate_dependencies(
201        &self,
202        manifest: &PluginManifest,
203        report: &mut ValidationReport,
204    ) -> Result<()> {
205        for dependency in &manifest.dependencies {
206            // Check if dependency is available
207            if !self.dependency_resolver.is_available(dependency) {
208                report.add_error(ValidationError::MissingDependency(dependency.clone()));
209                continue;
210            }
211
212            // Check version compatibility
213            if !self.dependency_resolver.is_compatible_version(dependency) {
214                report.add_error(ValidationError::IncompatibleDependency(dependency.clone()));
215                continue;
216            }
217
218            // Check for known vulnerabilities
219            if let Some(vulnerabilities) =
220                self.dependency_resolver.check_vulnerabilities(dependency)
221            {
222                for vuln in vulnerabilities {
223                    report.add_error(ValidationError::VulnerableDependency(
224                        dependency.clone(),
225                        vuln,
226                    ));
227                }
228            }
229        }
230
231        report.add_check(ValidationCheck::Dependencies, ValidationResult::Passed);
232        Ok(())
233    }
234
235    /// Validate code safety
236    ///
237    /// Performs static analysis of the plugin code to identify potential
238    /// safety issues, suspicious patterns, and complexity problems.
239    fn validate_code_safety(
240        &self,
241        manifest: &PluginManifest,
242        report: &mut ValidationReport,
243    ) -> Result<()> {
244        if let Some(ref code_info) = manifest.code_analysis {
245            // Check complexity metrics
246            if code_info.cyclomatic_complexity > self.security_policy.max_complexity as usize {
247                report.add_warning(ValidationWarning::HighComplexity(
248                    code_info.cyclomatic_complexity,
249                ));
250            }
251
252            // Check for suspicious patterns
253            for pattern in &code_info.suspicious_patterns {
254                report.add_warning(ValidationWarning::SuspiciousPattern(pattern.clone()));
255            }
256
257            // Memory safety checks
258            if code_info.potential_memory_issues > 0 {
259                report.add_error(ValidationError::MemorySafetyIssue(
260                    code_info.potential_memory_issues,
261                ));
262            }
263        }
264
265        report.add_check(ValidationCheck::CodeSafety, ValidationResult::Passed);
266        Ok(())
267    }
268
269    /// Validate trust and signatures
270    ///
271    /// Verifies digital signatures and checks publisher trust levels.
272    fn validate_trust(
273        &self,
274        manifest: &PluginManifest,
275        report: &mut ValidationReport,
276    ) -> Result<()> {
277        // Verify digital signature
278        if let Some(ref signature) = manifest.signature {
279            match self
280                .trust_store
281                .verify_signature(&manifest.content_hash, signature)
282            {
283                Ok(true) => report.add_check(ValidationCheck::Signature, ValidationResult::Passed),
284                Ok(false) => report.add_error(ValidationError::InvalidSignature),
285                Err(e) => {
286                    report.add_error(ValidationError::SignatureVerificationFailed(e.to_string()))
287                }
288            }
289        } else if self.security_policy.require_signatures {
290            report.add_error(ValidationError::MissingSignature);
291        }
292
293        // Check publisher trust level
294        let trust_level = self.trust_store.get_publisher_trust(&manifest.publisher);
295        if trust_level < self.security_policy.min_trust_level as f32 {
296            report.add_warning(ValidationWarning::LowTrustPublisher(trust_level));
297        }
298
299        report.add_check(ValidationCheck::Trust, ValidationResult::Passed);
300        Ok(())
301    }
302
303    /// Check if version string is valid semver
304    fn is_valid_version(&self, version: &str) -> bool {
305        let parts: Vec<&str> = version.split('.').collect();
306        parts.len() >= 2 && parts.len() <= 3 && parts.iter().all(|p| p.parse::<u32>().is_ok())
307    }
308
309    /// Check if SDK version is compatible
310    fn is_compatible_sdk_version(&self, min_version: &str) -> bool {
311        // Simplified version check - in practice, you'd use a proper semver library
312        // For now, assume compatibility
313        !min_version.is_empty()
314    }
315}
316
317impl Default for PluginValidator {
318    fn default() -> Self {
319        Self::new()
320    }
321}
322
323/// Enhanced plugin manifest with marketplace information
324///
325/// Contains comprehensive information about a plugin including metadata,
326/// security information, dependencies, and marketplace data.
327#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
328pub struct PluginManifest {
329    /// Basic plugin metadata
330    pub metadata: PluginMetadata,
331    /// Plugin permissions required
332    pub permissions: Vec<Permission>,
333    /// API usage information
334    pub api_usage: Option<ApiUsageInfo>,
335    /// Whether plugin contains unsafe code
336    pub contains_unsafe_code: bool,
337    /// Plugin dependencies with versions
338    pub dependencies: Vec<Dependency>,
339    /// Code analysis results
340    pub code_analysis: Option<CodeAnalysisInfo>,
341    /// Digital signature for verification
342    pub signature: Option<DigitalSignature>,
343    /// Content hash for integrity verification
344    pub content_hash: String,
345    /// Publisher information
346    pub publisher: PublisherInfo,
347    /// Marketplace specific metadata
348    pub marketplace: MarketplaceInfo,
349}
350
351/// Validation report containing all validation results
352#[derive(Debug, Clone)]
353pub struct ValidationReport {
354    /// Validation errors that prevent plugin usage
355    pub errors: Vec<ValidationError>,
356    /// Validation warnings that should be noted but don't prevent usage
357    pub warnings: Vec<ValidationWarning>,
358    /// Completed validation checks
359    pub checks: HashMap<ValidationCheck, ValidationResult>,
360    /// Overall validation status
361    pub status: ValidationStatus,
362}
363
364impl ValidationReport {
365    /// Create a new empty validation report
366    pub fn new() -> Self {
367        Self {
368            errors: Vec::new(),
369            warnings: Vec::new(),
370            checks: HashMap::new(),
371            status: ValidationStatus::Pending,
372        }
373    }
374
375    /// Add a validation error
376    pub fn add_error(&mut self, error: ValidationError) {
377        self.errors.push(error);
378        self.status = ValidationStatus::Failed;
379    }
380
381    /// Add a validation warning
382    pub fn add_warning(&mut self, warning: ValidationWarning) {
383        self.warnings.push(warning);
384    }
385
386    /// Add a completed validation check
387    pub fn add_check(&mut self, check: ValidationCheck, result: ValidationResult) {
388        self.checks.insert(check, result);
389        if self.status == ValidationStatus::Pending && self.errors.is_empty() {
390            self.status = ValidationStatus::Passed;
391        }
392    }
393
394    /// Check if validation has errors
395    pub fn has_errors(&self) -> bool {
396        !self.errors.is_empty()
397    }
398
399    /// Check if validation has warnings
400    pub fn has_warnings(&self) -> bool {
401        !self.warnings.is_empty()
402    }
403
404    /// Get all validation errors
405    pub fn get_errors(&self) -> &[ValidationError] {
406        &self.errors
407    }
408
409    /// Get all validation warnings
410    pub fn get_warnings(&self) -> &[ValidationWarning] {
411        &self.warnings
412    }
413
414    /// Get validation status
415    pub fn status(&self) -> ValidationStatus {
416        self.status
417    }
418
419    /// Get completed checks
420    pub fn get_checks(&self) -> &HashMap<ValidationCheck, ValidationResult> {
421        &self.checks
422    }
423}
424
425/// Validation errors that prevent plugin usage
426#[derive(Debug, Clone)]
427pub enum ValidationError {
428    /// Invalid metadata
429    InvalidMetadata(String),
430    /// Invalid version format
431    InvalidVersion(String),
432    /// Incompatible SDK version
433    IncompatibleSdkVersion(String),
434    /// Missing required dependency
435    MissingDependency(Dependency),
436    /// Incompatible dependency version
437    IncompatibleDependency(Dependency),
438    /// Vulnerable dependency detected
439    VulnerableDependency(Dependency, String),
440    /// Restricted API usage detected
441    RestrictedApiUsage(String),
442    /// Unsafe code not allowed
443    UnsafeCodeNotAllowed,
444    /// Memory safety issue detected
445    MemorySafetyIssue(usize),
446    /// Invalid digital signature
447    InvalidSignature,
448    /// Missing required signature
449    MissingSignature,
450    /// Signature verification failed
451    SignatureVerificationFailed(String),
452}
453
454/// Validation warnings that should be noted but don't prevent usage
455#[derive(Debug, Clone)]
456pub enum ValidationWarning {
457    /// Dangerous permission requested
458    DangerousPermission(Permission),
459    /// Unsafe code detected
460    UnsafeCodeDetected,
461    /// High code complexity
462    HighComplexity(usize),
463    /// Suspicious code pattern detected
464    SuspiciousPattern(String),
465    /// Low trust publisher
466    LowTrustPublisher(f32),
467}
468
469/// Types of validation checks
470#[derive(Debug, Clone, PartialEq, Eq, Hash)]
471pub enum ValidationCheck {
472    /// Basic metadata validation
473    BasicMetadata,
474    /// Security validation
475    Security,
476    /// Dependency validation
477    Dependencies,
478    /// Code safety validation
479    CodeSafety,
480    /// Trust and signature validation
481    Trust,
482    /// Digital signature verification
483    Signature,
484}
485
486/// Validation check results
487#[derive(Debug, Clone, PartialEq, Eq)]
488pub enum ValidationResult {
489    /// Check passed successfully
490    Passed,
491    /// Check failed
492    Failed,
493    /// Check was skipped
494    Skipped,
495}
496
497/// Overall validation status
498#[derive(Debug, Clone, Copy, PartialEq, Eq)]
499pub enum ValidationStatus {
500    /// Validation is pending
501    Pending,
502    /// Validation passed
503    Passed,
504    /// Validation failed
505    Failed,
506}
507
508/// Security vulnerability information
509#[derive(Debug, Clone)]
510pub struct Vulnerability {
511    /// Vulnerability ID (e.g., CVE number)
512    pub id: String,
513    /// Severity level
514    pub severity: VulnerabilitySeverity,
515    /// Description of the vulnerability
516    pub description: String,
517    /// Affected versions
518    pub affected_versions: Vec<String>,
519}
520
521/// Vulnerability severity levels
522#[derive(Debug, Clone, PartialEq, Eq)]
523pub enum VulnerabilitySeverity {
524    Low,
525    Medium,
526    High,
527    Critical,
528}
529
530/// API usage information for security analysis
531#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
532pub struct ApiUsageInfo {
533    /// API calls made by the plugin
534    pub calls: Vec<String>,
535    /// Network access patterns
536    pub network_access: Vec<String>,
537    /// File system access patterns
538    pub filesystem_access: Vec<String>,
539}
540
541/// Code analysis information
542#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
543pub struct CodeAnalysisInfo {
544    /// Cyclomatic complexity score
545    pub cyclomatic_complexity: usize,
546    /// Suspicious patterns detected
547    pub suspicious_patterns: Vec<String>,
548    /// Potential memory issues count
549    pub potential_memory_issues: usize,
550    /// Lines of code
551    pub lines_of_code: usize,
552    /// Test coverage percentage
553    pub test_coverage: f32,
554}
555
556/// Dependency specification
557#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
558pub struct Dependency {
559    /// Dependency name
560    pub name: String,
561    /// Version requirement
562    pub version: String,
563    /// Whether dependency is optional
564    pub optional: bool,
565    /// Features required from the dependency
566    pub features: Vec<String>,
567}
568
569/// Marketplace information
570#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
571pub struct MarketplaceInfo {
572    /// Plugin URL on marketplace
573    pub url: String,
574    /// Download count
575    pub downloads: u64,
576    /// User rating (0.0 to 5.0)
577    pub rating: f32,
578    /// Number of reviews
579    pub reviews: u32,
580    /// Last update timestamp
581    pub last_updated: String,
582}
583
584/// Dependency resolver for checking plugin dependencies
585#[derive(Debug)]
586pub struct DependencyResolver {
587    /// Available dependencies
588    available_deps: HashMap<String, String>,
589}
590
591impl Default for DependencyResolver {
592    fn default() -> Self {
593        Self::new()
594    }
595}
596
597impl DependencyResolver {
598    /// Create a new dependency resolver
599    pub fn new() -> Self {
600        Self {
601            available_deps: HashMap::new(),
602        }
603    }
604
605    /// Check if a dependency is available
606    pub fn is_available(&self, dependency: &Dependency) -> bool {
607        self.available_deps.contains_key(&dependency.name)
608    }
609
610    /// Check if dependency version is compatible
611    pub fn is_compatible_version(&self, _dependency: &Dependency) -> bool {
612        // Simplified version check
613        true
614    }
615
616    /// Check for known vulnerabilities
617    pub fn check_vulnerabilities(&self, _dependency: &Dependency) -> Option<Vec<String>> {
618        // Placeholder - would integrate with vulnerability databases
619        None
620    }
621}
622
623/// Code analyzer for security checks
624#[derive(Debug)]
625pub struct CodeAnalyzer {
626    /// Analysis rules
627    #[allow(dead_code)]
628    rules: Vec<AnalysisRule>,
629}
630
631impl Default for CodeAnalyzer {
632    fn default() -> Self {
633        Self::new()
634    }
635}
636
637impl CodeAnalyzer {
638    /// Create a new code analyzer
639    pub fn new() -> Self {
640        Self { rules: Vec::new() }
641    }
642}
643
644/// Trust store for plugin verification
645#[derive(Debug)]
646pub struct TrustStore {
647    /// Trusted publishers
648    trusted_publishers: HashMap<String, f32>,
649}
650
651impl Default for TrustStore {
652    fn default() -> Self {
653        Self::new()
654    }
655}
656
657impl TrustStore {
658    /// Create a new trust store
659    pub fn new() -> Self {
660        Self {
661            trusted_publishers: HashMap::new(),
662        }
663    }
664
665    /// Verify a digital signature
666    pub fn verify_signature(
667        &self,
668        _content_hash: &str,
669        _signature: &DigitalSignature,
670    ) -> Result<bool> {
671        // Placeholder - would implement actual signature verification
672        Ok(true)
673    }
674
675    /// Get publisher trust level
676    pub fn get_publisher_trust(&self, publisher: &PublisherInfo) -> f32 {
677        self.trusted_publishers
678            .get(&publisher.name)
679            .copied()
680            .unwrap_or(0.5)
681    }
682}
683
684/// Analysis rule for code validation
685#[derive(Debug, Clone)]
686pub struct AnalysisRule {
687    /// Rule name
688    pub name: String,
689    /// Rule description
690    pub description: String,
691    /// Rule pattern
692    pub pattern: String,
693}
694
695impl Default for ValidationReport {
696    fn default() -> Self {
697        Self::new()
698    }
699}