auths_sdk/domains/identity/
error.rs1use auths_core::error::AuthsErrorInfo;
2use thiserror::Error;
3
4#[derive(Debug, Error)]
15#[non_exhaustive]
16pub enum SetupError {
17 #[error("identity already exists: {did}")]
19 IdentityAlreadyExists {
20 did: String,
22 },
23
24 #[error("keychain unavailable ({backend}): {reason}")]
26 KeychainUnavailable {
27 backend: String,
29 reason: String,
31 },
32
33 #[error("crypto error: {0}")]
35 CryptoError(#[source] auths_core::AgentError),
36
37 #[error("passphrase from {source_name} is too weak: {reason}")]
41 WeakPassphrase {
42 source_name: String,
45 reason: String,
47 },
48
49 #[error("storage error: {0}")]
51 StorageError(#[source] crate::error::SdkStorageError),
52
53 #[error("git config error: {0}")]
55 GitConfigError(#[source] crate::ports::git_config::GitConfigError),
56
57 #[error("invalid setup config: {0}")]
59 InvalidSetupConfig(String),
60
61 #[error("registration failed: {0}")]
63 RegistrationFailed(#[source] RegistrationError),
64
65 #[error("platform verification failed: {0}")]
67 PlatformVerificationFailed(String),
68}
69
70#[derive(Debug, Error)]
81#[non_exhaustive]
82pub enum RotationError {
83 #[error("identity not found at {path}")]
85 IdentityNotFound {
86 path: std::path::PathBuf,
88 },
89
90 #[error("key not found: {0}")]
92 KeyNotFound(String),
93
94 #[error("key decryption failed: {0}")]
96 KeyDecryptionFailed(String),
97
98 #[error("KEL history error: {0}")]
100 KelHistoryFailed(String),
101
102 #[error("rotation failed: {0}")]
104 RotationFailed(String),
105
106 #[error(
109 "rotation event committed to KEL but keychain write failed — manual recovery required: {0}"
110 )]
111 PartialRotation(String),
112
113 #[error(
115 "rotation requires a software-backed key; alias '{alias}' is hardware-backed (Secure Enclave) and cannot export the raw key material rotation needs"
116 )]
117 HardwareKeyNotRotatable {
118 alias: String,
120 },
121}
122
123#[derive(Debug, Error)]
135#[non_exhaustive]
136pub enum RegistrationError {
137 #[error(
142 "no registry configured. Auths needs no registry: identity, signing and verification are local and git-native, and a signer's KEL reaches a verifier over the same git remote as the code. Pass --registry <url> or set AUTHS_REGISTRY_URL only if you are running one."
143 )]
144 NoRegistryConfigured,
145
146 #[error("identity already registered at this registry")]
148 AlreadyRegistered,
149
150 #[error("registration quota exceeded — try again later")]
152 QuotaExceeded,
153
154 #[error("network error: {0}")]
156 NetworkError(#[source] auths_core::ports::network::NetworkError),
157
158 #[error("invalid DID format: {did}")]
160 InvalidDidFormat {
161 did: String,
163 },
164
165 #[error("identity load error: {0}")]
167 IdentityLoadError(#[source] auths_id::error::StorageError),
168
169 #[error("registry read error: {0}")]
171 RegistryReadError(#[source] auths_id::storage::registry::backend::RegistryError),
172
173 #[error("serialization error: {0}")]
175 SerializationError(#[source] serde_json::Error),
176}
177
178impl From<auths_core::AgentError> for SetupError {
179 fn from(err: auths_core::AgentError) -> Self {
180 SetupError::CryptoError(err)
181 }
182}
183
184impl From<RegistrationError> for SetupError {
185 fn from(err: RegistrationError) -> Self {
186 SetupError::RegistrationFailed(err)
187 }
188}
189
190impl From<auths_core::ports::network::NetworkError> for RegistrationError {
191 fn from(err: auths_core::ports::network::NetworkError) -> Self {
192 RegistrationError::NetworkError(err)
193 }
194}
195
196impl AuthsErrorInfo for SetupError {
197 fn error_code(&self) -> &'static str {
198 match self {
199 Self::IdentityAlreadyExists { .. } => "AUTHS-E5001",
200 Self::KeychainUnavailable { .. } => "AUTHS-E5002",
201 Self::CryptoError(e) => e.error_code(),
202 Self::WeakPassphrase { .. } => "AUTHS-E5008",
203 Self::StorageError(e) => e.error_code(),
204 Self::GitConfigError(_) => "AUTHS-E5004",
205 Self::InvalidSetupConfig(_) => "AUTHS-E5007",
206 Self::RegistrationFailed(e) => e.error_code(),
207 Self::PlatformVerificationFailed(_) => "AUTHS-E5006",
208 }
209 }
210
211 fn suggestion(&self) -> Option<&'static str> {
212 match self {
213 Self::IdentityAlreadyExists { .. } => {
214 Some("Use `auths id show` to inspect the existing identity")
215 }
216 Self::KeychainUnavailable { .. } => {
217 Some("Run `auths doctor` to diagnose keychain issues")
218 }
219 Self::CryptoError(e) => e.suggestion(),
220 Self::WeakPassphrase { .. } => Some(
221 "Use at least 12 characters with 3 of 4 character classes (lowercase, uppercase, digit, symbol)",
222 ),
223 Self::StorageError(e) => e.suggestion(),
224 Self::GitConfigError(_) => {
225 Some("Ensure Git is configured: git config --global user.name/email")
226 }
227 Self::InvalidSetupConfig(_) => None,
230 Self::RegistrationFailed(e) => e.suggestion(),
231 Self::PlatformVerificationFailed(_) => Some(
232 "Platform identity verification failed; check your platform credentials and network connectivity",
233 ),
234 }
235 }
236}
237
238impl AuthsErrorInfo for RotationError {
239 fn error_code(&self) -> &'static str {
240 match self {
241 Self::IdentityNotFound { .. } => "AUTHS-E5301",
242 Self::KeyNotFound(_) => "AUTHS-E5302",
243 Self::KeyDecryptionFailed(_) => "AUTHS-E5303",
244 Self::KelHistoryFailed(_) => "AUTHS-E5304",
245 Self::RotationFailed(_) => "AUTHS-E5305",
246 Self::PartialRotation(_) => "AUTHS-E5306",
247 Self::HardwareKeyNotRotatable { .. } => "AUTHS-E5307",
248 }
249 }
250
251 fn suggestion(&self) -> Option<&'static str> {
252 match self {
253 Self::IdentityNotFound { .. } => Some("Run `auths init` to create an identity first"),
254 Self::KeyNotFound(_) => Some("Run `auths key list` to see available keys"),
255 Self::KeyDecryptionFailed(_) => Some("Check your passphrase and try again"),
256 Self::KelHistoryFailed(_) => Some("Run `auths doctor` to check KEL integrity"),
257 Self::RotationFailed(_) => Some(
258 "Key rotation failed; verify your current key is accessible with `auths key list`",
259 ),
260 Self::PartialRotation(_) => {
261 Some("Re-run the rotation with the same new key to complete the keychain write")
262 }
263 Self::HardwareKeyNotRotatable { .. } => Some(
264 "Hardware-backed keys (Secure Enclave / HSM) cannot be rotated in-place; provision a software-backed identity or rotate by creating a new identity",
265 ),
266 }
267 }
268}
269
270impl AuthsErrorInfo for RegistrationError {
271 fn error_code(&self) -> &'static str {
272 match self {
273 Self::NoRegistryConfigured => "AUTHS-E5400",
274 Self::AlreadyRegistered => "AUTHS-E5401",
275 Self::QuotaExceeded => "AUTHS-E5402",
276 Self::NetworkError(e) => e.error_code(),
277 Self::InvalidDidFormat { .. } => "AUTHS-E5403",
278 Self::IdentityLoadError(_) => "AUTHS-E5404",
279 Self::RegistryReadError(_) => "AUTHS-E5405",
280 Self::SerializationError(_) => "AUTHS-E5406",
281 }
282 }
283
284 fn suggestion(&self) -> Option<&'static str> {
285 match self {
286 Self::NoRegistryConfigured => Some(
287 "Registration is optional — signing and verification need no registry. Pass --registry <url> or set AUTHS_REGISTRY_URL only if you run one",
288 ),
289 Self::AlreadyRegistered => Some(
290 "This identity is already registered; use `auths id show` to see registration details",
291 ),
292 Self::QuotaExceeded => Some("Wait a few minutes and try again"),
293 Self::NetworkError(e) => e.suggestion(),
294 Self::InvalidDidFormat { .. } => {
295 Some("Run `auths doctor` to check local identity data")
296 }
297 Self::IdentityLoadError(_) => Some("Run `auths doctor` to check local identity data"),
298 Self::RegistryReadError(_) => Some("Run `auths doctor` to check local identity data"),
299 Self::SerializationError(_) => Some("Run `auths doctor` to check local identity data"),
300 }
301 }
302}