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}