Files
agent-sandbox/src/errors.rs
T
2026-04-24 20:09:27 +02:00

130 lines
4.7 KiB
Rust

use std::path::PathBuf;
#[derive(Debug)]
pub enum SandboxError {
HomeNotSet,
RunUserNotFound,
BwrapNotFound,
CommandNotFound(PathBuf),
CommandNotExecutable(PathBuf),
PathMissing(PathBuf),
ChdirMissing(PathBuf),
CurrentDirUnavailable(std::io::Error),
GlobPattern(glob::PatternError),
Io(std::io::Error),
ConfigRead {
path: PathBuf,
source: std::io::Error,
},
ConfigParse {
path: PathBuf,
source: toml::de::Error,
},
ProfileNotFound(String),
ConflictingMode,
ConflictingEnvKey(String),
InvalidEnvEntry(String),
UnknownConfigKey(String),
NestedExtraConfig(PathBuf),
ConfigPathNotAbsolute(PathBuf),
InvalidBwrapArg(String),
InvalidBindSpec(String),
NoCommand,
Seccomp(String),
SeccompUnsupportedArch(String),
}
impl std::fmt::Display for SandboxError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::HomeNotSet => write!(
f,
"$HOME is not set; cannot determine which paths to protect"
),
Self::RunUserNotFound => write!(
f,
"cannot determine XDG_RUNTIME_DIR; tried $XDG_RUNTIME_DIR and /proc/self/status"
),
Self::BwrapNotFound => write!(
f,
"bwrap not found; install bubblewrap (e.g. `apt install bubblewrap` or `pacman -S bubblewrap`)"
),
Self::CommandNotFound(p) => write!(f, "command not found: {}", p.display()),
Self::CommandNotExecutable(p) => {
write!(f, "command is not executable: {}", p.display())
}
Self::PathMissing(p) => write!(f, "path does not exist: {}", p.display()),
Self::ChdirMissing(p) => write!(f, "--chdir path does not exist: {}", p.display()),
Self::CurrentDirUnavailable(e) => write!(f, "cannot determine current directory: {e}"),
Self::GlobPattern(e) => write!(f, "invalid glob pattern: {e}"),
Self::Io(e) => write!(f, "I/O error: {e}"),
Self::ConfigRead { path, source } => {
write!(f, "cannot read config file '{}': {source}", path.display())
}
Self::ConfigParse { path, source } => {
write!(f, "cannot parse config file '{}': {source}", path.display())
}
Self::ProfileNotFound(name) => write!(f, "profile not found in config: {name}"),
Self::ConflictingMode => write!(
f,
"config section sets both blacklist and whitelist to true"
),
Self::ConflictingEnvKey(key) => {
write!(f, "conflicting environment variable options for key: {key}")
}
Self::InvalidEnvEntry(raw) => {
write!(f, "invalid env entry (expected KEY or KEY=VALUE): {raw:?}")
}
Self::UnknownConfigKey(key) => write!(f, "unknown config key: {key}"),
Self::NestedExtraConfig(p) => write!(
f,
"extra-config file '{}' sets its own extra-config (nesting not supported)",
p.display()
),
Self::ConfigPathNotAbsolute(p) => {
write!(f, "config path is not absolute: {}", p.display())
}
Self::InvalidBwrapArg(s) => {
write!(f, "invalid quoting in --bwrap-arg: {s}")
}
Self::InvalidBindSpec(s) => {
write!(f, "invalid bind spec (expected SRC or SRC:DST): {s:?}")
}
Self::NoCommand => write!(
f,
"no command to run; specify a command via config, entrypoint, or pass one after --"
),
Self::Seccomp(msg) => write!(f, "failed to build seccomp filter: {msg}"),
Self::SeccompUnsupportedArch(arch) => write!(
f,
"seccomp filtering is not supported on this architecture: {arch} (use --no-seccomp to disable)"
),
}
}
}
impl std::error::Error for SandboxError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::CurrentDirUnavailable(e) => Some(e),
Self::GlobPattern(e) => Some(e),
Self::Io(e) => Some(e),
Self::ConfigRead { source, .. } => Some(source),
Self::ConfigParse { source, .. } => Some(source),
_ => None,
}
}
}
impl From<std::io::Error> for SandboxError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl From<glob::PatternError> for SandboxError {
fn from(e: glob::PatternError) -> Self {
Self::GlobPattern(e)
}
}