sklears_core/plugin/security.rs
1//! Plugin Security Framework
2//!
3//! This module provides comprehensive security infrastructure for the plugin system,
4//! including permission management, digital signatures, trust policies, and
5//! security validation frameworks.
6
7use crate::error::Result;
8use std::collections::HashMap;
9
10/// Security policy configuration for the plugin system
11///
12/// The SecurityPolicy defines the security requirements and restrictions
13/// for plugin validation and execution. It provides configurable security
14/// levels to balance functionality with safety requirements.
15///
16/// # Security Levels
17///
18/// - **Strict**: Maximum security with signature requirements and minimal permissions
19/// - **Standard**: Balanced security for production environments
20/// - **Permissive**: Relaxed security for development and testing
21///
22/// # Examples
23///
24/// ```rust
25/// use sklears_core::plugin::{SecurityPolicy, Permission};
26///
27/// // Create a strict security policy
28/// let strict_policy = SecurityPolicy::strict();
29/// assert!(strict_policy.require_signatures);
30/// assert!(!strict_policy.allow_unsafe_code);
31///
32/// // Create a custom policy
33/// let custom_policy = SecurityPolicy {
34/// allow_unsafe_code: false,
35/// require_signatures: true,
36/// min_trust_level: 7,
37/// max_complexity: 15,
38/// dangerous_permissions: vec![
39/// "file_system_write".to_string(),
40/// "network_access".to_string(),
41/// ],
42/// restricted_apis: vec![
43/// "std::process::Command".to_string(),
44/// ],
45/// };
46/// ```
47#[derive(Debug, Clone)]
48pub struct SecurityPolicy {
49 /// Whether to allow plugins with unsafe code blocks
50 pub allow_unsafe_code: bool,
51 /// Whether digital signatures are required for plugins
52 pub require_signatures: bool,
53 /// Minimum trust level required for plugin publishers (0-10)
54 pub min_trust_level: u8,
55 /// Maximum allowed cyclomatic complexity for plugin code
56 pub max_complexity: u32,
57 /// List of dangerous permissions that trigger warnings
58 pub dangerous_permissions: Vec<String>,
59 /// List of restricted API patterns that are not allowed
60 pub restricted_apis: Vec<String>,
61}
62
63impl SecurityPolicy {
64 /// Create a strict security policy suitable for production environments
65 ///
66 /// This policy provides maximum security with signature requirements,
67 /// no unsafe code, and minimal dangerous permissions.
68 ///
69 /// # Examples
70 ///
71 /// ```rust
72 /// use sklears_core::plugin::SecurityPolicy;
73 ///
74 /// let policy = SecurityPolicy::strict();
75 /// assert!(policy.require_signatures);
76 /// assert!(!policy.allow_unsafe_code);
77 /// assert_eq!(policy.min_trust_level, 8);
78 /// ```
79 pub fn strict() -> Self {
80 Self {
81 allow_unsafe_code: false,
82 require_signatures: true,
83 min_trust_level: 8,
84 max_complexity: 10,
85 dangerous_permissions: vec![
86 "file_system_write".to_string(),
87 "file_system_delete".to_string(),
88 "network_access".to_string(),
89 "system_commands".to_string(),
90 "environment_variables".to_string(),
91 "process_spawn".to_string(),
92 ],
93 restricted_apis: vec![
94 "std::process::Command".to_string(),
95 "std::fs::remove_file".to_string(),
96 "std::fs::remove_dir".to_string(),
97 "std::env::set_var".to_string(),
98 "libc::system".to_string(),
99 ],
100 }
101 }
102
103 /// Create a standard security policy for typical production use
104 ///
105 /// Balances security with functionality, allowing more flexibility
106 /// than strict mode while maintaining essential protections.
107 ///
108 /// # Examples
109 ///
110 /// ```rust
111 /// use sklears_core::plugin::SecurityPolicy;
112 ///
113 /// let policy = SecurityPolicy::standard();
114 /// assert!(policy.require_signatures);
115 /// assert!(!policy.allow_unsafe_code);
116 /// assert_eq!(policy.min_trust_level, 5);
117 /// ```
118 pub fn standard() -> Self {
119 Self {
120 allow_unsafe_code: false,
121 require_signatures: true,
122 min_trust_level: 5,
123 max_complexity: 20,
124 dangerous_permissions: vec![
125 "file_system_write".to_string(),
126 "network_access".to_string(),
127 "system_commands".to_string(),
128 ],
129 restricted_apis: vec![
130 "std::process::Command".to_string(),
131 "std::fs::remove_file".to_string(),
132 ],
133 }
134 }
135
136 /// Create a permissive security policy for development and testing
137 ///
138 /// Provides minimal security restrictions to enable rapid development
139 /// and testing. Should not be used in production environments.
140 ///
141 /// # Examples
142 ///
143 /// ```rust
144 /// use sklears_core::plugin::SecurityPolicy;
145 ///
146 /// let policy = SecurityPolicy::permissive();
147 /// assert!(!policy.require_signatures);
148 /// assert!(policy.allow_unsafe_code);
149 /// assert_eq!(policy.min_trust_level, 0);
150 /// ```
151 pub fn permissive() -> Self {
152 Self {
153 allow_unsafe_code: true,
154 require_signatures: false,
155 min_trust_level: 0,
156 max_complexity: 100,
157 dangerous_permissions: vec!["system_commands".to_string()],
158 restricted_apis: vec![],
159 }
160 }
161
162 /// Check if a permission is considered dangerous
163 ///
164 /// Dangerous permissions are those that could potentially be used
165 /// maliciously or cause system damage if misused.
166 ///
167 /// # Arguments
168 ///
169 /// * `permission` - The permission to check
170 ///
171 /// # Returns
172 ///
173 /// true if the permission is considered dangerous, false otherwise.
174 ///
175 /// # Examples
176 ///
177 /// ```rust
178 /// use sklears_core::plugin::{SecurityPolicy, Permission};
179 ///
180 /// let policy = SecurityPolicy::standard();
181 /// assert!(policy.is_dangerous_permission(&Permission::FileSystemWrite));
182 /// assert!(!policy.is_dangerous_permission(&Permission::FileSystemRead));
183 /// ```
184 pub fn is_dangerous_permission(&self, permission: &Permission) -> bool {
185 match permission {
186 Permission::FileSystemWrite => true,
187 Permission::FileSystemDelete => true,
188 Permission::NetworkAccess => self
189 .dangerous_permissions
190 .contains(&"network_access".to_string()),
191 Permission::SystemCommands => true,
192 Permission::ProcessSpawn => true,
193 Permission::EnvironmentVariables => self
194 .dangerous_permissions
195 .contains(&"environment_variables".to_string()),
196 Permission::Custom(name) => self.dangerous_permissions.contains(name),
197 _ => false,
198 }
199 }
200
201 /// Check if an API call is restricted
202 ///
203 /// Restricted APIs are those that are prohibited from use in plugins
204 /// due to security concerns or system stability issues.
205 ///
206 /// # Arguments
207 ///
208 /// * `api` - The API call pattern to check
209 ///
210 /// # Returns
211 ///
212 /// true if the API is restricted, false otherwise.
213 ///
214 /// # Examples
215 ///
216 /// ```rust
217 /// use sklears_core::plugin::SecurityPolicy;
218 ///
219 /// let policy = SecurityPolicy::standard();
220 /// assert!(policy.is_restricted_api("std::process::Command"));
221 /// assert!(!policy.is_restricted_api("std::fs::read_to_string"));
222 /// ```
223 pub fn is_restricted_api(&self, api: &str) -> bool {
224 self.restricted_apis
225 .iter()
226 .any(|restricted| api.contains(restricted) || api.starts_with(restricted))
227 }
228
229 /// Add a dangerous permission to the policy
230 ///
231 /// # Arguments
232 ///
233 /// * `permission` - The permission name to add as dangerous
234 pub fn add_dangerous_permission(&mut self, permission: String) {
235 if !self.dangerous_permissions.contains(&permission) {
236 self.dangerous_permissions.push(permission);
237 }
238 }
239
240 /// Remove a dangerous permission from the policy
241 ///
242 /// # Arguments
243 ///
244 /// * `permission` - The permission name to remove from dangerous list
245 pub fn remove_dangerous_permission(&mut self, permission: &str) {
246 self.dangerous_permissions.retain(|p| p != permission);
247 }
248
249 /// Add a restricted API pattern to the policy
250 ///
251 /// # Arguments
252 ///
253 /// * `api_pattern` - The API pattern to restrict
254 pub fn add_restricted_api(&mut self, api_pattern: String) {
255 if !self.restricted_apis.contains(&api_pattern) {
256 self.restricted_apis.push(api_pattern);
257 }
258 }
259
260 /// Remove a restricted API pattern from the policy
261 ///
262 /// # Arguments
263 ///
264 /// * `api_pattern` - The API pattern to remove from restrictions
265 pub fn remove_restricted_api(&mut self, api_pattern: &str) {
266 self.restricted_apis.retain(|p| p != api_pattern);
267 }
268
269 /// Validate the policy configuration
270 ///
271 /// Ensures that the policy configuration is consistent and valid.
272 ///
273 /// # Returns
274 ///
275 /// Ok(()) if the policy is valid, error otherwise.
276 pub fn validate(&self) -> Result<()> {
277 if self.min_trust_level > 10 {
278 return Err(crate::error::SklearsError::InvalidOperation(
279 "Trust level must be between 0 and 10".to_string(),
280 ));
281 }
282
283 if self.max_complexity == 0 {
284 return Err(crate::error::SklearsError::InvalidOperation(
285 "Maximum complexity must be greater than 0".to_string(),
286 ));
287 }
288
289 Ok(())
290 }
291}
292
293impl Default for SecurityPolicy {
294 fn default() -> Self {
295 Self::standard()
296 }
297}
298
299/// Plugin permission types
300///
301/// Permissions define what system resources and capabilities a plugin
302/// requires to function. They are used for security validation and
303/// user consent workflows.
304///
305/// # Permission Categories
306///
307/// - **File System**: Read, write, and delete file operations
308/// - **Network**: Internet and local network access
309/// - **System**: Process execution and system command access
310/// - **Hardware**: GPU and specialized hardware access
311/// - **Environment**: Access to environment variables and system settings
312///
313/// # Examples
314///
315/// ```rust
316/// use sklears_core::plugin::Permission;
317///
318/// // Standard permissions
319/// let read_perm = Permission::FileSystemRead;
320/// let write_perm = Permission::FileSystemWrite;
321/// let network_perm = Permission::NetworkAccess;
322///
323/// // Custom permission
324/// let custom_perm = Permission::Custom("database_access".to_string());
325/// ```
326#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
327pub enum Permission {
328 /// Read access to file system
329 FileSystemRead,
330 /// Write access to file system
331 FileSystemWrite,
332 /// Delete access to file system
333 FileSystemDelete,
334 /// Access to network resources
335 NetworkAccess,
336 /// Execute system commands
337 SystemCommands,
338 /// Spawn new processes
339 ProcessSpawn,
340 /// Access to GPU resources
341 GpuAccess,
342 /// Access to environment variables
343 EnvironmentVariables,
344 /// Access to system configuration
345 SystemConfiguration,
346 /// Custom permission with user-defined name
347 Custom(String),
348}
349
350impl Permission {
351 /// Get a human-readable description of the permission
352 ///
353 /// # Returns
354 ///
355 /// A string describing what this permission allows.
356 ///
357 /// # Examples
358 ///
359 /// ```rust
360 /// use sklears_core::plugin::Permission;
361 ///
362 /// let perm = Permission::FileSystemWrite;
363 /// assert_eq!(perm.description(), "Write access to file system");
364 /// ```
365 pub fn description(&self) -> &'static str {
366 match self {
367 Permission::FileSystemRead => "Read access to file system",
368 Permission::FileSystemWrite => "Write access to file system",
369 Permission::FileSystemDelete => "Delete access to file system",
370 Permission::NetworkAccess => "Access to network resources",
371 Permission::SystemCommands => "Execute system commands",
372 Permission::ProcessSpawn => "Spawn new processes",
373 Permission::GpuAccess => "Access to GPU resources",
374 Permission::EnvironmentVariables => "Access to environment variables",
375 Permission::SystemConfiguration => "Access to system configuration",
376 Permission::Custom(_) => "Custom permission",
377 }
378 }
379
380 /// Get the risk level of this permission
381 ///
382 /// # Returns
383 ///
384 /// Risk level from 1 (low) to 5 (high).
385 ///
386 /// # Examples
387 ///
388 /// ```rust
389 /// use sklears_core::plugin::Permission;
390 ///
391 /// assert_eq!(Permission::FileSystemRead.risk_level(), 2);
392 /// assert_eq!(Permission::SystemCommands.risk_level(), 5);
393 /// ```
394 pub fn risk_level(&self) -> u8 {
395 match self {
396 Permission::FileSystemRead => 2,
397 Permission::GpuAccess => 2,
398 Permission::FileSystemWrite => 3,
399 Permission::NetworkAccess => 3,
400 Permission::EnvironmentVariables => 3,
401 Permission::FileSystemDelete => 4,
402 Permission::SystemConfiguration => 4,
403 Permission::ProcessSpawn => 5,
404 Permission::SystemCommands => 5,
405 Permission::Custom(_) => 3, // Default to medium risk
406 }
407 }
408
409 /// Check if this permission requires user consent
410 ///
411 /// # Returns
412 ///
413 /// true if user consent is required, false otherwise.
414 pub fn requires_user_consent(&self) -> bool {
415 self.risk_level() >= 3
416 }
417
418 /// Get all standard permissions
419 ///
420 /// # Returns
421 ///
422 /// A vector of all predefined permission types.
423 pub fn all_standard() -> Vec<Permission> {
424 vec![
425 Permission::FileSystemRead,
426 Permission::FileSystemWrite,
427 Permission::FileSystemDelete,
428 Permission::NetworkAccess,
429 Permission::SystemCommands,
430 Permission::ProcessSpawn,
431 Permission::GpuAccess,
432 Permission::EnvironmentVariables,
433 Permission::SystemConfiguration,
434 ]
435 }
436}
437
438/// Digital signature for plugin verification
439///
440/// Digital signatures provide cryptographic verification of plugin integrity
441/// and authenticity. They ensure that plugins have not been tampered with
442/// and come from trusted sources.
443///
444/// # Supported Algorithms
445///
446/// - RSA-SHA256: Standard RSA signature with SHA-256 hashing
447/// - ECDSA-P256: Elliptic curve signature with P-256 curve
448/// - Ed25519: Edwards curve signature algorithm
449///
450/// # Examples
451///
452/// ```rust
453/// use sklears_core::plugin::DigitalSignature;
454///
455/// let signature = DigitalSignature {
456/// algorithm: "RSA-SHA256".to_string(),
457/// signature: vec![0x12, 0x34, 0x56, 0x78],
458/// public_key_fingerprint: "SHA256:abc123def456".to_string(),
459/// timestamp: std::time::SystemTime::now(),
460/// signer_certificate: Some("-----BEGIN CERTIFICATE-----\n...".to_string()),
461/// };
462/// ```
463#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
464pub struct DigitalSignature {
465 /// Signature algorithm used (e.g., "RSA-SHA256", "ECDSA-P256", "Ed25519")
466 pub algorithm: String,
467 /// The actual signature bytes
468 pub signature: Vec<u8>,
469 /// Fingerprint of the public key used for verification
470 pub public_key_fingerprint: String,
471 /// Timestamp when the signature was created
472 pub timestamp: std::time::SystemTime,
473 /// Optional signer certificate in PEM format
474 pub signer_certificate: Option<String>,
475}
476
477impl DigitalSignature {
478 /// Create a new digital signature
479 ///
480 /// # Arguments
481 ///
482 /// * `algorithm` - The signature algorithm used
483 /// * `signature` - The signature bytes
484 /// * `public_key_fingerprint` - Fingerprint of the signing key
485 ///
486 /// # Examples
487 ///
488 /// ```rust
489 /// use sklears_core::plugin::DigitalSignature;
490 ///
491 /// let sig = DigitalSignature::new(
492 /// "RSA-SHA256".to_string(),
493 /// vec![0x12, 0x34],
494 /// "SHA256:abc123".to_string(),
495 /// );
496 /// ```
497 pub fn new(algorithm: String, signature: Vec<u8>, public_key_fingerprint: String) -> Self {
498 Self {
499 algorithm,
500 signature,
501 public_key_fingerprint,
502 timestamp: std::time::SystemTime::now(),
503 signer_certificate: None,
504 }
505 }
506
507 /// Verify the signature algorithm is supported
508 ///
509 /// # Returns
510 ///
511 /// true if the algorithm is supported, false otherwise.
512 pub fn is_algorithm_supported(&self) -> bool {
513 matches!(
514 self.algorithm.as_str(),
515 "RSA-SHA256" | "RSA-SHA512" | "ECDSA-P256" | "ECDSA-P384" | "Ed25519"
516 )
517 }
518
519 /// Get the security strength of the signature algorithm
520 ///
521 /// # Returns
522 ///
523 /// Security strength in bits, or 0 for unknown algorithms.
524 pub fn security_strength(&self) -> u32 {
525 match self.algorithm.as_str() {
526 "RSA-SHA256" => 112, // 2048-bit RSA
527 "RSA-SHA512" => 112, // 2048-bit RSA
528 "ECDSA-P256" => 128, // P-256 curve
529 "ECDSA-P384" => 192, // P-384 curve
530 "Ed25519" => 128, // Ed25519 curve
531 _ => 0, // Unknown algorithm
532 }
533 }
534
535 /// Check if the signature has expired
536 ///
537 /// # Arguments
538 ///
539 /// * `max_age_seconds` - Maximum age in seconds before expiration
540 ///
541 /// # Returns
542 ///
543 /// true if the signature has expired, false otherwise.
544 pub fn is_expired(&self, max_age_seconds: u64) -> bool {
545 if let Ok(elapsed) = self.timestamp.elapsed() {
546 elapsed.as_secs() > max_age_seconds
547 } else {
548 true // If we can't determine age, consider it expired
549 }
550 }
551}
552
553/// Trust store for managing trusted keys and certificates
554///
555/// The TrustStore manages the cryptographic keys and certificates used
556/// for plugin signature verification. It provides a secure storage
557/// mechanism for trusted publisher keys.
558///
559/// # Examples
560///
561/// ```rust
562/// use sklears_core::plugin::TrustStore;
563///
564/// let trust_store = TrustStore::new();
565///
566/// // In a real implementation, you would load keys from secure storage
567/// // trust_store.load_from_file("trust_store.pem")?;
568/// ```
569#[derive(Debug, Clone)]
570pub struct TrustStore {
571 /// Trusted public keys indexed by fingerprint
572 trusted_keys: HashMap<String, PublicKeyInfo>,
573 /// Trusted certificates indexed by subject
574 trusted_certificates: HashMap<String, CertificateInfo>,
575 /// Revoked key fingerprints
576 revoked_keys: Vec<String>,
577}
578
579impl TrustStore {
580 /// Create a new empty trust store
581 pub fn new() -> Self {
582 Self {
583 trusted_keys: HashMap::new(),
584 trusted_certificates: HashMap::new(),
585 revoked_keys: Vec::new(),
586 }
587 }
588
589 /// Verify a digital signature against the trust store
590 ///
591 /// # Arguments
592 ///
593 /// * `content_hash` - Hash of the content being verified
594 /// * `signature` - The digital signature to verify
595 ///
596 /// # Returns
597 ///
598 /// Ok(true) if signature is valid, Ok(false) if invalid, Err if verification fails.
599 pub fn verify_signature(
600 &self,
601 _content_hash: &str,
602 signature: &DigitalSignature,
603 ) -> Result<bool> {
604 // Check if the signing key is revoked
605 if self
606 .revoked_keys
607 .contains(&signature.public_key_fingerprint)
608 {
609 return Ok(false);
610 }
611
612 // Check if algorithm is supported
613 if !signature.is_algorithm_supported() {
614 return Err(crate::error::SklearsError::InvalidOperation(format!(
615 "Unsupported signature algorithm: {}",
616 signature.algorithm
617 )));
618 }
619
620 // Check if signature has expired (1 year default)
621 if signature.is_expired(365 * 24 * 60 * 60) {
622 return Ok(false);
623 }
624
625 // Look up the public key
626 if let Some(key_info) = self.trusted_keys.get(&signature.public_key_fingerprint) {
627 if key_info.is_valid() {
628 // In a real implementation, this would perform actual cryptographic verification
629 // For now, we simulate verification based on fingerprint match
630 Ok(true)
631 } else {
632 Ok(false)
633 }
634 } else {
635 // Key not found in trust store
636 Ok(false)
637 }
638 }
639
640 /// Get the trust level of a publisher
641 ///
642 /// # Arguments
643 ///
644 /// * `publisher` - The publisher information to evaluate
645 ///
646 /// # Returns
647 ///
648 /// Trust level from 0 (untrusted) to 10 (fully trusted).
649 pub fn get_publisher_trust(&self, publisher: &PublisherInfo) -> u8 {
650 let mut trust_level = 0u8;
651
652 // Base trust for verified publishers
653 if publisher.verified {
654 trust_level += 3;
655 }
656
657 // Additional trust based on publisher trust score
658 trust_level += (publisher.trust_score / 2).min(5);
659
660 // Bonus for having certificates in trust store
661 if self.trusted_certificates.contains_key(&publisher.name) {
662 trust_level += 2;
663 }
664
665 trust_level.min(10)
666 }
667
668 /// Add a trusted public key to the store
669 ///
670 /// # Arguments
671 ///
672 /// * `fingerprint` - The key fingerprint
673 /// * `key_info` - Information about the public key
674 pub fn add_trusted_key(&mut self, fingerprint: String, key_info: PublicKeyInfo) {
675 self.trusted_keys.insert(fingerprint, key_info);
676 }
677
678 /// Remove a trusted key from the store
679 ///
680 /// # Arguments
681 ///
682 /// * `fingerprint` - The key fingerprint to remove
683 pub fn remove_trusted_key(&mut self, fingerprint: &str) {
684 self.trusted_keys.remove(fingerprint);
685 }
686
687 /// Revoke a key by adding it to the revocation list
688 ///
689 /// # Arguments
690 ///
691 /// * `fingerprint` - The key fingerprint to revoke
692 pub fn revoke_key(&mut self, fingerprint: String) {
693 if !self.revoked_keys.contains(&fingerprint) {
694 self.revoked_keys.push(fingerprint.clone());
695 }
696 // Also remove from trusted keys if present
697 self.trusted_keys.remove(&fingerprint);
698 }
699
700 /// Check if a key is revoked
701 ///
702 /// # Arguments
703 ///
704 /// * `fingerprint` - The key fingerprint to check
705 ///
706 /// # Returns
707 ///
708 /// true if the key is revoked, false otherwise.
709 pub fn is_key_revoked(&self, fingerprint: &str) -> bool {
710 self.revoked_keys.contains(&fingerprint.to_string())
711 }
712
713 /// Load trust store from a file
714 ///
715 /// # Arguments
716 ///
717 /// * `path` - Path to the trust store file
718 ///
719 /// # Returns
720 ///
721 /// Ok(()) on success, error on failure.
722 pub fn load_from_file(&mut self, _path: &str) -> Result<()> {
723 // Placeholder implementation
724 // In practice, this would load keys and certificates from a file
725 Ok(())
726 }
727
728 /// Save trust store to a file
729 ///
730 /// # Arguments
731 ///
732 /// * `path` - Path where to save the trust store
733 ///
734 /// # Returns
735 ///
736 /// Ok(()) on success, error on failure.
737 pub fn save_to_file(&self, _path: &str) -> Result<()> {
738 // Placeholder implementation
739 // In practice, this would save keys and certificates to a file
740 Ok(())
741 }
742}
743
744impl Default for TrustStore {
745 fn default() -> Self {
746 Self::new()
747 }
748}
749
750/// Information about a publisher
751#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
752pub struct PublisherInfo {
753 /// Publisher name
754 pub name: String,
755 /// Publisher email
756 pub email: String,
757 /// Publisher website
758 pub website: Option<String>,
759 /// Whether the publisher is verified
760 pub verified: bool,
761 /// Trust score (0-10)
762 pub trust_score: u8,
763}
764
765impl PublisherInfo {
766 /// Create a new publisher info
767 pub fn new(name: String, email: String) -> Self {
768 Self {
769 name,
770 email,
771 website: None,
772 verified: false,
773 trust_score: 0,
774 }
775 }
776
777 /// Check if the publisher information is complete
778 pub fn is_complete(&self) -> bool {
779 !self.name.is_empty() && !self.email.is_empty() && self.email.contains('@')
780 }
781}
782
783/// Information about a public key in the trust store
784#[derive(Debug, Clone)]
785pub struct PublicKeyInfo {
786 /// Key algorithm (e.g., "RSA", "ECDSA", "Ed25519")
787 pub algorithm: String,
788 /// Key size in bits
789 pub key_size: u32,
790 /// When the key was added to the trust store
791 pub added_timestamp: std::time::SystemTime,
792 /// Optional expiration time for the key
793 pub expires_at: Option<std::time::SystemTime>,
794 /// Owner of the key
795 pub owner: String,
796}
797
798impl PublicKeyInfo {
799 /// Check if the key is still valid (not expired)
800 pub fn is_valid(&self) -> bool {
801 if let Some(expires_at) = self.expires_at {
802 std::time::SystemTime::now() < expires_at
803 } else {
804 true // No expiration set
805 }
806 }
807
808 /// Get the security strength of this key
809 pub fn security_strength(&self) -> u32 {
810 match self.algorithm.as_str() {
811 "RSA" => {
812 if self.key_size >= 2048 {
813 112
814 } else if self.key_size >= 1024 {
815 80
816 } else {
817 0 // Too weak
818 }
819 }
820 "ECDSA" => {
821 if self.key_size >= 256 {
822 128
823 } else {
824 80
825 }
826 }
827 "Ed25519" => 128,
828 _ => 0,
829 }
830 }
831}
832
833/// Information about a certificate in the trust store
834#[derive(Debug, Clone)]
835pub struct CertificateInfo {
836 /// Certificate subject
837 pub subject: String,
838 /// Certificate issuer
839 pub issuer: String,
840 /// Certificate validity period
841 pub not_before: std::time::SystemTime,
842 /// Certificate expiration
843 pub not_after: std::time::SystemTime,
844 /// Certificate fingerprint
845 pub fingerprint: String,
846}
847
848impl CertificateInfo {
849 /// Check if the certificate is currently valid
850 pub fn is_valid(&self) -> bool {
851 let now = std::time::SystemTime::now();
852 now >= self.not_before && now <= self.not_after
853 }
854}
855
856/// Permission set for grouping related permissions
857#[derive(Debug, Clone)]
858pub struct PermissionSet {
859 /// Name of the permission set
860 pub name: String,
861 /// Description of what this set enables
862 pub description: String,
863 /// Individual permissions in this set
864 pub permissions: Vec<Permission>,
865}
866
867impl PermissionSet {
868 /// Create a new permission set
869 pub fn new(name: String, description: String, permissions: Vec<Permission>) -> Self {
870 Self {
871 name,
872 description,
873 permissions,
874 }
875 }
876
877 /// Create a file system permission set
878 pub fn file_system() -> Self {
879 Self::new(
880 "file_system".to_string(),
881 "Read and write access to the file system".to_string(),
882 vec![Permission::FileSystemRead, Permission::FileSystemWrite],
883 )
884 }
885
886 /// Create a network permission set
887 pub fn network() -> Self {
888 Self::new(
889 "network".to_string(),
890 "Access to network resources".to_string(),
891 vec![Permission::NetworkAccess],
892 )
893 }
894
895 /// Create a system administration permission set
896 pub fn system_admin() -> Self {
897 Self::new(
898 "system_admin".to_string(),
899 "Administrative access to system resources".to_string(),
900 vec![
901 Permission::SystemCommands,
902 Permission::ProcessSpawn,
903 Permission::EnvironmentVariables,
904 Permission::SystemConfiguration,
905 ],
906 )
907 }
908
909 /// Get the maximum risk level in this permission set
910 pub fn max_risk_level(&self) -> u8 {
911 self.permissions
912 .iter()
913 .map(|p| p.risk_level())
914 .max()
915 .unwrap_or(0)
916 }
917
918 /// Check if any permissions require user consent
919 pub fn requires_user_consent(&self) -> bool {
920 self.permissions.iter().any(|p| p.requires_user_consent())
921 }
922}
923
924#[allow(non_snake_case)]
925#[cfg(test)]
926mod tests {
927 use super::*;
928
929 #[test]
930 fn test_security_policy_levels() {
931 let strict = SecurityPolicy::strict();
932 assert!(strict.require_signatures);
933 assert!(!strict.allow_unsafe_code);
934 assert_eq!(strict.min_trust_level, 8);
935
936 let standard = SecurityPolicy::standard();
937 assert!(standard.require_signatures);
938 assert!(!standard.allow_unsafe_code);
939 assert_eq!(standard.min_trust_level, 5);
940
941 let permissive = SecurityPolicy::permissive();
942 assert!(!permissive.require_signatures);
943 assert!(permissive.allow_unsafe_code);
944 assert_eq!(permissive.min_trust_level, 0);
945 }
946
947 #[test]
948 fn test_permission_risk_levels() {
949 assert_eq!(Permission::FileSystemRead.risk_level(), 2);
950 assert_eq!(Permission::FileSystemWrite.risk_level(), 3);
951 assert_eq!(Permission::SystemCommands.risk_level(), 5);
952 assert_eq!(Permission::GpuAccess.risk_level(), 2);
953 }
954
955 #[test]
956 fn test_permission_consent_requirements() {
957 assert!(!Permission::FileSystemRead.requires_user_consent());
958 assert!(Permission::FileSystemWrite.requires_user_consent());
959 assert!(Permission::SystemCommands.requires_user_consent());
960 assert!(!Permission::GpuAccess.requires_user_consent());
961 }
962
963 #[test]
964 fn test_digital_signature_algorithms() {
965 let rsa_sig = DigitalSignature::new("RSA-SHA256".to_string(), vec![], "test".to_string());
966 assert!(rsa_sig.is_algorithm_supported());
967 assert_eq!(rsa_sig.security_strength(), 112);
968
969 let unknown_sig = DigitalSignature::new("UNKNOWN".to_string(), vec![], "test".to_string());
970 assert!(!unknown_sig.is_algorithm_supported());
971 assert_eq!(unknown_sig.security_strength(), 0);
972 }
973
974 #[test]
975 fn test_trust_store_key_management() {
976 let mut trust_store = TrustStore::new();
977
978 let key_info = PublicKeyInfo {
979 algorithm: "RSA".to_string(),
980 key_size: 2048,
981 added_timestamp: std::time::SystemTime::now(),
982 expires_at: None,
983 owner: "test@example.com".to_string(),
984 };
985
986 // Add trusted key
987 trust_store.add_trusted_key("fingerprint123".to_string(), key_info.clone());
988 assert!(!trust_store.is_key_revoked("fingerprint123"));
989
990 // Revoke key
991 trust_store.revoke_key("fingerprint123".to_string());
992 assert!(trust_store.is_key_revoked("fingerprint123"));
993 }
994
995 #[test]
996 fn test_permission_sets() {
997 let fs_set = PermissionSet::file_system();
998 assert_eq!(fs_set.permissions.len(), 2);
999 assert!(fs_set.requires_user_consent());
1000 assert_eq!(fs_set.max_risk_level(), 3);
1001
1002 let admin_set = PermissionSet::system_admin();
1003 assert!(admin_set.permissions.len() > 2);
1004 assert!(admin_set.requires_user_consent());
1005 assert_eq!(admin_set.max_risk_level(), 5);
1006 }
1007
1008 #[test]
1009 fn test_publisher_info() {
1010 let publisher =
1011 PublisherInfo::new("Test Publisher".to_string(), "test@example.com".to_string());
1012 assert!(publisher.is_complete());
1013
1014 let incomplete = PublisherInfo::new("".to_string(), "invalid-email".to_string());
1015 assert!(!incomplete.is_complete());
1016 }
1017}