1use thiserror::Error;
4
5pub trait AuthsErrorInfo {
11 fn error_code(&self) -> &'static str;
18
19 fn suggestion(&self) -> Option<&'static str>;
24}
25
26#[derive(Debug, Error)]
28pub enum AgentError {
29 #[error("Key not found")]
31 KeyNotFound,
32
33 #[error("Incorrect passphrase")]
35 IncorrectPassphrase,
36
37 #[error("Missing Passphrase")]
39 MissingPassphrase,
40
41 #[error("Security error: {0}")]
43 SecurityError(String),
44
45 #[error("Crypto error: {0}")]
47 CryptoError(String),
48
49 #[error("Key deserialization error: {0}")]
51 KeyDeserializationError(String),
52
53 #[error("Signing failed: {0}")]
55 SigningFailed(String),
56
57 #[error("Protocol error: {0}")]
59 Proto(String),
60
61 #[error("IO error: {0}")]
63 IO(#[from] std::io::Error),
64
65 #[error("git error: {0}")]
67 GitError(String),
68
69 #[error("Invalid input: {0}")]
71 InvalidInput(String),
72
73 #[error("Mutex lock poisoned: {0}")]
75 MutexError(String),
76
77 #[error("Storage error: {0}")]
79 StorageError(String),
80
81 #[error("User input cancelled")]
83 UserInputCancelled,
84
85 #[error("Keychain backend unavailable: {backend} - {reason}")]
88 BackendUnavailable {
89 backend: &'static str,
91 reason: String,
93 },
94
95 #[error("Storage is locked, authentication required")]
97 StorageLocked,
98
99 #[error("Failed to initialize keychain backend: {backend} - {error}")]
101 BackendInitFailed {
102 backend: &'static str,
104 error: String,
106 },
107
108 #[error("Credential too large for backend (max {max_bytes} bytes, got {actual_bytes})")]
110 CredentialTooLarge {
111 max_bytes: usize,
113 actual_bytes: usize,
115 },
116
117 #[error("Agent is locked. Unlock with 'auths agent unlock' or restart the agent.")]
119 AgentLocked,
120
121 #[error("Passphrase too weak: {0}")]
123 WeakPassphrase(String),
124}
125
126impl AuthsErrorInfo for AgentError {
127 fn error_code(&self) -> &'static str {
128 match self {
129 Self::KeyNotFound => "AUTHS_KEY_NOT_FOUND",
130 Self::IncorrectPassphrase => "AUTHS_INCORRECT_PASSPHRASE",
131 Self::MissingPassphrase => "AUTHS_MISSING_PASSPHRASE",
132 Self::SecurityError(_) => "AUTHS_SECURITY_ERROR",
133 Self::CryptoError(_) => "AUTHS_CRYPTO_ERROR",
134 Self::KeyDeserializationError(_) => "AUTHS_KEY_DESERIALIZATION_ERROR",
135 Self::SigningFailed(_) => "AUTHS_SIGNING_FAILED",
136 Self::Proto(_) => "AUTHS_PROTOCOL_ERROR",
137 Self::IO(_) => "AUTHS_IO_ERROR",
138 Self::GitError(_) => "AUTHS_GIT_ERROR",
139 Self::InvalidInput(_) => "AUTHS_INVALID_INPUT",
140 Self::MutexError(_) => "AUTHS_MUTEX_ERROR",
141 Self::StorageError(_) => "AUTHS_STORAGE_ERROR",
142 Self::UserInputCancelled => "AUTHS_USER_CANCELLED",
143 Self::BackendUnavailable { .. } => "AUTHS_BACKEND_UNAVAILABLE",
144 Self::StorageLocked => "AUTHS_STORAGE_LOCKED",
145 Self::BackendInitFailed { .. } => "AUTHS_BACKEND_INIT_FAILED",
146 Self::CredentialTooLarge { .. } => "AUTHS_CREDENTIAL_TOO_LARGE",
147 Self::AgentLocked => "AUTHS_AGENT_LOCKED",
148 Self::WeakPassphrase(_) => "AUTHS_WEAK_PASSPHRASE",
149 }
150 }
151
152 fn suggestion(&self) -> Option<&'static str> {
153 match self {
154 Self::KeyNotFound => Some("Run `auths key list` to see available keys"),
155 Self::IncorrectPassphrase => Some("Check your passphrase and try again"),
156 Self::MissingPassphrase => {
157 Some("Provide a passphrase with --passphrase or set AUTHS_PASSPHRASE")
158 }
159 Self::BackendUnavailable { .. } => {
160 Some("Run `auths doctor` to diagnose keychain issues")
161 }
162 Self::StorageLocked => Some("Authenticate with your platform keychain"),
163 Self::BackendInitFailed { .. } => {
164 Some("Run `auths doctor` to diagnose keychain issues")
165 }
166 Self::GitError(_) => Some("Ensure you're in a Git repository"),
167 Self::AgentLocked => {
168 Some("Run `auths agent unlock` or restart with `auths agent start`")
169 }
170 Self::UserInputCancelled => {
171 Some("Run the command again and provide the required input")
172 }
173 Self::StorageError(_) => Some("Check file permissions and disk space"),
174 Self::SecurityError(_)
176 | Self::CryptoError(_)
177 | Self::KeyDeserializationError(_)
178 | Self::SigningFailed(_)
179 | Self::Proto(_)
180 | Self::IO(_)
181 | Self::InvalidInput(_)
182 | Self::MutexError(_)
183 | Self::CredentialTooLarge { .. } => None,
184 Self::WeakPassphrase(_) => {
185 Some("Use at least 12 characters with uppercase, lowercase, and a digit or symbol")
186 }
187 }
188 }
189}
190
191#[derive(Debug, Error)]
193pub enum TrustError {
194 #[error("I/O error: {0}")]
196 Io(#[from] std::io::Error),
197 #[error("{0}")]
199 InvalidData(String),
200 #[error("not found: {0}")]
202 NotFound(String),
203 #[error("serialization error: {0}")]
205 Serialization(#[from] serde_json::Error),
206 #[error("already exists: {0}")]
208 AlreadyExists(String),
209 #[error("lock acquisition failed: {0}")]
211 Lock(String),
212 #[error("policy rejected: {0}")]
214 PolicyRejected(String),
215}
216
217impl From<AgentError> for ssh_agent_lib::error::AgentError {
218 fn from(err: AgentError) -> Self {
219 match err {
220 AgentError::KeyNotFound => Self::Failure,
221 AgentError::IncorrectPassphrase => Self::Failure,
222 _ => Self::Failure,
223 }
224 }
225}