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}