qcs_api_client_common/configuration/
error.rs1use std::{error::Error, path::PathBuf};
2
3use crate::configuration::{oidc::DISCOVERY_REQUIRED_SCOPE, tokens::PkceFlowError};
4
5use super::ClientConfigurationBuilderError;
6use super::secrets::SECRETS_READ_ONLY_VAR;
7
8#[derive(Debug, thiserror::Error)]
10#[non_exhaustive]
11pub enum LoadError {
12 #[error("Failed to load settings: {0}")]
14 Load(Box<dyn Error + Send + Sync + 'static>),
15 #[error("Failed to load value from the environment variable {variable_name}: {message}")]
17 EnvVar {
18 variable_name: String,
20 message: String,
22 },
23 #[error("Failed to load file from path {path:?}: {message}")]
25 Path {
26 path: PathBuf,
28 message: String,
30 },
31 #[error(transparent)]
33 Io(#[from] std::io::Error),
34 #[error("Failed to build the ClientConfiguration: {0}")]
36 Build(#[from] ClientConfigurationBuilderError),
37 #[error("Expected profile {0} in settings.profiles but it does not exist")]
39 ProfileNotFound(String),
40 #[error("Expected auth server {0} in settings.auth_servers but it does not exist")]
42 AuthServerNotFound(String),
43 #[error("Failed to complete PKCE login: {0}")]
45 PkceFlow(#[from] PkceFlowError),
46 #[cfg(feature = "tracing-config")]
47 #[error("Could not parse tracing filter: {0}")]
50 TracingFilterParseError(#[from] crate::tracing_configuration::TracingFilterError),
51}
52
53impl<E: Error + 'static> From<shellexpand::LookupError<E>> for LoadError {
54 fn from(value: shellexpand::LookupError<E>) -> Self {
55 Self::EnvVar {
56 variable_name: value.var_name,
57 message: value.cause.to_string(),
58 }
59 }
60}
61
62impl From<figment::Error> for LoadError {
63 fn from(value: figment::Error) -> Self {
64 Self::Load(Box::new(value))
65 }
66}
67
68#[derive(Debug, thiserror::Error)]
70pub enum TokenError {
71 #[error("No refresh token is configured within the selected QCS credential.")]
73 NoRefreshToken,
74 #[error("No access token has been requested.")]
76 NoAccessToken,
77 #[error("Requested an access token for a configuration without credentials.")]
79 NoCredentials,
80 #[error("The access token is invalid: {0}")]
82 InvalidAccessToken(jsonwebtoken::errors::Error),
83 #[error("No auth server is configured within the selected QCS credential.")]
85 NoAuthServer,
86 #[error("Error fetching new token from the QCS API: {0}")]
88 Fetch(#[from] qcs_dependencies_client::reqwest::Error),
89 #[error("Failed to request an externally managed access token: {0}")]
91 ExternallyManaged(String),
92 #[error(
94 "Failed to write the new access token to the secrets file. Setting `{SECRETS_READ_ONLY_VAR}=true` in the environment will skip persistence of newly acquired tokens. Error details: {error}"
95 )]
96 Write {
97 error: WriteError,
99 oauth_session: Box<super::OAuthSession>,
103 },
104 #[error("Failed to fetch the OIDC discovery document: {0}")]
106 Discovery(#[from] DiscoveryError),
107}
108
109#[derive(Debug, thiserror::Error)]
111pub enum DiscoveryError {
112 #[error("invalid issuer URL: {0}")]
113 Url(#[from] url::ParseError),
114 #[error("error fetching discovery document: {0}")]
115 Fetch(#[from] qcs_dependencies_client::reqwest::Error),
116 #[error("failed to parse discovery document: {0}")]
117 Json(#[from] serde_json::Error),
118 #[error("issuer URL ({issuer}) is invalid: {reason}")]
119 InvalidIssuer { issuer: String, reason: String },
120 #[error("discovery document is invalid: {reason}")]
121 InvalidDocument { reason: String },
122 #[error("discovery document issuer ({document}) does not match the queried issuer ({query})")]
123 IssuerMismatch { document: String, query: String },
124 #[error("discovery document `supported_scopes` does not include the required minimum scope \"{expected}\", received: {0:?}", expected = DISCOVERY_REQUIRED_SCOPE)]
125 InvalidScopes(Vec<String>),
126}
127
128#[derive(Debug, thiserror::Error)]
130pub enum WriteError {
131 #[error(transparent)]
133 IoWithPath(#[from] IoErrorWithPath),
134 #[error("File could not be read as TOML: {0}")]
136 InvalidToml(#[from] toml_edit::TomlError),
137 #[error("The table `{0}` does not exist.")]
139 MissingTable(String),
140 #[error("Error formatting time: {0}.")]
142 TimeFormat(#[from] time::error::Format),
143 #[error("Error writing or persisting temporary secrets file during access token refresh: {0}")]
145 TempFile(#[from] async_tempfile::Error),
146}
147
148#[derive(Debug)]
150pub enum IoOperation {
151 Open,
152 Read,
153 Write,
154 Rename { dest: PathBuf },
155 GetMetadata,
156 SetPermissions,
157 Flush,
158}
159
160#[derive(Debug, thiserror::Error)]
162#[error("Io error while error performing {operation:?} on {path}: {error}")]
163pub struct IoErrorWithPath {
164 #[source]
165 pub error: std::io::Error,
166 pub path: PathBuf,
167 pub operation: IoOperation,
168}