signstar_config/error.rs
1//! Common, top-level error type for all components of signstar-config.
2
3use std::{
4 path::PathBuf,
5 process::{ExitCode, ExitStatus},
6 string::FromUtf8Error,
7};
8
9/// An error that may occur when using Signstar config.
10#[derive(Debug, thiserror::Error)]
11pub enum Error {
12 /// An error specific to administrative secret handling.
13 #[error("Error with administrative secret handling:\n{0}")]
14 AdminSecretHandling(#[from] crate::admin_credentials::Error),
15
16 /// An error specific to Signstar config handling.
17 /// Applying permissions to a file or directory failed.
18 #[error("Unable to apply permissions from mode {mode} to {path}:\n{source}")]
19 ApplyPermissions {
20 /// The path to a file for which permissions can not be applied.
21 path: PathBuf,
22 /// The file mode that should be applied for `path`.
23 mode: u32,
24 /// The source error.
25 source: std::io::Error,
26 },
27
28 /// The ownership of a path can not be changed.
29 #[error("Changing ownership of {path} to user {user} failed:\n{source}")]
30 Chown {
31 /// The path to a file for which ownership can not be changed.
32 path: PathBuf,
33 /// The system user that should be the new owner of `path`.
34 user: String,
35 /// The source error.
36 source: std::io::Error,
37 },
38
39 /// Unable to attach to stdin of a command.
40 #[error("Unable to attach to stdin of command \"{command}\"")]
41 CommandAttachToStdin {
42 /// The command for which attaching to stdin failed.
43 command: String,
44 },
45
46 /// A command exited unsuccessfully.
47 #[error("The command \"{command}\" could not be started in the background:\n{source}")]
48 CommandBackground {
49 /// The command that could not be started in the background.
50 command: String,
51 /// The source error.
52 source: std::io::Error,
53 },
54
55 /// A command could not be executed.
56 #[error("The command \"{command}\" could not be executed:\n{source}")]
57 CommandExec {
58 /// The command that could not be executed.
59 command: String,
60 /// The source error.
61 source: std::io::Error,
62 },
63
64 /// A command exited unsuccessfully.
65 #[error(
66 "The command \"{command}\" exited with non-zero status code \"{exit_status}\":\nstderr:\n{stderr}"
67 )]
68 CommandNonZero {
69 /// The command that exited with a non-zero exit code.
70 command: String,
71 /// The exit status of `command`.
72 exit_status: ExitStatus,
73 /// The stderr of `command`.
74 stderr: String,
75 },
76
77 /// Unable to write to stdin of a command.
78 #[error("Unable to write to stdin of command \"{command}\"")]
79 CommandWriteToStdin {
80 /// The command for which writing to stdin failed.
81 command: String,
82 /// The source error.
83 source: std::io::Error,
84 },
85
86 /// Configuration errors.
87 #[error("Signstar config error:\n{0}")]
88 Config(#[from] crate::ConfigError),
89
90 /// An I/O error occurred for a file.
91 #[error("I/O error for file {path} while {context}: {source}")]
92 IoPath {
93 /// The path to the file for which the error occurred.
94 path: PathBuf,
95 /// The context in which the error occurs.
96 ///
97 /// This is meant to complete the sentence "I/O error for file {path} while ".
98 context: &'static str,
99 /// The error source.
100 source: std::io::Error,
101 },
102
103 /// A NetHSM error.
104 #[error("NetHSM error:\n{0}")]
105 NetHsm(#[from] nethsm::Error),
106
107 /// A NetHSM backend error
108 ///
109 /// This variant is used when actions for a NetHSM backend fail.
110 #[error("NetHSM backend error:\n{0}")]
111 NetHsmBackend(#[from] crate::NetHsmBackendError),
112
113 /// An error specific to non-administrative secret handling.
114 #[error("Error with non-administrative secret handling:\n{0}")]
115 NonAdminSecretHandling(#[from] crate::non_admin_credentials::Error),
116
117 /// Low-level administrative credentials handling in signstar-common failed.
118 #[error("Handling of administrative credentials failed:\n{0}")]
119 SignstarCommonAdminCreds(#[from] signstar_common::admin_credentials::Error),
120
121 /// Joining a thread returned an error.
122 #[error("Thread error while {context}")]
123 Thread {
124 /// The context in which the failed thread ran.
125 ///
126 /// Should complete the sentence "Thread error while ".
127 context: String,
128 },
129
130 /// TOML error while reading a file.
131 #[error("TOML read error for file {path} while {context}: {source}")]
132 TomlRead {
133 /// The path to a file that fails to read.
134 path: PathBuf,
135 /// The context in which the error occurs.
136 ///
137 /// This is meant to complete the sentence " error for file {path} while ".
138 context: &'static str,
139 /// The error source.
140 source: Box<toml::de::Error>,
141 },
142
143 /// TOML error while writing a file.
144 #[error("TOML write error for file {path} while {context}: {source}")]
145 TomlWrite {
146 /// The path to a file that fails to read.
147 path: PathBuf,
148 /// The context in which the error occurs.
149 ///
150 /// This is meant to complete the sentence " error for file {path} while ".
151 context: &'static str,
152 /// The error source.
153 source: toml::ser::Error,
154 },
155
156 /// A UTF-8 error occurred when trying to convert a byte vector to a string.
157 #[error("Converting contents of {path} to string failed while {context}:\n{source}")]
158 Utf8String {
159 /// The path to a file for which conversion to UTF-8 string failed.
160 path: PathBuf,
161 /// The context in which the error occurred.
162 ///
163 /// Should complete the sentence "Converting contents of `path` to string failed while "
164 context: String,
165 /// The source error.
166 source: FromUtf8Error,
167 },
168
169 /// A utility function returned an error.
170 #[error("Utility function error: {0}")]
171 Utils(#[from] crate::utils::Error),
172}
173
174/// Mapping for relevant [`Error`] variants to an [`ExitCode`].
175#[derive(Clone, Copy, Debug, Eq, num_enum::IntoPrimitive, Ord, PartialEq, PartialOrd)]
176#[repr(u8)]
177pub enum ErrorExitCode {
178 /// Mapping for [`crate::admin_credentials::Error::AdministratorMissing`] wrapped in
179 /// [`Error::AdminSecretHandling`].
180 AdminCredentialsAdministratorMissing = 100,
181
182 /// Mapping for [`crate::admin_credentials::Error::AdministratorNoDefault`] wrapped in
183 /// [`Error::AdminSecretHandling`].
184 AdminCredentialsAdministratorNoDefault = 101,
185
186 /// Mapping for [`crate::admin_credentials::Error::CredsFileCreate`] wrapped in
187 /// [`Error::AdminSecretHandling`].
188 AdminCredentialsCredsFileCreate = 102,
189
190 /// Mapping for [`crate::admin_credentials::Error::CredsFileMissing`] wrapped in
191 /// [`Error::AdminSecretHandling`].
192 AdminCredentialsCredsFileMissing = 103,
193
194 /// Mapping for [`crate::admin_credentials::Error::CredsFileNotAFile`] wrapped in
195 /// [`Error::AdminSecretHandling`].
196 AdminCredentialsCredsFileNotAFile = 104,
197
198 /// Mapping for [`crate::admin_credentials::Error::CredsFileWrite`] wrapped in
199 /// [`Error::AdminSecretHandling`].
200 AdminCredentialsCredsFileWrite = 105,
201
202 /// Mapping for [`crate::admin_credentials::Error::PassphraseTooShort`] wrapped in
203 /// [`Error::AdminSecretHandling`].
204 AdminCredentialsPassphraseTooShort = 106,
205
206 /// Mapping for [`Error::ApplyPermissions`].
207 ApplyPermissions = 10,
208
209 /// Mapping for [`Error::Chown`].
210 Chown = 11,
211
212 /// Mapping for [`Error::CommandAttachToStdin`].
213 CommandAttachToStdin = 12,
214
215 /// Mapping for [`Error::CommandBackground`].
216 CommandBackground = 13,
217
218 /// Mapping for [`Error::CommandExec`].
219 CommandExec = 14,
220
221 /// Mapping for [`Error::CommandNonZero`].
222 CommandNonZero = 15,
223
224 /// Mapping for [`Error::CommandWriteToStdin`].
225 CommandWriteToStdin = 16,
226
227 /// Mapping for [`crate::ConfigError::ConfigIsMissing`] wrapped in [`Error::Config`].
228 ConfigConfigMissing = 120,
229
230 /// Mapping for [`crate::ConfigError::DuplicateNetHsmUserId`] wrapped in
231 /// [`Error::Config`].
232 ConfigDuplicateNetHsmUserId = 121,
233
234 /// Mapping for [`crate::ConfigError::DuplicateSshPublicKey`] wrapped in
235 /// [`Error::Config`].
236 ConfigDuplicateSshPublicKey = 122,
237
238 /// Mapping for [`crate::ConfigError::DuplicateKeyId`] wrapped in [`Error::Config`].
239 ConfigDuplicateKeyId = 123,
240
241 /// Mapping for [`crate::ConfigError::DuplicateSystemUserId`] wrapped in
242 /// [`Error::Config`].
243 ConfigDuplicateSystemUserId = 124,
244
245 /// Mapping for [`crate::ConfigError::DuplicateTag`] wrapped in [`Error::Config`].
246 ConfigDuplicateTag = 125,
247
248 /// Mapping for [`crate::ConfigError::InvalidSystemUserName`] wrapped in
249 /// [`Error::Config`].
250 ConfigInvalidSystemUserName = 126,
251
252 /// Mapping for [`crate::ConfigError::InvalidAuthorizedKeyEntry`] wrapped in
253 /// [`Error::Config`].
254 ConfigInvalidAuthorizedKeyEntry = 127,
255
256 /// Mapping for [`crate::ConfigError::MetricsAlsoOperator`] wrapped in
257 /// [`Error::Config`].
258 ConfigMetricsAlsoOperator = 128,
259
260 /// Mapping for [`crate::ConfigError::MissingAdministrator`] wrapped in
261 /// [`Error::Config`].
262 ConfigMissingAdministrator = 129,
263
264 /// Mapping for [`crate::ConfigError::MissingShareDownloadSystemUser`] wrapped in
265 /// [`Error::Config`].
266 ConfigMissingShareDownloadSystemUser = 130,
267
268 /// Mapping for [`crate::ConfigError::MissingShareUploadSystemUser`] wrapped in
269 /// [`Error::Config`].
270 ConfigMissingShareUploadSystemUser = 131,
271
272 /// Mapping for [`crate::ConfigError::NoAuthorizedKeys`] wrapped in [`Error::Config`].
273 ConfigNoAuthorizedKeys = 132,
274
275 /// Mapping for [`crate::ConfigError::NoMatchingMappingForSystemUser`] wrapped in
276 /// [`Error::Config`].
277 ConfigNoMatchingMappingForSystemUser = 133,
278
279 /// Mapping for [`crate::ConfigError::NoSssButShareUsers`] wrapped in [`Error::Config`].
280 ConfigNoSssButShareUsers = 134,
281
282 /// Mapping for [`crate::ConfigError::SshKey`] wrapped in [`Error::Config`].
283 ConfigSshKey = 135,
284
285 /// Mapping for [`crate::ConfigError::User`] wrapped in [`Error::Config`].
286 ConfigUser = 136,
287
288 /// Mapping for [`crate::ConfigError::SystemWideUserIdWithNamespace`] wrapped in
289 /// [`Error::Config`].
290 ConfigSystemWideUserIdWithNamespace = 137,
291
292 /// Mapping for [`crate::Error::NetHsm`].
293 IoPath = 17,
294
295 /// Mapping for [`crate::Error::NetHsm`].
296 NetHsm = 18,
297
298 /// Mapping for [`crate::Error::NetHsmBackend`].
299 NetHsmBackend = 19,
300
301 /// Mapping for [`crate::non_admin_credentials::Error::CredentialsLoading`] wrapped in
302 /// [`Error::NonAdminSecretHandling`].
303 NonAdminCredentialsCredentialsLoading = 140,
304
305 /// Mapping for [`crate::non_admin_credentials::Error::CredentialsMissing`] wrapped in
306 /// [`Error::NonAdminSecretHandling`].
307 NonAdminCredentialsCredentialsMissing = 141,
308
309 /// Mapping for [`crate::non_admin_credentials::Error::NoSystemUser`] wrapped in
310 /// [`Error::NonAdminSecretHandling`].
311 NonAdminCredentialsNoSystemUser = 142,
312
313 /// Mapping for [`crate::non_admin_credentials::Error::NotSigningUser`] wrapped in
314 /// [`Error::NonAdminSecretHandling`].
315 NonAdminCredentialsNotSigningUser = 143,
316
317 /// Mapping for [`crate::non_admin_credentials::Error::SecretsDirCreate`] wrapped in
318 /// [`Error::NonAdminSecretHandling`].
319 NonAdminCredentialsSecretsDirCreate = 144,
320
321 /// Mapping for [`crate::non_admin_credentials::Error::SecretsFileCreate`] wrapped in
322 /// [`Error::NonAdminSecretHandling`].
323 NonAdminCredentialsSecretsFileCreate = 145,
324
325 /// Mapping for [`crate::non_admin_credentials::Error::SecretsFileMetadata`] wrapped in
326 /// [`Error::NonAdminSecretHandling`].
327 NonAdminCredentialsSecretsFileMetadata = 146,
328
329 /// Mapping for [`crate::non_admin_credentials::Error::SecretsFileMissing`] wrapped in
330 /// [`Error::NonAdminSecretHandling`].
331 NonAdminCredentialsSecretsFileMissing = 147,
332
333 /// Mapping for [`crate::non_admin_credentials::Error::SecretsFileNotAFile`] wrapped in
334 /// [`Error::NonAdminSecretHandling`].
335 NonAdminCredentialsSecretsFileNotAFile = 148,
336
337 /// Mapping for [`crate::non_admin_credentials::Error::SecretsFilePermissions`] wrapped in
338 /// [`Error::NonAdminSecretHandling`].
339 NonAdminCredentialsSecretsFilePermissions = 149,
340
341 /// Mapping for [`crate::non_admin_credentials::Error::SecretsFileRead`] wrapped in
342 /// [`Error::NonAdminSecretHandling`].
343 NonAdminCredentialsSecretsFileRead = 150,
344
345 /// Mapping for [`crate::non_admin_credentials::Error::SecretsFileWrite`] wrapped in
346 /// [`Error::NonAdminSecretHandling`].
347 NonAdminCredentialsSecretsFileWrite = 151,
348
349 /// Mapping for [`signstar_common::admin_credentials::Error::ApplyPermissions`] wrapped in
350 /// [`Error::SignstarCommonAdminCreds`].
351 SignstarCommonAdminCredsApplyPermissions = 170,
352
353 /// Mapping for [`signstar_common::admin_credentials::Error::CreateDirectory`] wrapped in
354 /// [`Error::SignstarCommonAdminCreds`].
355 SignstarCommonAdminCredsCreateDirectory = 171,
356
357 /// Mapping for [`signstar_common::admin_credentials::Error::DirChangeOwner`] wrapped in
358 /// [`Error::SignstarCommonAdminCreds`].
359 SignstarCommonAdminCredsDirChangeOwner = 172,
360
361 /// Mapping for [`Error::Thread`].
362 Thread = 20,
363
364 /// Mapping for [`Error::TomlRead`].
365 TomlRead = 21,
366
367 /// Mapping for [`Error::TomlWrite`].
368 TomlWrite = 22,
369
370 /// Mapping for [`Error::Utf8String`].
371 Utf8String = 23,
372
373 /// Mapping for [`crate::utils::Error::ExecutableNotFound`] wrapped in [`Error::Utils`].
374 UtilsExecutableNotFound = 190,
375
376 /// Mapping for [`crate::utils::Error::MappingSystemUserGet`] wrapped in [`Error::Utils`].
377 UtilsMappingSystemUserGet = 191,
378
379 /// Mapping for [`crate::utils::Error::SystemUserData`] wrapped in [`Error::Utils`].
380 UtilsSystemUserData = 192,
381
382 /// Mapping for [`crate::utils::Error::SystemUserLookup`] wrapped in [`Error::Utils`].
383 UtilsSystemUserLookup = 193,
384
385 /// Mapping for [`crate::utils::Error::SystemUserMismatch`] wrapped in [`Error::Utils`].
386 UtilsSystemUserMismatch = 194,
387
388 /// Mapping for [`crate::utils::Error::SystemUserNotRoot`] wrapped in [`Error::Utils`].
389 UtilsSystemUserNotRoot = 195,
390
391 /// Mapping for [`crate::utils::Error::SystemUserRoot`] wrapped in [`Error::Utils`].
392 UtilsSystemUserRoot = 196,
393}
394
395impl From<Error> for ErrorExitCode {
396 fn from(value: Error) -> Self {
397 match value {
398 // admin credentials related errors and their exit codes
399 Error::AdminSecretHandling(error) => match error {
400 crate::admin_credentials::Error::AdministratorMissing => {
401 Self::AdminCredentialsAdministratorMissing
402 }
403 crate::admin_credentials::Error::AdministratorNoDefault => {
404 Self::AdminCredentialsAdministratorNoDefault
405 }
406 crate::admin_credentials::Error::CredsFileCreate { .. } => {
407 Self::AdminCredentialsCredsFileCreate
408 }
409 crate::admin_credentials::Error::CredsFileMissing { .. } => {
410 Self::AdminCredentialsCredsFileMissing
411 }
412 crate::admin_credentials::Error::CredsFileNotAFile { .. } => {
413 Self::AdminCredentialsCredsFileNotAFile
414 }
415 crate::admin_credentials::Error::CredsFileWrite { .. } => {
416 Self::AdminCredentialsCredsFileWrite
417 }
418 crate::admin_credentials::Error::PassphraseTooShort { .. } => {
419 Self::AdminCredentialsPassphraseTooShort
420 }
421 },
422 // config related errors
423 Error::Config(error) => match error {
424 crate::ConfigError::ConfigIsMissing => Self::ConfigConfigMissing,
425 crate::ConfigError::DuplicateNetHsmUserId { .. } => {
426 Self::ConfigDuplicateNetHsmUserId
427 }
428 crate::ConfigError::DuplicateSshPublicKey { .. } => {
429 Self::ConfigDuplicateSshPublicKey
430 }
431 crate::ConfigError::DuplicateKeyId { .. } => Self::ConfigDuplicateKeyId,
432 crate::ConfigError::DuplicateSystemUserId { .. } => {
433 Self::ConfigDuplicateSystemUserId
434 }
435 crate::ConfigError::DuplicateTag { .. } => Self::ConfigDuplicateTag,
436 crate::ConfigError::InvalidSystemUserName { .. } => {
437 Self::ConfigInvalidSystemUserName
438 }
439 crate::ConfigError::InvalidAuthorizedKeyEntry { .. } => {
440 Self::ConfigInvalidAuthorizedKeyEntry
441 }
442 crate::ConfigError::MetricsAlsoOperator { .. } => Self::ConfigMetricsAlsoOperator,
443 crate::ConfigError::MissingAdministrator { .. } => Self::ConfigMissingAdministrator,
444 crate::ConfigError::MissingShareDownloadSystemUser => {
445 Self::ConfigMissingShareDownloadSystemUser
446 }
447 crate::ConfigError::MissingShareUploadSystemUser => {
448 Self::ConfigMissingShareUploadSystemUser
449 }
450 crate::ConfigError::NoAuthorizedKeys => Self::ConfigNoAuthorizedKeys,
451 crate::ConfigError::NoMatchingMappingForSystemUser { .. } => {
452 Self::ConfigNoMatchingMappingForSystemUser
453 }
454 crate::ConfigError::NoSssButShareUsers { .. } => Self::ConfigNoSssButShareUsers,
455 crate::ConfigError::SshKey(_) => Self::ConfigSshKey,
456 crate::ConfigError::User(_) => Self::ConfigUser,
457 crate::ConfigError::SystemWideUserIdWithNamespace(_) => {
458 Self::ConfigSystemWideUserIdWithNamespace
459 }
460 },
461 // NetHSM related errors
462 Error::NetHsm(_) => Self::NetHsm,
463 // NetHSM backend related errors
464 Error::NetHsmBackend(_) => Self::NetHsmBackend,
465 // non-admin credentials related errors and their exit codes
466 Error::NonAdminSecretHandling(error) => match error {
467 crate::non_admin_credentials::Error::CredentialsLoading { .. } => {
468 Self::NonAdminCredentialsCredentialsLoading
469 }
470 crate::non_admin_credentials::Error::CredentialsMissing { .. } => {
471 Self::NonAdminCredentialsCredentialsMissing
472 }
473 crate::non_admin_credentials::Error::NoSystemUser => {
474 Self::NonAdminCredentialsNoSystemUser
475 }
476 crate::non_admin_credentials::Error::NotSigningUser => {
477 Self::NonAdminCredentialsNotSigningUser
478 }
479 crate::non_admin_credentials::Error::SecretsDirCreate { .. } => {
480 Self::NonAdminCredentialsSecretsDirCreate
481 }
482 crate::non_admin_credentials::Error::SecretsFileCreate { .. } => {
483 Self::NonAdminCredentialsSecretsFileCreate
484 }
485 crate::non_admin_credentials::Error::SecretsFileMetadata { .. } => {
486 Self::NonAdminCredentialsSecretsFileMetadata
487 }
488 crate::non_admin_credentials::Error::SecretsFileMissing { .. } => {
489 Self::NonAdminCredentialsSecretsFileMissing
490 }
491 crate::non_admin_credentials::Error::SecretsFileNotAFile { .. } => {
492 Self::NonAdminCredentialsSecretsFileNotAFile
493 }
494 crate::non_admin_credentials::Error::SecretsFilePermissions { .. } => {
495 Self::NonAdminCredentialsSecretsFilePermissions
496 }
497 crate::non_admin_credentials::Error::SecretsFileRead { .. } => {
498 Self::NonAdminCredentialsSecretsFileRead
499 }
500 crate::non_admin_credentials::Error::SecretsFileWrite { .. } => {
501 Self::NonAdminCredentialsSecretsFileWrite
502 }
503 },
504 // signstar-common admin credentials related errors
505 Error::SignstarCommonAdminCreds(error) => match error {
506 signstar_common::admin_credentials::Error::ApplyPermissions { .. } => {
507 Self::SignstarCommonAdminCredsApplyPermissions
508 }
509 signstar_common::admin_credentials::Error::CreateDirectory { .. } => {
510 Self::SignstarCommonAdminCredsCreateDirectory
511 }
512 signstar_common::admin_credentials::Error::DirChangeOwner { .. } => {
513 Self::SignstarCommonAdminCredsDirChangeOwner
514 }
515 },
516 // utils related errors
517 Error::Utils(error) => match error {
518 crate::utils::Error::ExecutableNotFound { .. } => Self::UtilsExecutableNotFound,
519 crate::utils::Error::MappingSystemUserGet(_) => Self::UtilsMappingSystemUserGet,
520 crate::utils::Error::SystemUserData { .. } => Self::UtilsSystemUserData,
521 crate::utils::Error::SystemUserLookup { .. } => Self::UtilsSystemUserLookup,
522 crate::utils::Error::SystemUserMismatch { .. } => Self::UtilsSystemUserMismatch,
523 crate::utils::Error::SystemUserNotRoot { .. } => Self::UtilsSystemUserNotRoot,
524 crate::utils::Error::SystemUserRoot => Self::UtilsSystemUserRoot,
525 },
526 // top-level errors and their exit codes
527 Error::ApplyPermissions { .. } => Self::ApplyPermissions,
528 Error::CommandAttachToStdin { .. } => Self::CommandAttachToStdin,
529 Error::Chown { .. } => Self::Chown,
530 Error::CommandBackground { .. } => Self::CommandBackground,
531 Error::CommandExec { .. } => Self::CommandExec,
532 Error::CommandNonZero { .. } => Self::CommandNonZero,
533 Error::CommandWriteToStdin { .. } => Self::CommandWriteToStdin,
534 Error::IoPath { .. } => Self::IoPath,
535 Error::Thread { .. } => Self::Thread,
536 Error::TomlRead { .. } => Self::TomlRead,
537 Error::TomlWrite { .. } => Self::TomlWrite,
538 Error::Utf8String { .. } => Self::Utf8String,
539 }
540 }
541}
542
543impl From<ErrorExitCode> for ExitCode {
544 fn from(value: ErrorExitCode) -> Self {
545 Self::from(std::convert::Into::<u8>::into(value))
546 }
547}
548
549impl From<ErrorExitCode> for i32 {
550 fn from(value: ErrorExitCode) -> Self {
551 Self::from(std::convert::Into::<u8>::into(value))
552 }
553}