1use serde::{Deserialize, Serialize};
10use std::error::Error as StdError;
11use std::fmt;
12
13pub type Result<T> = std::result::Result<T, CleanroomError>;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct CleanroomError {
19 pub kind: ErrorKind,
21 pub message: String,
23 pub context: Option<String>,
25 pub source: Option<String>,
27 pub timestamp: chrono::DateTime<chrono::Utc>,
29}
30
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
33pub enum ErrorKind {
34 ContainerError,
36 NetworkError,
38 ResourceLimitExceeded,
40 Timeout,
42 ConfigurationError,
44 PolicyViolation,
46 DeterministicError,
48 CoverageError,
50 SnapshotError,
52 TracingError,
54 RedactionError,
56 ReportError,
58 IoError,
60 SerializationError,
62 ValidationError,
64 ServiceError,
66 InternalError,
68 TemplateError,
70 NotImplementedError,
72}
73
74impl CleanroomError {
75 pub fn new(kind: ErrorKind, message: impl Into<String>) -> Self {
77 Self {
78 kind,
79 message: message.into(),
80 context: None,
81 source: None,
82 timestamp: chrono::Utc::now(),
83 }
84 }
85
86 pub fn with_context(mut self, context: impl Into<String>) -> Self {
88 self.context = Some(context.into());
89 self
90 }
91
92 pub fn with_source(mut self, source: impl Into<String>) -> Self {
94 self.source = Some(source.into());
95 self
96 }
97
98 pub fn container_error(message: impl Into<String>) -> Self {
100 Self::new(ErrorKind::ContainerError, message)
101 }
102
103 pub fn network_error(message: impl Into<String>) -> Self {
105 Self::new(ErrorKind::NetworkError, message)
106 }
107
108 pub fn resource_limit_exceeded(message: impl Into<String>) -> Self {
110 Self::new(ErrorKind::ResourceLimitExceeded, message)
111 }
112
113 pub fn timeout_error(message: impl Into<String>) -> Self {
115 Self::new(ErrorKind::Timeout, message)
116 }
117
118 pub fn configuration_error(message: impl Into<String>) -> Self {
120 Self::new(ErrorKind::ConfigurationError, message)
121 }
122
123 pub fn policy_violation_error(message: impl Into<String>) -> Self {
125 Self::new(ErrorKind::PolicyViolation, message)
126 }
127
128 pub fn deterministic_error(message: impl Into<String>) -> Self {
130 Self::new(ErrorKind::DeterministicError, message)
131 }
132
133 pub fn coverage_error(message: impl Into<String>) -> Self {
135 Self::new(ErrorKind::CoverageError, message)
136 }
137
138 pub fn snapshot_error(message: impl Into<String>) -> Self {
140 Self::new(ErrorKind::SnapshotError, message)
141 }
142
143 pub fn tracing_error(message: impl Into<String>) -> Self {
145 Self::new(ErrorKind::TracingError, message)
146 }
147
148 pub fn redaction_error(message: impl Into<String>) -> Self {
150 Self::new(ErrorKind::RedactionError, message)
151 }
152
153 pub fn report_error(message: impl Into<String>) -> Self {
155 Self::new(ErrorKind::ReportError, message)
156 }
157
158 pub fn connection_failed(message: impl Into<String>) -> Self {
160 Self::new(ErrorKind::NetworkError, message)
161 }
162
163 pub fn service_error(message: impl Into<String>) -> Self {
165 Self::new(ErrorKind::ServiceError, message)
166 }
167
168 pub fn io_error(message: impl Into<String>) -> Self {
170 Self::new(ErrorKind::IoError, message)
171 }
172
173 pub fn serialization_error(message: impl Into<String>) -> Self {
175 Self::new(ErrorKind::SerializationError, message)
176 }
177
178 pub fn validation_error(message: impl Into<String>) -> Self {
180 Self::new(ErrorKind::ValidationError, message)
181 }
182
183 pub fn internal_error(message: impl Into<String>) -> Self {
185 Self::new(ErrorKind::InternalError, message)
186 }
187
188 pub fn config_error(message: impl Into<String>) -> Self {
190 Self::configuration_error(message)
191 }
192
193 pub fn execution_error(message: impl Into<String>) -> Self {
195 Self::internal_error(message)
196 }
197
198 pub fn template_error(message: impl Into<String>) -> Self {
200 Self::new(ErrorKind::TemplateError, message)
201 }
202
203 pub fn not_implemented(message: impl Into<String>) -> Self {
205 Self::new(ErrorKind::NotImplementedError, message)
206 }
207}
208
209impl fmt::Display for CleanroomError {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 write!(f, "{:?}: {}", self.kind, self.message)?;
212 if let Some(context) = &self.context {
213 write!(f, " (Context: {})", context)?;
214 }
215 if let Some(source) = &self.source {
216 write!(f, " (Source: {})", source)?;
217 }
218 Ok(())
219 }
220}
221
222impl StdError for CleanroomError {
223 fn source(&self) -> Option<&(dyn StdError + 'static)> {
224 None
226 }
227}
228
229impl From<std::io::Error> for CleanroomError {
231 fn from(err: std::io::Error) -> Self {
232 CleanroomError::io_error(err.to_string())
233 }
234}
235
236impl From<clnrm_template::TemplateError> for CleanroomError {
238 fn from(err: clnrm_template::TemplateError) -> Self {
239 match err {
240 clnrm_template::TemplateError::RenderError(msg) => CleanroomError::template_error(msg),
241 clnrm_template::TemplateError::ConfigError(msg) => CleanroomError::config_error(msg),
242 clnrm_template::TemplateError::IoError(msg) => CleanroomError::io_error(msg),
243 clnrm_template::TemplateError::ValidationError(msg) => {
244 CleanroomError::validation_error(msg)
245 }
246 clnrm_template::TemplateError::InternalError(msg) => {
247 CleanroomError::internal_error(msg)
248 }
249 }
250 }
251}
252
253impl From<serde_json::Error> for CleanroomError {
254 fn from(err: serde_json::Error) -> Self {
255 CleanroomError::serialization_error(err.to_string())
256 }
257}
258
259impl From<testcontainers::TestcontainersError> for CleanroomError {
260 fn from(err: testcontainers::TestcontainersError) -> Self {
261 CleanroomError::container_error(err.to_string())
262 }
263}
264
265impl From<BackendError> for CleanroomError {
266 fn from(err: BackendError) -> Self {
267 match err {
268 BackendError::Runtime(msg) => CleanroomError::internal_error(msg),
269 BackendError::CommandExecution(msg) => CleanroomError::internal_error(msg),
270 BackendError::ContainerStartup(msg) => CleanroomError::container_error(msg),
271 BackendError::ContainerCommunication(msg) => CleanroomError::container_error(msg),
272 BackendError::ImagePull(msg) => CleanroomError::container_error(msg),
273 BackendError::ImageBuild(msg) => CleanroomError::container_error(msg),
274 BackendError::UnsupportedFeature(msg) => CleanroomError::internal_error(msg),
275 }
276 }
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
285pub enum BackendError {
286 Runtime(String),
288 CommandExecution(String),
290 ContainerStartup(String),
292 ContainerCommunication(String),
294 ImagePull(String),
296 ImageBuild(String),
298 UnsupportedFeature(String),
300}
301
302impl fmt::Display for BackendError {
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 write!(f, "{:?}", self)
305 }
306}
307
308impl StdError for BackendError {}
309
310#[derive(Debug, Clone, Serialize, Deserialize)]
312pub enum PolicyError {
313 InvalidPolicy(String),
315 PolicyViolation(String),
317 UnsupportedFeature(String),
319}
320
321impl fmt::Display for PolicyError {
322 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
323 write!(f, "{:?}", self)
324 }
325}
326
327impl StdError for PolicyError {}
328
329#[derive(Debug, Clone, Serialize, Deserialize)]
331pub enum ScenarioError {
332 InvalidScenario(String),
334 StepExecutionFailed(String),
336 ScenarioTimeout(String),
338 ConcurrentExecution(String),
340}
341
342impl fmt::Display for ScenarioError {
343 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344 write!(f, "{:?}", self)
345 }
346}
347
348impl StdError for ScenarioError {}
349
350#[derive(Debug, Clone, Serialize, Deserialize)]
352pub enum ServiceError {
353 ConnectionFailed(String),
355 StartupFailed(String),
357 HealthCheckFailed(String),
359 Configuration(String),
361 UnsupportedOperation(String),
363}
364
365impl fmt::Display for ServiceError {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 write!(f, "{:?}", self)
368 }
369}
370
371impl StdError for ServiceError {}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
375pub enum ConfigError {
376 InvalidFile(String),
378 MissingValue(String),
380 InvalidValue(String),
382 InvalidPattern(String, String),
384}
385
386impl fmt::Display for ConfigError {
387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388 write!(f, "{:?}", self)
389 }
390}
391
392impl StdError for ConfigError {}