use thiserror::Error;
#[derive(Error, Debug)]
pub enum AgentTrustError {
#[error("authentication failed: {message}")]
Authentication {
message: String,
status: u16,
},
#[error("authorization denied: {message}")]
Authorization {
message: String,
status: u16,
},
#[error("validation error: {message}")]
Validation {
message: String,
status: u16,
},
#[error("not found: {message}")]
NotFound {
message: String,
status: u16,
},
#[error("network error: {0}")]
Network(#[from] reqwest::Error),
#[error("action denied: {message}")]
ActionDenied {
message: String,
check_id: Option<String>,
},
#[error("elevation required: {message}")]
ElevationRequired {
message: String,
approval_id: String,
},
#[error("guardian unavailable: {message}")]
GuardianUnavailable {
message: String,
},
#[error("api error ({status}): {message}")]
Api {
message: String,
code: String,
status: u16,
},
#[error("json error: {0}")]
Json(#[from] serde_json::Error),
}
pub type Result<T> = std::result::Result<T, AgentTrustError>;
pub(crate) fn error_from_status(status: u16, message: String) -> AgentTrustError {
match status {
401 => AgentTrustError::Authentication { message, status },
403 => AgentTrustError::Authorization { message, status },
400 => AgentTrustError::Validation { message, status },
404 => AgentTrustError::NotFound { message, status },
_ => AgentTrustError::Api {
message,
code: format!("HTTP_{}", status),
status,
},
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_from_status_401() {
let err = error_from_status(401, "bad key".to_string());
assert!(matches!(
err,
AgentTrustError::Authentication { status: 401, .. }
));
assert!(err.to_string().contains("bad key"));
}
#[test]
fn test_error_from_status_403() {
let err = error_from_status(403, "forbidden".to_string());
assert!(matches!(
err,
AgentTrustError::Authorization { status: 403, .. }
));
}
#[test]
fn test_error_from_status_400() {
let err = error_from_status(400, "invalid".to_string());
assert!(matches!(
err,
AgentTrustError::Validation { status: 400, .. }
));
}
#[test]
fn test_error_from_status_404() {
let err = error_from_status(404, "not found".to_string());
assert!(matches!(err, AgentTrustError::NotFound { status: 404, .. }));
}
#[test]
fn test_error_from_status_500() {
let err = error_from_status(500, "server error".to_string());
match err {
AgentTrustError::Api { code, status, .. } => {
assert_eq!(code, "HTTP_500");
assert_eq!(status, 500);
}
_ => panic!("expected AgentTrustError::Api"),
}
}
#[test]
fn test_error_display() {
let err = AgentTrustError::ActionDenied {
message: "not allowed".to_string(),
check_id: Some("chk-1".to_string()),
};
assert_eq!(err.to_string(), "action denied: not allowed");
}
}