pub type EvaluationResult<T> = std::result::Result<T, EvaluationError>;
#[derive(Debug, thiserror::Error)]
pub enum EvaluationError {
#[error("evaluation root could not be resolved")]
Root(#[from] crate::config::defaults::StateRootError),
#[error("evaluation directory could not be prepared")]
Directory {
#[source]
source: std::io::Error,
},
#[error("installation salt unusable: {reason}")]
Salt {
reason: &'static str,
#[source]
source: Option<std::io::Error>,
},
#[error("evaluation record could not be appended")]
Append {
#[source]
source: std::io::Error,
},
#[error("evaluation record could not be serialized")]
Serialize(#[from] serde_json::Error),
#[error("evaluation root could not be read")]
Read {
#[source]
source: std::io::Error,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn messages_carry_no_path_or_record_content() {
let errors = [
EvaluationError::Directory {
source: std::io::Error::other("/secret/state/evaluations denied"),
},
EvaluationError::Salt {
reason: "salt is a symlink",
source: None,
},
EvaluationError::Append {
source: std::io::Error::other("/secret/state/evaluations/x.jsonl"),
},
EvaluationError::Read {
source: std::io::Error::other("/secret/state"),
},
];
for error in errors {
let rendered = error.to_string();
assert!(
!rendered.contains('/'),
"the bounded warning text must stay path-free: {rendered}"
);
assert!(!rendered.contains("secret"), "{rendered}");
}
}
}