Skip to main content

soma_fleet/
request.rs

1use std::path::{Component, PathBuf};
2
3/// Invalid fleet command or transfer request.
4#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
5#[non_exhaustive]
6pub enum RequestError {
7    /// Program was empty, oversized, or contained control characters.
8    #[error("invalid command program")]
9    InvalidProgram,
10    /// One positional argument was invalid.
11    #[error("invalid command argument at index {index}")]
12    InvalidArgument {
13        /// Invalid argument position.
14        index: usize,
15    },
16    /// Too many positional arguments were supplied.
17    #[error("command has {count} arguments; maximum is {max}")]
18    TooManyArguments {
19        /// Supplied argument count.
20        count: usize,
21        /// Maximum accepted count.
22        max: usize,
23    },
24    /// Working or transfer path was not absolute and normalized.
25    #[error("fleet path must be absolute and contain no parent traversal: {0}")]
26    InvalidAbsolutePath(PathBuf),
27    /// Output budget was zero or exceeded the hard ceiling.
28    #[error("invalid {stream} output limit: {bytes} bytes")]
29    InvalidOutputLimit {
30        /// Output stream.
31        stream: &'static str,
32        /// Requested byte limit.
33        bytes: usize,
34    },
35    /// Command stdin exceeded the hard ceiling.
36    #[error("invalid command stdin length: {bytes} bytes; maximum is {max}")]
37    InvalidStdinLimit {
38        /// Supplied stdin bytes.
39        bytes: usize,
40        /// Hard maximum.
41        max: usize,
42    },
43    /// Transfer byte bound was zero or exceeded the hard ceiling.
44    #[error("invalid transfer limit {bytes}; maximum is {max}")]
45    InvalidTransferLimit {
46        /// Requested byte limit.
47        bytes: u64,
48        /// Hard maximum.
49        max: u64,
50    },
51    /// Request deadline was not in the future.
52    #[error("fleet request deadline has elapsed")]
53    DeadlineElapsed,
54    /// Content digest was not lowercase SHA-256.
55    #[error("invalid SHA-256 digest")]
56    InvalidSha256,
57}
58
59pub(crate) fn validate_absolute_path(path: PathBuf) -> Result<PathBuf, RequestError> {
60    if !path.is_absolute()
61        || path
62            .components()
63            .any(|component| matches!(component, Component::ParentDir | Component::CurDir))
64    {
65        Err(RequestError::InvalidAbsolutePath(path))
66    } else {
67        Ok(path)
68    }
69}
70
71#[cfg(test)]
72#[path = "request_tests.rs"]
73mod tests;