Skip to main content

soma_infra/
error.rs

1use std::path::PathBuf;
2
3use soma_fleet::{FleetError, HostId};
4
5const PUBLIC_DIAGNOSTIC_LIMIT: usize = 2048;
6
7/// Result type for neutral infrastructure operations.
8pub type InfraResult<T> = Result<T, InfraError>;
9
10/// Product-neutral infrastructure operation failure.
11#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
12#[non_exhaustive]
13pub enum InfraError {
14    /// Fleet transport or topology failed.
15    #[error(transparent)]
16    Fleet(#[from] FleetError),
17    /// A typed request violated a closed contract.
18    #[error("invalid {domain} request: {message}")]
19    InvalidRequest {
20        /// Infrastructure domain.
21        domain: &'static str,
22        /// Corrective detail.
23        message: String,
24    },
25    /// The target transport cannot execute the requested driver.
26    #[error("{domain} operation is unsupported for host {host}")]
27    UnsupportedTarget {
28        /// Infrastructure domain.
29        domain: &'static str,
30        /// Target host.
31        host: HostId,
32    },
33    /// A bounded command returned a non-zero status.
34    #[error("{domain} command failed on {host} with exit {exit_code:?}: {stderr}")]
35    CommandFailed {
36        /// Infrastructure domain.
37        domain: &'static str,
38        /// Target host.
39        host: HostId,
40        /// Process exit status when available.
41        exit_code: Option<i32>,
42        /// Bounded stderr text.
43        stderr: String,
44    },
45    /// Driver output could not be parsed into the neutral contract.
46    #[error("failed to parse {domain} output: {message}")]
47    Parse {
48        /// Infrastructure domain.
49        domain: &'static str,
50        /// Parse detail.
51        message: String,
52    },
53    /// Descriptor-confined filesystem access failed.
54    #[error("filesystem {operation} failed for {path}: {message}")]
55    Filesystem {
56        /// Read operation.
57        operation: &'static str,
58        /// Requested path.
59        path: PathBuf,
60        /// Failure detail.
61        message: String,
62    },
63    /// Requested path was not within an admitted read root.
64    #[error("path is outside admitted read roots: {0}")]
65    PathOutsideRoots(PathBuf),
66    /// Docker API access failed.
67    #[error("Docker access failed: {0}")]
68    Docker(String),
69}
70
71pub(crate) fn public_diagnostic(bytes: &[u8]) -> String {
72    #[derive(Clone, Copy)]
73    enum EscapeState {
74        None,
75        Escape,
76        ControlSequence,
77    }
78
79    let text = String::from_utf8_lossy(bytes);
80    let mut sanitized = String::with_capacity(text.len().min(PUBLIC_DIAGNOSTIC_LIMIT));
81    let mut escape = EscapeState::None;
82    for character in text.chars() {
83        match escape {
84            EscapeState::Escape => {
85                escape = if character == '[' {
86                    EscapeState::ControlSequence
87                } else {
88                    EscapeState::None
89                };
90                continue;
91            }
92            EscapeState::ControlSequence => {
93                if ('@'..='~').contains(&character) {
94                    escape = EscapeState::None;
95                }
96                continue;
97            }
98            EscapeState::None => {}
99        }
100        if character == '\u{1b}' {
101            escape = EscapeState::Escape;
102            continue;
103        }
104        if character.is_control() {
105            if !sanitized.ends_with(' ') && sanitized.len() < PUBLIC_DIAGNOSTIC_LIMIT {
106                sanitized.push(' ');
107            }
108        } else if sanitized.len() + character.len_utf8() <= PUBLIC_DIAGNOSTIC_LIMIT {
109            sanitized.push(character);
110        } else {
111            break;
112        }
113    }
114    sanitized.trim().to_owned()
115}
116
117#[cfg(test)]
118#[path = "error_tests.rs"]
119mod tests;