Skip to main content

age_setup/
errors.rs

1//! Error types for the `age-setup` crate.
2//!
3//! This module defines the central [`Error`] enum that encompasses all possible
4//! failures in key generation and validation. It is designed to provide clear,
5//! actionable error messages through the [`thiserror`] crate.
6
7use thiserror::Error;
8
9/// The main error type for the `age-setup` crate.
10///
11/// All fallible operations in the library return a [`Result<T>`] where the error
12/// is of this type. It is deliberately kept small and covers only the failure
13/// modes that can occur:
14///
15/// - **Generation failures** – when the underlying `age` library fails to create
16///   a new identity.
17/// - **Validation failures** – when a public or secret key does not meet the
18///   expected format.
19///
20/// # Example
21///
22/// ```rust
23/// use age_setup::Error;
24///
25/// fn handle_error(e: Error) {
26///     match e {
27///         Error::Generation(err) => eprintln!("Generation error: {}", err),
28///         Error::Validation(err) => eprintln!("Validation error: {}", err),
29///     }
30/// }
31/// ```
32#[derive(Debug, Error)]
33pub enum Error {
34    /// An error that occurred during key generation.
35    ///
36    /// This variant wraps [`GenerationError`] and is produced by
37    /// [`build_keypair`](crate::build_keypair) if the internal identity generation
38    /// fails.
39    #[error("Key generation failed: {0}")]
40    Generation(#[from] GenerationError),
41
42    /// An error that occurred while validating a public or secret key.
43    ///
44    /// This variant wraps [`ValidationError`] and is produced by constructors like
45    /// [`PublicKey::new`](crate::PublicKey::new) or
46    /// [`SecretKey::new`](crate::SecretKey::new) when the provided string does
47    /// not conform to the expected format.
48    #[error("Validation failed: {0}")]
49    Validation(#[from] ValidationError),
50}
51
52/// The standard `Result` type used throughout the crate.
53///
54/// This is a convenience alias for `std::result::Result<T, Error>`.
55pub type Result<T> = std::result::Result<T, Error>;
56
57/// Errors that can occur during key generation.
58///
59/// Currently, the only possible failure is if the `age` library fails to create
60/// a new X25519 identity. This should be extremely rare and typically indicates
61/// a system-level issue (e.g., lack of entropy).
62#[derive(Debug, Error)]
63pub enum GenerationError {
64    /// The identity could not be created.
65    ///
66    /// This error is returned when the underlying `age` crate encounters an
67    /// internal failure while generating a new X25519 keypair.
68    #[error("Identity generation failed")]
69    IdentityCreationFailed,
70}
71
72/// Errors that can occur while validating a public or secret key.
73///
74/// Both public and secret keys are validated for basic format correctness before
75/// being wrapped. This enum captures the specific reason for the validation
76/// failure.
77#[derive(Debug, Error)]
78pub enum ValidationError {
79    /// The provided public key string is not in a valid format.
80    ///
81    /// This error is returned when a public key is empty or does not start with
82    /// the `"age1"` prefix.
83    #[error("Invalid public key format: {reason}")]
84    InvalidPublicKeyFormat { reason: String },
85
86    /// The provided secret key string is not in a valid format.
87    ///
88    /// This error is returned when a secret key is empty or does not start with
89    /// `"AGE-SECRET-KEY-1"`.
90    #[error("Invalid secret key format: {reason}")]
91    InvalidSecretKeyFormat { reason: String },
92}
93
94impl ValidationError {
95    /// Creates a new [`ValidationError::InvalidPublicKeyFormat`] with the given reason.
96    ///
97    /// This is a convenience constructor used internally by the public key validation
98    /// logic.
99    pub(crate) fn invalid_public_key(reason: impl Into<String>) -> Self {
100        Self::InvalidPublicKeyFormat {
101            reason: reason.into(),
102        }
103    }
104
105    /// Creates a new [`ValidationError::InvalidSecretKeyFormat`] with the given reason.
106    ///
107    /// This is a convenience constructor used internally by the secret key validation
108    /// logic.
109    pub(crate) fn invalid_secret_key(reason: impl Into<String>) -> Self {
110        Self::InvalidSecretKeyFormat {
111            reason: reason.into(),
112        }
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    /// Ensure `GenerationError` can be converted into `Error`.
121    #[test]
122    fn generation_error_conversion() {
123        let gen_err = GenerationError::IdentityCreationFailed;
124        let err: Error = gen_err.into();
125        assert!(matches!(err, Error::Generation(_)));
126    }
127
128    /// Ensure `ValidationError` can be converted into `Error`.
129    #[test]
130    fn validation_error_conversion() {
131        let val_err = ValidationError::invalid_public_key("test");
132        let err: Error = val_err.into();
133        assert!(matches!(err, Error::Validation(_)));
134    }
135
136    /// Test the `Display` implementation of `GenerationError`.
137    #[test]
138    fn generation_error_display() {
139        let e = GenerationError::IdentityCreationFailed;
140        assert_eq!(format!("{}", e), "Identity generation failed");
141    }
142
143    /// Test the `Display` implementation of `ValidationError` for public key.
144    #[test]
145    fn validation_error_display_public() {
146        let e = ValidationError::invalid_public_key("too short");
147        assert_eq!(format!("{}", e), "Invalid public key format: too short");
148    }
149
150    /// Test the `Display` implementation of `ValidationError` for secret key.
151    #[test]
152    fn validation_error_display_secret() {
153        let e = ValidationError::invalid_secret_key("empty");
154        assert_eq!(format!("{}", e), "Invalid secret key format: empty");
155    }
156
157    /// Test that the `Result` alias works properly.
158    #[test]
159    fn result_type_alias() {
160        fn returns_ok() -> Result<()> {
161            Ok(())
162        }
163        fn returns_err() -> Result<()> {
164            Err(Error::Generation(GenerationError::IdentityCreationFailed))
165        }
166        assert!(returns_ok().is_ok());
167        assert!(returns_err().is_err());
168    }
169}