Skip to main content

confium_sandbox_process/
error.rs

1//! Error type for the process sandbox crate.
2//!
3//! Mirrors the snafu-based pattern used across confium crates. All
4//! public [`Sandbox`](crate::Sandbox) / [`SandboxInstance`](crate::SandboxInstance)
5//! operations surface these via [`Result`].
6//!
7//! Error codes share the sandbox block (`0x2000..`), offset to a
8//! distinct sub-range (`0x2100..`) so they do not collide with the
9//! WASM sandbox codes when both are in play.
10
11use snafu::Backtrace;
12use snafu::Snafu;
13
14#[derive(Snafu, Debug)]
15#[snafu(visibility(pub))]
16pub enum Error {
17    /// The plugin path passed to [`Sandbox::load_module`](crate::Sandbox::load_module)
18    /// was not valid UTF-8.
19    #[snafu(display("plugin path was not valid UTF-8: {}", source))]
20    InvalidPath {
21        source: std::str::Utf8Error,
22        backtrace: Backtrace,
23    },
24    /// Spawning the plugin subprocess failed (binary missing, no
25    /// execute permission, etc.).
26    #[snafu(display("failed to spawn plugin subprocess: {}", source))]
27    Spawn {
28        source: std::io::Error,
29        backtrace: Backtrace,
30    },
31    /// Writing a request frame to the plugin's stdin failed.
32    #[snafu(display("failed to write request to plugin stdin: {}", source))]
33    WriteRequest {
34        source: std::io::Error,
35        backtrace: Backtrace,
36    },
37    /// Reading a response frame from the plugin's stdout failed (EOF,
38    /// truncated length header, etc.).
39    #[snafu(display("failed to read response from plugin stdout: {}", source))]
40    ReadResponse {
41        source: std::io::Error,
42        backtrace: Backtrace,
43    },
44    /// A response frame was malformed JSON, or did not match the
45    /// expected protocol shape.
46    #[snafu(display("malformed plugin protocol message: {}", reason))]
47    Protocol {
48        reason: String,
49        backtrace: Backtrace,
50    },
51    /// The plugin reported an error for the call.
52    #[snafu(display("plugin returned error for '{}': {}", method, message))]
53    PluginError {
54        method: String,
55        message: String,
56        backtrace: Backtrace,
57    },
58    /// An argument value could not be marshaled to/from the protocol
59    /// (e.g. `Value::Bytes` on a path that only carries scalars).
60    #[snafu(display("argument type mismatch for function '{}'", function))]
61    ArgumentType {
62        function: String,
63        backtrace: Backtrace,
64    },
65    /// The requested function is not exported by the plugin.
66    #[snafu(display("plugin function '{}' not found", function))]
67    FunctionNotFound {
68        function: String,
69        backtrace: Backtrace,
70    },
71}
72
73impl Error {
74    /// Numeric error code for the process sandbox ABI. Disjoint from
75    /// core (1..), TC (0x1000..), and the WASM sandbox (0x2000..);
76    /// process sandbox codes begin at 0x2100.
77    pub fn code(&self) -> u32 {
78        match self {
79            Error::InvalidPath { .. } => 0x2100,
80            Error::Spawn { .. } => 0x2101,
81            Error::WriteRequest { .. } => 0x2102,
82            Error::ReadResponse { .. } => 0x2103,
83            Error::Protocol { .. } => 0x2104,
84            Error::PluginError { .. } => 0x2105,
85            Error::ArgumentType { .. } => 0x2106,
86            Error::FunctionNotFound { .. } => 0x2107,
87        }
88    }
89}
90
91pub type Result<T> = std::result::Result<T, Error>;
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96    use snafu::GenerateImplicitData;
97
98    #[test]
99    fn error_codes_are_in_process_range() {
100        let err = Error::Protocol {
101            reason: "x".to_string(),
102            backtrace: Backtrace::generate(),
103        };
104        assert!(err.code() >= 0x2100);
105        assert!(err.code() < 0x2200);
106    }
107
108    #[test]
109    fn codes_are_disjoint_from_wasm_sandbox() {
110        // WASM sandbox uses 0x2000..; process sandbox must not collide.
111        let err = Error::PluginError {
112            method: "m".to_string(),
113            message: "boom".to_string(),
114            backtrace: Backtrace::generate(),
115        };
116        assert!(err.code() >= 0x2100);
117    }
118
119    #[test]
120    fn spawn_code_is_stable() {
121        let err = Error::Spawn {
122            source: std::io::Error::new(std::io::ErrorKind::NotFound, "missing"),
123            backtrace: Backtrace::generate(),
124        };
125        assert_eq!(err.code(), 0x2101);
126    }
127}