module_registry/
security.rs

1//! Security-related functionality for module registry
2
3use anyhow::Result;
4use std::time::{SystemTime, UNIX_EPOCH};
5
6use crate::constants::*;
7use crate::types::*;
8
9/// Security validator for modules
10pub struct SecurityValidator;
11
12impl SecurityValidator {
13    /// Verify module signature
14    pub fn verify_signature(metadata: &ModuleMetadata) -> Result<bool> {
15        match &metadata.signature {
16            Some(sig) => {
17                // Check if signature is not expired
18                let current_time = SystemTime::now()
19                    .duration_since(UNIX_EPOCH)
20                    .unwrap()
21                    .as_secs();
22                
23                if current_time - sig.timestamp > SIGNATURE_EXPIRY_SECONDS {
24                    return Ok(false);
25                }
26
27                // Verify signature algorithm
28                if sig.algorithm != DEFAULT_SIGNATURE_ALGORITHM {
29                    return Ok(false);
30                }
31
32                // In a real implementation, verify the actual signature
33                // For now, just check that signature exists and is not empty
34                Ok(!sig.signature.is_empty() && !sig.public_key.is_empty())
35            }
36            None => Ok(false), // No signature means not verified
37        }
38    }
39
40    /// Check if module has required permissions
41    pub fn check_permissions(metadata: &ModuleMetadata, required_permission: &str) -> Result<bool> {
42        match required_permission {
43            "filesystem_access" => Ok(metadata.permissions.filesystem_access),
44            "network_access" => Ok(metadata.permissions.network_access),
45            "process_spawn" => Ok(metadata.permissions.process_spawn),
46            "env_access" => Ok(metadata.permissions.env_access),
47            "system_access" => Ok(metadata.permissions.system_access),
48            _ => Ok(false),
49        }
50    }
51
52    /// Check if module passed code review
53    pub fn is_approved(metadata: &ModuleMetadata) -> Result<bool> {
54        Ok(matches!(metadata.review_status, CodeReviewStatus::Approved { .. }))
55    }
56
57    /// Verify supply chain information
58    pub fn verify_supply_chain(metadata: &ModuleMetadata) -> Result<bool> {
59        match &metadata.supply_chain {
60            Some(chain) => {
61                // Verify source URL is valid
62                if chain.source_url.is_empty() {
63                    return Ok(false);
64                }
65
66                // Verify commit hash is not empty
67                if chain.commit_hash.is_empty() {
68                    return Ok(false);
69                }
70
71                // Verify build timestamp is reasonable
72                let current_time = SystemTime::now()
73                    .duration_since(UNIX_EPOCH)
74                    .unwrap()
75                    .as_secs();
76                
77                if chain.build_timestamp > current_time {
78                    return Ok(false);
79                }
80
81                // In a real implementation, verify the verifier signature
82                Ok(true)
83            }
84            None => Ok(false), // No supply chain info means not verified
85        }
86    }
87
88    /// Perform comprehensive security check
89    pub fn comprehensive_check(metadata: &ModuleMetadata) -> SecurityCheckResult {
90        let mut issues = Vec::new();
91        let mut warnings = Vec::new();
92
93        // Check signature
94        match Self::verify_signature(metadata) {
95            Ok(true) => {
96                // Signature is valid
97            }
98            Ok(false) => {
99                issues.push(SecurityIssue {
100                    severity: SecuritySeverity::High,
101                    message: "Module signature verification failed".to_string(),
102                    component: "signature".to_string(),
103                });
104            }
105            Err(e) => {
106                warnings.push(SecurityWarning {
107                    message: format!("Failed to verify signature: {}", e),
108                    component: "signature".to_string(),
109                });
110            }
111        }
112
113        // Check approval status
114        match Self::is_approved(metadata) {
115            Ok(true) => {
116                // Module is approved
117            }
118            Ok(false) => {
119                issues.push(SecurityIssue {
120                    severity: SecuritySeverity::Medium,
121                    message: "Module not approved by code review".to_string(),
122                    component: "review".to_string(),
123                });
124            }
125            Err(e) => {
126                warnings.push(SecurityWarning {
127                    message: format!("Failed to check approval status: {}", e),
128                    component: "review".to_string(),
129                });
130            }
131        }
132
133        // Check supply chain
134        match Self::verify_supply_chain(metadata) {
135            Ok(true) => {
136                // Supply chain is verified
137            }
138            Ok(false) => {
139                issues.push(SecurityIssue {
140                    severity: SecuritySeverity::Medium,
141                    message: "Supply chain verification failed".to_string(),
142                    component: "supply_chain".to_string(),
143                });
144            }
145            Err(e) => {
146                warnings.push(SecurityWarning {
147                    message: format!("Failed to verify supply chain: {}", e),
148                    component: "supply_chain".to_string(),
149                });
150            }
151        }
152
153        // Check permissions
154        if metadata.permissions.system_access && !metadata.sandbox_config.enabled {
155            issues.push(SecurityIssue {
156                severity: SecuritySeverity::High,
157                message: "System access granted without sandboxing".to_string(),
158                component: "permissions".to_string(),
159            });
160        }
161
162        let is_secure = issues.is_empty();
163        let risk_level = Self::calculate_risk_level(&issues);
164
165        SecurityCheckResult {
166            is_secure,
167            risk_level,
168            issues,
169            warnings,
170            check_timestamp: SystemTime::now()
171                .duration_since(UNIX_EPOCH)
172                .unwrap()
173                .as_secs(),
174        }
175    }
176
177    /// Calculate risk level based on security issues
178    fn calculate_risk_level(issues: &[SecurityIssue]) -> SecurityRiskLevel {
179        if issues.iter().any(|i| matches!(i.severity, SecuritySeverity::Critical)) {
180            SecurityRiskLevel::Critical
181        } else if issues.iter().any(|i| matches!(i.severity, SecuritySeverity::High)) {
182            SecurityRiskLevel::High
183        } else if issues.iter().any(|i| matches!(i.severity, SecuritySeverity::Medium)) {
184            SecurityRiskLevel::Medium
185        } else if !issues.is_empty() {
186            SecurityRiskLevel::Low
187        } else {
188            SecurityRiskLevel::None
189        }
190    }
191}
192
193/// Security check result
194#[derive(Debug, Clone)]
195pub struct SecurityCheckResult {
196    pub is_secure: bool,
197    pub risk_level: SecurityRiskLevel,
198    pub issues: Vec<SecurityIssue>,
199    pub warnings: Vec<SecurityWarning>,
200    pub check_timestamp: u64,
201}
202
203/// Security issue severity
204#[derive(Debug, Clone, PartialEq)]
205pub enum SecuritySeverity {
206    Low,
207    Medium,
208    High,
209    Critical,
210}
211
212/// Security risk level
213#[derive(Debug, Clone, PartialEq)]
214pub enum SecurityRiskLevel {
215    None,
216    Low,
217    Medium,
218    High,
219    Critical,
220}
221
222/// Security issue
223#[derive(Debug, Clone)]
224pub struct SecurityIssue {
225    pub severity: SecuritySeverity,
226    pub message: String,
227    pub component: String,
228}
229
230/// Security warning
231#[derive(Debug, Clone)]
232pub struct SecurityWarning {
233    pub message: String,
234    pub component: String,
235}
236
237impl SecurityCheckResult {
238    /// Get a summary of the security check
239    pub fn summary(&self) -> String {
240        format!(
241            "Security check {}: {} issues, {} warnings, risk level: {:?}",
242            if self.is_secure { "PASSED" } else { "FAILED" },
243            self.issues.len(),
244            self.warnings.len(),
245            self.risk_level
246        )
247    }
248
249    /// Check if the result indicates a security risk
250    pub fn has_security_risk(&self) -> bool {
251        matches!(self.risk_level, SecurityRiskLevel::Medium | SecurityRiskLevel::High | SecurityRiskLevel::Critical)
252    }
253
254    /// Get all critical issues
255    pub fn get_critical_issues(&self) -> Vec<&SecurityIssue> {
256        self.issues.iter().filter(|i| matches!(i.severity, SecuritySeverity::Critical)).collect()
257    }
258
259    /// Get all high-severity issues
260    pub fn get_high_severity_issues(&self) -> Vec<&SecurityIssue> {
261        self.issues.iter().filter(|i| matches!(i.severity, SecuritySeverity::High | SecuritySeverity::Critical)).collect()
262    }
263}