mockforge_core/encryption/
errors.rs

1//! Error types and handling for encryption operations
2//!
3//! This module provides comprehensive error handling for all encryption-related
4//! operations, including encryption, decryption, key management, and validation.
5
6use std::fmt;
7use thiserror::Error;
8
9/// Errors that can occur during encryption/decryption operations
10#[derive(Error, Debug)]
11pub enum EncryptionError {
12    /// Invalid key length or format
13    #[error("Invalid key: {message}")]
14    InvalidKey { message: String },
15
16    /// Invalid nonce/IV length or format
17    #[error("Invalid nonce: {message}")]
18    InvalidNonce { message: String },
19
20    /// Authentication failed during decryption
21    #[error("Authentication failed: {message}")]
22    AuthenticationFailed { message: String },
23
24    /// Invalid ciphertext format
25    #[error("Invalid ciphertext: {message}")]
26    InvalidCiphertext { message: String },
27
28    /// Key derivation failed
29    #[error("Key derivation failed: {message}")]
30    KeyDerivationFailed { message: String },
31
32    /// Key not found in key store
33    #[error("Key not found: {key_id}")]
34    KeyNotFound { key_id: String },
35
36    /// Insufficient permissions for key operation
37    #[error("Access denied: {message}")]
38    AccessDenied { message: String },
39
40    /// Key store operation failed
41    #[error("Key store error: {message}")]
42    KeyStoreError { message: String },
43
44    /// Random number generation failed
45    #[error("Random generation failed: {message}")]
46    RandomGenerationFailed { message: String },
47
48    /// Invalid algorithm configuration
49    #[error("Invalid algorithm: {message}")]
50    InvalidAlgorithm { message: String },
51
52    /// Cipher operation failed
53    #[error("Cipher operation failed: {message}")]
54    CipherOperationFailed { message: String },
55
56    /// Base64 encoding/decoding failed
57    #[error("Base64 operation failed: {message}")]
58    Base64Error { message: String },
59
60    /// Serialization/deserialization failed
61    #[error("Serialization failed: {message}")]
62    SerializationError { message: String },
63
64    /// Template processing failed
65    #[error("Template processing failed: {message}")]
66    TemplateError { message: String },
67
68    /// Auto-encryption configuration error
69    #[error("Auto-encryption configuration error: {message}")]
70    AutoEncryptionConfigError { message: String },
71
72    /// Workspace encryption error
73    #[error("Workspace encryption error: {message}")]
74    Workspace { message: String },
75
76    /// Generic encryption error
77    #[error("Encryption error: {message}")]
78    Generic { message: String },
79}
80
81impl EncryptionError {
82    /// Create a new invalid key error
83    pub fn invalid_key(message: impl Into<String>) -> Self {
84        Self::InvalidKey {
85            message: message.into(),
86        }
87    }
88
89    /// Create a new invalid nonce error
90    pub fn invalid_nonce(message: impl Into<String>) -> Self {
91        Self::InvalidNonce {
92            message: message.into(),
93        }
94    }
95
96    /// Create a new authentication failed error
97    pub fn authentication_failed(message: impl Into<String>) -> Self {
98        Self::AuthenticationFailed {
99            message: message.into(),
100        }
101    }
102
103    /// Create a new invalid ciphertext error
104    pub fn invalid_ciphertext(message: impl Into<String>) -> Self {
105        Self::InvalidCiphertext {
106            message: message.into(),
107        }
108    }
109
110    /// Create a new key derivation failed error
111    pub fn key_derivation_failed(message: impl Into<String>) -> Self {
112        Self::KeyDerivationFailed {
113            message: message.into(),
114        }
115    }
116
117    /// Create a new key not found error
118    pub fn key_not_found(key_id: impl Into<String>) -> Self {
119        Self::KeyNotFound {
120            key_id: key_id.into(),
121        }
122    }
123
124    /// Create a new access denied error
125    pub fn access_denied(message: impl Into<String>) -> Self {
126        Self::AccessDenied {
127            message: message.into(),
128        }
129    }
130
131    /// Create a new key store error
132    pub fn key_store_error(message: impl Into<String>) -> Self {
133        Self::KeyStoreError {
134            message: message.into(),
135        }
136    }
137
138    /// Create a new random generation failed error
139    pub fn random_generation_failed(message: impl Into<String>) -> Self {
140        Self::RandomGenerationFailed {
141            message: message.into(),
142        }
143    }
144
145    /// Create a new invalid algorithm error
146    pub fn invalid_algorithm(message: impl Into<String>) -> Self {
147        Self::InvalidAlgorithm {
148            message: message.into(),
149        }
150    }
151
152    /// Create a new cipher operation failed error
153    pub fn cipher_operation_failed(message: impl Into<String>) -> Self {
154        Self::CipherOperationFailed {
155            message: message.into(),
156        }
157    }
158
159    /// Create a new base64 error
160    pub fn base64_error(message: impl Into<String>) -> Self {
161        Self::Base64Error {
162            message: message.into(),
163        }
164    }
165
166    /// Create a new serialization error
167    pub fn serialization_error(message: impl Into<String>) -> Self {
168        Self::SerializationError {
169            message: message.into(),
170        }
171    }
172
173    /// Create a new template error
174    pub fn template_error(message: impl Into<String>) -> Self {
175        Self::TemplateError {
176            message: message.into(),
177        }
178    }
179
180    /// Create a new auto-encryption config error
181    pub fn auto_encryption_config_error(message: impl Into<String>) -> Self {
182        Self::AutoEncryptionConfigError {
183            message: message.into(),
184        }
185    }
186
187    /// Create a new workspace encryption error
188    pub fn workspace_encryption_error(message: impl Into<String>) -> Self {
189        Self::Workspace {
190            message: message.into(),
191        }
192    }
193
194    /// Create a new generic error
195    pub fn generic(message: impl Into<String>) -> Self {
196        Self::Generic {
197            message: message.into(),
198        }
199    }
200
201    /// Check if this is a recoverable error
202    pub fn is_recoverable(&self) -> bool {
203        match self {
204            Self::InvalidKey { .. }
205            | Self::InvalidNonce { .. }
206            | Self::AuthenticationFailed { .. }
207            | Self::InvalidCiphertext { .. }
208            | Self::KeyNotFound { .. }
209            | Self::InvalidAlgorithm { .. }
210            | Self::Base64Error { .. }
211            | Self::SerializationError { .. }
212            | Self::TemplateError { .. }
213            | Self::AutoEncryptionConfigError { .. } => false,
214
215            Self::KeyDerivationFailed { .. }
216            | Self::AccessDenied { .. }
217            | Self::KeyStoreError { .. }
218            | Self::RandomGenerationFailed { .. }
219            | Self::CipherOperationFailed { .. }
220            | Self::Workspace { .. }
221            | Self::Generic { .. } => true,
222        }
223    }
224
225    /// Get error severity level
226    pub fn severity(&self) -> ErrorSeverity {
227        match self {
228            Self::AuthenticationFailed { .. } | Self::AccessDenied { .. } => {
229                ErrorSeverity::Critical
230            }
231
232            Self::InvalidKey { .. }
233            | Self::InvalidNonce { .. }
234            | Self::InvalidCiphertext { .. }
235            | Self::InvalidAlgorithm { .. } => ErrorSeverity::High,
236
237            Self::KeyDerivationFailed { .. }
238            | Self::KeyStoreError { .. }
239            | Self::RandomGenerationFailed { .. }
240            | Self::CipherOperationFailed { .. } => ErrorSeverity::Medium,
241
242            Self::Base64Error { .. }
243            | Self::SerializationError { .. }
244            | Self::TemplateError { .. }
245            | Self::AutoEncryptionConfigError { .. }
246            | Self::Workspace { .. }
247            | Self::Generic { .. } => ErrorSeverity::Low,
248
249            Self::KeyNotFound { .. } => ErrorSeverity::Info,
250        }
251    }
252}
253
254/// Error severity levels
255#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
256pub enum ErrorSeverity {
257    /// Informational messages
258    Info,
259    /// Low severity errors
260    Low,
261    /// Medium severity errors
262    Medium,
263    /// High severity errors
264    High,
265    /// Critical severity errors
266    Critical,
267}
268
269/// Result type alias for encryption operations
270pub type EncryptionResult<T> = Result<T, EncryptionError>;
271
272/// Error context for better debugging
273#[derive(Debug, Clone)]
274pub struct ErrorContext {
275    /// Operation that failed
276    pub operation: String,
277    /// Additional context information
278    pub context: HashMap<String, String>,
279    /// Timestamp when error occurred
280    pub timestamp: chrono::DateTime<chrono::Utc>,
281}
282
283impl ErrorContext {
284    /// Create a new error context
285    pub fn new(operation: impl Into<String>) -> Self {
286        Self {
287            operation: operation.into(),
288            context: HashMap::new(),
289            timestamp: chrono::Utc::now(),
290        }
291    }
292
293    /// Add context information
294    pub fn with_context(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
295        self.context.insert(key.into(), value.into());
296        self
297    }
298}
299
300/// Enhanced error with context
301#[derive(Debug)]
302pub struct ContextualError {
303    /// The underlying encryption error
304    pub error: EncryptionError,
305    /// Additional context information
306    pub context: ErrorContext,
307}
308
309impl fmt::Display for ContextualError {
310    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
311        write!(
312            f,
313            "Encryption error in {} at {}: {} (context: {:?})",
314            self.context.operation, self.context.timestamp, self.error, self.context.context
315        )
316    }
317}
318
319impl std::error::Error for ContextualError {
320    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
321        Some(&self.error)
322    }
323}
324
325/// Error recovery strategies
326#[derive(Debug, Clone)]
327pub enum ErrorRecoveryStrategy {
328    /// Retry with exponential backoff
329    RetryWithBackoff {
330        max_attempts: usize,
331        base_delay_ms: u64,
332    },
333    /// Use fallback encryption method
334    FallbackMethod,
335    /// Skip encryption for this operation
336    SkipEncryption,
337    /// Request user intervention
338    ManualIntervention,
339    /// Fail fast
340    FailFast,
341}
342
343impl EncryptionError {
344    /// Suggest recovery strategy based on error type
345    pub fn suggested_recovery(&self) -> ErrorRecoveryStrategy {
346        match self {
347            Self::RandomGenerationFailed { .. } => ErrorRecoveryStrategy::RetryWithBackoff {
348                max_attempts: 3,
349                base_delay_ms: 100,
350            },
351
352            Self::KeyStoreError { .. } | Self::KeyDerivationFailed { .. } => {
353                ErrorRecoveryStrategy::ManualIntervention
354            }
355
356            Self::AuthenticationFailed { .. } | Self::AccessDenied { .. } => {
357                ErrorRecoveryStrategy::FailFast
358            }
359
360            Self::InvalidKey { .. } | Self::InvalidNonce { .. } => {
361                ErrorRecoveryStrategy::FallbackMethod
362            }
363
364            _ => ErrorRecoveryStrategy::RetryWithBackoff {
365                max_attempts: 2,
366                base_delay_ms: 50,
367            },
368        }
369    }
370
371    /// Convert to contextual error
372    pub fn with_context(self, context: ErrorContext) -> ContextualError {
373        ContextualError {
374            error: self,
375            context,
376        }
377    }
378}
379
380use std::collections::HashMap;