auths_sdk/error.rs
1use thiserror::Error;
2
3/// Wrapper for storage errors originating from `auths-id` traits.
4/// Preserves the full error display string from the underlying storage layer.
5///
6/// Usage:
7/// ```ignore
8/// storage.save(data)
9/// .map_err(|e| SetupError::StorageError(SdkStorageError::OperationFailed(e.to_string())))?;
10/// ```
11#[derive(Debug, Error)]
12pub enum SdkStorageError {
13 /// A storage operation failed with the given message.
14 #[error("storage operation failed: {0}")]
15 OperationFailed(String),
16}
17
18/// Errors from identity setup operations (developer, CI, agent).
19///
20/// Usage:
21/// ```ignore
22/// match sdk_result {
23/// Err(SetupError::IdentityAlreadyExists { did }) => { /* reuse or abort */ }
24/// Err(e) => return Err(e.into()),
25/// Ok(result) => { /* success */ }
26/// }
27/// ```
28#[derive(Debug, Error)]
29#[non_exhaustive]
30pub enum SetupError {
31 /// An identity already exists at the configured path.
32 #[error("identity already exists: {did}")]
33 IdentityAlreadyExists {
34 /// The DID of the existing identity.
35 did: String,
36 },
37
38 /// The platform keychain is unavailable or inaccessible.
39 #[error("keychain unavailable ({backend}): {reason}")]
40 KeychainUnavailable {
41 /// The keychain backend name (e.g. "macOS Keychain").
42 backend: String,
43 /// The reason the keychain is unavailable.
44 reason: String,
45 },
46
47 /// A cryptographic operation failed.
48 #[error("crypto error: {0}")]
49 CryptoError(#[source] auths_core::AgentError),
50
51 /// A storage operation failed.
52 #[error("storage error: {0}")]
53 StorageError(#[source] SdkStorageError),
54
55 /// Setting a git configuration key failed.
56 #[error("git config error: {0}")]
57 GitConfigError(String),
58
59 /// Remote registry registration failed.
60 #[error("registration failed: {0}")]
61 RegistrationFailed(#[source] RegistrationError),
62
63 /// Platform identity verification failed.
64 #[error("platform verification failed: {0}")]
65 PlatformVerificationFailed(String),
66}
67
68/// Errors from device linking and revocation operations.
69///
70/// Usage:
71/// ```ignore
72/// match link_result {
73/// Err(DeviceError::IdentityNotFound { did }) => { /* identity missing */ }
74/// Err(e) => return Err(e.into()),
75/// Ok(result) => { /* success */ }
76/// }
77/// ```
78#[derive(Debug, Error)]
79#[non_exhaustive]
80pub enum DeviceError {
81 /// The identity could not be found in storage.
82 #[error("identity not found: {did}")]
83 IdentityNotFound {
84 /// The DID that was not found.
85 did: String,
86 },
87
88 /// The device could not be found in attestation records.
89 #[error("device not found: {did}")]
90 DeviceNotFound {
91 /// The DID of the missing device.
92 did: String,
93 },
94
95 /// Attestation creation or validation failed.
96 #[error("attestation error: {0}")]
97 AttestationError(String),
98
99 /// A cryptographic operation failed.
100 #[error("crypto error: {0}")]
101 CryptoError(#[source] auths_core::AgentError),
102
103 /// A storage operation failed.
104 #[error("storage error: {0}")]
105 StorageError(#[source] SdkStorageError),
106}
107
108/// Errors from device authorization extension operations.
109///
110/// Usage:
111/// ```ignore
112/// match extend_result {
113/// Err(DeviceExtensionError::AlreadyRevoked { device_did }) => { /* already gone */ }
114/// Err(e) => return Err(e.into()),
115/// Ok(result) => { /* success */ }
116/// }
117/// ```
118#[derive(Debug, Error)]
119#[non_exhaustive]
120pub enum DeviceExtensionError {
121 /// The identity could not be found in storage.
122 #[error("identity not found")]
123 IdentityNotFound,
124
125 /// No attestation exists for the specified device.
126 #[error("no attestation found for device {device_did}")]
127 NoAttestationFound {
128 /// The DID of the device with no attestation.
129 device_did: String,
130 },
131
132 /// The device has already been revoked.
133 #[error("device {device_did} is already revoked")]
134 AlreadyRevoked {
135 /// The DID of the revoked device.
136 device_did: String,
137 },
138
139 /// Creating a new attestation failed.
140 #[error("attestation creation failed: {0}")]
141 AttestationFailed(String),
142
143 /// A storage operation failed.
144 #[error("storage error: {0}")]
145 StorageError(String),
146}
147
148/// Errors from identity rotation operations.
149///
150/// Usage:
151/// ```ignore
152/// match rotate_result {
153/// Err(RotationError::KelHistoryFailed(msg)) => { /* no prior events */ }
154/// Err(e) => return Err(e.into()),
155/// Ok(result) => { /* success */ }
156/// }
157/// ```
158#[derive(Debug, Error)]
159#[non_exhaustive]
160pub enum RotationError {
161 /// The identity was not found at the expected path.
162 #[error("identity not found at {path}")]
163 IdentityNotFound {
164 /// The filesystem path where the identity was expected.
165 path: std::path::PathBuf,
166 },
167
168 /// The requested key alias was not found in the keychain.
169 #[error("key not found: {0}")]
170 KeyNotFound(String),
171
172 /// Decrypting the key material failed (e.g. wrong passphrase).
173 #[error("key decryption failed: {0}")]
174 KeyDecryptionFailed(String),
175
176 /// Reading or validating the KEL history failed.
177 #[error("KEL history error: {0}")]
178 KelHistoryFailed(String),
179
180 /// The rotation operation failed.
181 #[error("rotation failed: {0}")]
182 RotationFailed(String),
183
184 /// KEL event was written but the new key could not be persisted to the keychain.
185 /// Recovery: re-run rotation with the same new key to replay the keychain write.
186 #[error(
187 "rotation event committed to KEL but keychain write failed — manual recovery required: {0}"
188 )]
189 PartialRotation(String),
190}
191
192/// Errors from remote registry operations.
193///
194/// Usage:
195/// ```ignore
196/// match register_result {
197/// Err(RegistrationError::AlreadyRegistered) => { /* skip */ }
198/// Err(RegistrationError::QuotaExceeded) => { /* retry later */ }
199/// Err(e) => return Err(e.into()),
200/// Ok(outcome) => { /* success */ }
201/// }
202/// ```
203#[derive(Debug, Error)]
204#[non_exhaustive]
205pub enum RegistrationError {
206 /// The identity is already registered at the target registry.
207 #[error("identity already registered at this registry")]
208 AlreadyRegistered,
209
210 /// The registration rate limit has been exceeded.
211 #[error("registration quota exceeded — try again later")]
212 QuotaExceeded,
213
214 /// A network error occurred during registration.
215 #[error("network error: {0}")]
216 NetworkError(#[source] auths_core::ports::network::NetworkError),
217
218 /// Local identity or attestation data is invalid.
219 #[error("local data error: {0}")]
220 LocalDataError(String),
221}
222
223impl From<auths_core::AgentError> for SetupError {
224 fn from(err: auths_core::AgentError) -> Self {
225 SetupError::CryptoError(err)
226 }
227}
228
229impl From<RegistrationError> for SetupError {
230 fn from(err: RegistrationError) -> Self {
231 SetupError::RegistrationFailed(err)
232 }
233}
234
235impl From<auths_core::AgentError> for DeviceError {
236 fn from(err: auths_core::AgentError) -> Self {
237 DeviceError::CryptoError(err)
238 }
239}
240
241impl From<auths_core::ports::network::NetworkError> for RegistrationError {
242 fn from(err: auths_core::ports::network::NetworkError) -> Self {
243 RegistrationError::NetworkError(err)
244 }
245}
246
247/// Errors from organization member management workflows.
248///
249/// Usage:
250/// ```ignore
251/// match result {
252/// Err(OrgError::AdminNotFound { .. }) => { /* 403 Forbidden */ }
253/// Err(OrgError::MemberNotFound { .. }) => { /* 404 Not Found */ }
254/// Err(e) => return Err(e.into()),
255/// Ok(att) => { /* proceed */ }
256/// }
257/// ```
258#[derive(Debug, Error)]
259#[non_exhaustive]
260pub enum OrgError {
261 /// No admin matching the given public key was found in the organization.
262 #[error("no admin with the given public key found in organization '{org}'")]
263 AdminNotFound {
264 /// The organization identifier.
265 org: String,
266 },
267
268 /// The specified member was not found in the organization.
269 #[error("member '{did}' not found in organization '{org}'")]
270 MemberNotFound {
271 /// The organization identifier.
272 org: String,
273 /// The DID of the member that was not found.
274 did: String,
275 },
276
277 /// The member has already been revoked.
278 #[error("member '{did}' is already revoked")]
279 AlreadyRevoked {
280 /// The DID of the already-revoked member.
281 did: String,
282 },
283
284 /// The capability string could not be parsed.
285 #[error("invalid capability '{cap}': {reason}")]
286 InvalidCapability {
287 /// The invalid capability string.
288 cap: String,
289 /// The reason parsing failed.
290 reason: String,
291 },
292
293 /// The organization DID is malformed.
294 #[error("invalid organization DID: {0}")]
295 InvalidDid(String),
296
297 /// The hex-encoded public key is invalid.
298 #[error("invalid public key: {0}")]
299 InvalidPublicKey(String),
300
301 /// A storage operation failed.
302 #[error("storage error: {0}")]
303 Storage(String),
304}