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("identity already registered at this registry")]
139 AlreadyRegistered,
140
141 #[error("registration quota exceeded — try again later")]
143 QuotaExceeded,
144
145 #[error("network error: {0}")]
147 NetworkError(#[source] auths_core::ports::network::NetworkError),
148
149 #[error("invalid DID format: {did}")]
151 InvalidDidFormat {
152 did: String,
154 },
155
156 #[error("identity load error: {0}")]
158 IdentityLoadError(#[source] auths_id::error::StorageError),
159
160 #[error("registry read error: {0}")]
162 RegistryReadError(#[source] auths_id::storage::registry::backend::RegistryError),
163
164 #[error("serialization error: {0}")]
166 SerializationError(#[source] serde_json::Error),
167}
168
169impl From<auths_core::AgentError> for SetupError {
170 fn from(err: auths_core::AgentError) -> Self {
171 SetupError::CryptoError(err)
172 }
173}
174
175impl From<RegistrationError> for SetupError {
176 fn from(err: RegistrationError) -> Self {
177 SetupError::RegistrationFailed(err)
178 }
179}
180
181impl From<auths_core::ports::network::NetworkError> for RegistrationError {
182 fn from(err: auths_core::ports::network::NetworkError) -> Self {
183 RegistrationError::NetworkError(err)
184 }
185}
186
187impl AuthsErrorInfo for SetupError {
188 fn error_code(&self) -> &'static str {
189 match self {
190 Self::IdentityAlreadyExists { .. } => "AUTHS-E5001",
191 Self::KeychainUnavailable { .. } => "AUTHS-E5002",
192 Self::CryptoError(e) => e.error_code(),
193 Self::WeakPassphrase { .. } => "AUTHS-E5008",
194 Self::StorageError(e) => e.error_code(),
195 Self::GitConfigError(_) => "AUTHS-E5004",
196 Self::InvalidSetupConfig(_) => "AUTHS-E5007",
197 Self::RegistrationFailed(e) => e.error_code(),
198 Self::PlatformVerificationFailed(_) => "AUTHS-E5006",
199 }
200 }
201
202 fn suggestion(&self) -> Option<&'static str> {
203 match self {
204 Self::IdentityAlreadyExists { .. } => {
205 Some("Use `auths id show` to inspect the existing identity")
206 }
207 Self::KeychainUnavailable { .. } => {
208 Some("Run `auths doctor` to diagnose keychain issues")
209 }
210 Self::CryptoError(e) => e.suggestion(),
211 Self::WeakPassphrase { .. } => Some(
212 "Use at least 12 characters with 3 of 4 character classes (lowercase, uppercase, digit, symbol)",
213 ),
214 Self::StorageError(e) => e.suggestion(),
215 Self::GitConfigError(_) => {
216 Some("Ensure Git is configured: git config --global user.name/email")
217 }
218 Self::InvalidSetupConfig(_) => None,
221 Self::RegistrationFailed(e) => e.suggestion(),
222 Self::PlatformVerificationFailed(_) => Some(
223 "Platform identity verification failed; check your platform credentials and network connectivity",
224 ),
225 }
226 }
227}
228
229impl AuthsErrorInfo for RotationError {
230 fn error_code(&self) -> &'static str {
231 match self {
232 Self::IdentityNotFound { .. } => "AUTHS-E5301",
233 Self::KeyNotFound(_) => "AUTHS-E5302",
234 Self::KeyDecryptionFailed(_) => "AUTHS-E5303",
235 Self::KelHistoryFailed(_) => "AUTHS-E5304",
236 Self::RotationFailed(_) => "AUTHS-E5305",
237 Self::PartialRotation(_) => "AUTHS-E5306",
238 Self::HardwareKeyNotRotatable { .. } => "AUTHS-E5307",
239 }
240 }
241
242 fn suggestion(&self) -> Option<&'static str> {
243 match self {
244 Self::IdentityNotFound { .. } => Some("Run `auths init` to create an identity first"),
245 Self::KeyNotFound(_) => Some("Run `auths key list` to see available keys"),
246 Self::KeyDecryptionFailed(_) => Some("Check your passphrase and try again"),
247 Self::KelHistoryFailed(_) => Some("Run `auths doctor` to check KEL integrity"),
248 Self::RotationFailed(_) => Some(
249 "Key rotation failed; verify your current key is accessible with `auths key list`",
250 ),
251 Self::PartialRotation(_) => {
252 Some("Re-run the rotation with the same new key to complete the keychain write")
253 }
254 Self::HardwareKeyNotRotatable { .. } => Some(
255 "Hardware-backed keys (Secure Enclave / HSM) cannot be rotated in-place; provision a software-backed identity or rotate by creating a new identity",
256 ),
257 }
258 }
259}
260
261impl AuthsErrorInfo for RegistrationError {
262 fn error_code(&self) -> &'static str {
263 match self {
264 Self::AlreadyRegistered => "AUTHS-E5401",
265 Self::QuotaExceeded => "AUTHS-E5402",
266 Self::NetworkError(e) => e.error_code(),
267 Self::InvalidDidFormat { .. } => "AUTHS-E5403",
268 Self::IdentityLoadError(_) => "AUTHS-E5404",
269 Self::RegistryReadError(_) => "AUTHS-E5405",
270 Self::SerializationError(_) => "AUTHS-E5406",
271 }
272 }
273
274 fn suggestion(&self) -> Option<&'static str> {
275 match self {
276 Self::AlreadyRegistered => Some(
277 "This identity is already registered; use `auths id show` to see registration details",
278 ),
279 Self::QuotaExceeded => Some("Wait a few minutes and try again"),
280 Self::NetworkError(e) => e.suggestion(),
281 Self::InvalidDidFormat { .. } => {
282 Some("Run `auths doctor` to check local identity data")
283 }
284 Self::IdentityLoadError(_) => Some("Run `auths doctor` to check local identity data"),
285 Self::RegistryReadError(_) => Some("Run `auths doctor` to check local identity data"),
286 Self::SerializationError(_) => Some("Run `auths doctor` to check local identity data"),
287 }
288 }
289}