Skip to main content

siem_core/
error.rs

1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum SiemError {
5    #[error("Authentication failed: {0}")]
6    AuthError(String),
7
8    #[error("Connection failed: {0}")]
9    ConnectionError(String),
10
11    #[error("API error ({status}): {message}")]
12    ApiError { status: u16, message: String },
13
14    #[error("Not found: {0}")]
15    NotFound(String),
16
17    #[error("Invalid configuration: {0}")]
18    ConfigError(String),
19
20    #[error("Serialization error: {0}")]
21    SerializationError(String),
22
23    #[error("Provider error [{provider}]: {message}")]
24    ProviderError { provider: String, message: String },
25
26    #[error("{0}")]
27    Other(String),
28}
29
30pub type SiemResult<T> = Result<T, SiemError>;
31
32impl From<serde_json::Error> for SiemError {
33    fn from(err: serde_json::Error) -> Self {
34        SiemError::SerializationError(err.to_string())
35    }
36}
37
38// =============================================================================
39// Serializable error DTO (for JSON transport in invoke payloads)
40// =============================================================================
41
42/// Wire-safe error representation for InvokeCapability JSON payloads.
43#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
44pub struct SiemApiError {
45    pub error_type: String,
46    pub message: String,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub status: Option<u16>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub provider: Option<String>,
51}
52
53impl From<&SiemError> for SiemApiError {
54    fn from(err: &SiemError) -> Self {
55        match err {
56            SiemError::AuthError(msg) => SiemApiError {
57                error_type: "auth".to_string(),
58                message: msg.clone(),
59                status: Some(401),
60                provider: None,
61            },
62            SiemError::ConnectionError(msg) => SiemApiError {
63                error_type: "connection".to_string(),
64                message: msg.clone(),
65                status: None,
66                provider: None,
67            },
68            SiemError::ApiError { status, message } => SiemApiError {
69                error_type: "api".to_string(),
70                message: message.clone(),
71                status: Some(*status),
72                provider: None,
73            },
74            SiemError::NotFound(msg) => SiemApiError {
75                error_type: "not_found".to_string(),
76                message: msg.clone(),
77                status: Some(404),
78                provider: None,
79            },
80            SiemError::ConfigError(msg) => SiemApiError {
81                error_type: "config".to_string(),
82                message: msg.clone(),
83                status: None,
84                provider: None,
85            },
86            SiemError::SerializationError(msg) => SiemApiError {
87                error_type: "serialization".to_string(),
88                message: msg.clone(),
89                status: None,
90                provider: None,
91            },
92            SiemError::ProviderError { provider, message } => SiemApiError {
93                error_type: "provider".to_string(),
94                message: message.clone(),
95                status: None,
96                provider: Some(provider.clone()),
97            },
98            SiemError::Other(msg) => SiemApiError {
99                error_type: "other".to_string(),
100                message: msg.clone(),
101                status: None,
102                provider: None,
103            },
104        }
105    }
106}
107
108impl From<SiemApiError> for SiemError {
109    fn from(err: SiemApiError) -> Self {
110        match err.error_type.as_str() {
111            "auth" => SiemError::AuthError(err.message),
112            "connection" => SiemError::ConnectionError(err.message),
113            "api" => SiemError::ApiError {
114                status: err.status.unwrap_or(500),
115                message: err.message,
116            },
117            "not_found" => SiemError::NotFound(err.message),
118            "config" => SiemError::ConfigError(err.message),
119            "serialization" => SiemError::SerializationError(err.message),
120            "provider" => SiemError::ProviderError {
121                provider: err.provider.unwrap_or_default(),
122                message: err.message,
123            },
124            _ => SiemError::Other(err.message),
125        }
126    }
127}