Files
agent-sandbox/src/cli.rs
Kristóf Tóth 12644ae31e Apply a seccomp-BPF syscall allowlist by default
Derived from Podman's default profile, stripped of capability-conditional
rules (we never grant capabilities), argument filters, and the explicit
EPERM block. Dangerous syscalls (mount, unshare, ptrace, bpf,
perf_event_open, io_uring_*, keyctl, kexec_*, ...) fall through to the
default ENOSYS action, which also keeps glibc's clone3 -> clone fallback
working. x86_64 and aarch64 are supported; other archs error out.

Toggle with --seccomp / --no-seccomp or seccomp = <bool> in config.
2026-04-08 08:34:34 +02:00

93 lines
3.1 KiB
Rust

use std::ffi::OsString;
use std::path::PathBuf;
use clap::Parser;
#[derive(Parser, Debug, Default)]
#[command(
name = "agent-sandbox",
version,
about = "Sandbox agentic coding assistants with bubblewrap"
)]
pub struct Args {
/// Blacklist mode: bind / read-only, overlay sensitive paths (default)
#[arg(long, conflicts_with = "whitelist")]
pub blacklist: bool,
/// Whitelist mode: only explicitly listed minimal paths visible
#[arg(long)]
pub whitelist: bool,
/// Harden: unshare IPC, PID, UTS; private /tmp, /dev, /run
#[arg(long, overrides_with = "no_hardened")]
pub hardened: bool,
/// Disable hardening (overrides config-file `hardened = true`)
#[arg(long, overrides_with = "hardened")]
pub no_hardened: bool,
/// Unshare the network namespace
#[arg(long, overrides_with = "share_net")]
pub unshare_net: bool,
/// Share the host network namespace (overrides config-file `unshare-net = true`)
#[arg(long, overrides_with = "unshare_net")]
pub share_net: bool,
/// Enable seccomp syscall filtering (on by default; overrides config-file `seccomp = false`)
#[arg(long, overrides_with = "no_seccomp")]
pub seccomp: bool,
/// Disable seccomp syscall filtering (overrides config-file `seccomp = true`)
#[arg(long, overrides_with = "seccomp")]
pub no_seccomp: bool,
/// Bind an extra path read-write (repeatable)
#[arg(long = "rw", value_name = "PATH", action = clap::ArgAction::Append)]
pub extra_rw: Vec<PathBuf>,
/// Bind an extra path read-only (repeatable)
#[arg(long = "ro", value_name = "PATH", action = clap::ArgAction::Append)]
pub extra_ro: Vec<PathBuf>,
/// Print the bwrap command without executing
#[arg(long, overrides_with = "no_dry_run")]
pub dry_run: bool,
/// Disable dry-run (overrides config-file `dry-run = true`)
#[arg(long, overrides_with = "dry_run")]
pub no_dry_run: bool,
/// Working directory inside the sandbox (default: current directory)
#[arg(long, value_name = "PATH")]
pub chdir: Option<PathBuf>,
/// Use a named profile from the config file
#[arg(long, conflicts_with = "no_config")]
pub profile: Option<String>,
/// Path to config file (default: $XDG_CONFIG_HOME/agent-sandbox/config.toml)
#[arg(long = "config", value_name = "PATH", conflicts_with = "no_config")]
pub config_path: Option<PathBuf>,
/// Skip loading the config file entirely
#[arg(long)]
pub no_config: bool,
/// Hide a path inside the sandbox with a tmpfs overlay (repeatable)
#[arg(long = "mask", value_name = "PATH", action = clap::ArgAction::Append)]
pub mask: Vec<PathBuf>,
/// Pass an arbitrary argument directly to bwrap (repeatable)
#[arg(long = "bwrap-arg", value_name = "ARG", action = clap::ArgAction::Append)]
pub bwrap_args: Vec<String>,
/// Run this binary with the trailing args as its arguments
#[arg(long, value_name = "CMD")]
pub entrypoint: Option<String>,
/// Command and arguments to run inside the sandbox
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
pub command_and_args: Vec<OsString>,
}