CI no longer references k8s; delete the dead k8s surface: - deploy/helm/ (the chart), ci/check-helm.sh, scripts/netpol-cluster.sh - cm-sandbox: the feature-gated K8sDriver (src/k8s.rs) + k8s_security test + the `k8s`/`k8s-tests` features + the optional kube/k8s-openapi/rustls deps (Cargo.lock drops the kube-rs tree). Nothing outside cm-sandbox referenced it. Docker (bollard) DockerDriver is the sole sandbox driver. cm-sandbox + cm-runtime compile, fmt + clippy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
65 lines
2.6 KiB
Rust
65 lines
2.6 KiB
Rust
//! Per-agent sandbox orchestration (spec §15): containers with no root, no
|
||
//! capabilities, a seccomp deny profile, read-only rootfs, and no network.
|
||
//! One `SandboxDriver` trait; the Docker implementation serves dev and the
|
||
//! air-gapped compose target.
|
||
|
||
mod docker;
|
||
mod spec;
|
||
|
||
pub use docker::DockerDriver;
|
||
pub use spec::{
|
||
DriveMount, ExecResult, ManagedSandbox, PtySession, SandboxHandle, SandboxKind, SandboxSpec,
|
||
};
|
||
|
||
/// Label every Clawmates sandbox carries, so orphans can be found + reaped
|
||
/// after a crash/restart. Value is the kind: `agent` (no egress) or `browser`.
|
||
pub const SANDBOX_LABEL: &str = "clawmates.sandbox";
|
||
|
||
/// The label value for a sandbox of the given kind.
|
||
pub fn sandbox_kind(egress: bool) -> &'static str {
|
||
if egress {
|
||
"browser"
|
||
} else {
|
||
"agent"
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, thiserror::Error)]
|
||
pub enum SandboxError {
|
||
#[error("container engine error: {0}")]
|
||
Engine(String),
|
||
#[error("sandbox not found")]
|
||
NotFound,
|
||
}
|
||
|
||
#[async_trait::async_trait]
|
||
pub trait SandboxDriver: Send + Sync {
|
||
/// Creates and starts a hardened sandbox container.
|
||
async fn provision(&self, spec: &SandboxSpec) -> Result<SandboxHandle, SandboxError>;
|
||
/// Runs a command inside the sandbox (orchestrator-initiated only; the
|
||
/// sandbox can initiate nothing outbound).
|
||
async fn exec(&self, handle: &SandboxHandle, cmd: &[&str]) -> Result<ExecResult, SandboxError>;
|
||
/// Starts an interactive PTY (`exec -it`) inside the sandbox: a TTY-backed
|
||
/// `cmd` (e.g. `["zsh","-l"]`) whose combined output streams back and whose
|
||
/// stdin accepts keystrokes. `env` adds `KEY=VALUE` vars to the session (e.g.
|
||
/// a MOTD greeting). Used by the Terminal app, not agent tools.
|
||
async fn attach_pty(
|
||
&self,
|
||
handle: &SandboxHandle,
|
||
cmd: &[&str],
|
||
cols: u16,
|
||
rows: u16,
|
||
env: &[String],
|
||
) -> Result<crate::PtySession, SandboxError>;
|
||
/// Resizes a running PTY exec's window (cols × rows).
|
||
async fn resize_pty(&self, exec_id: &str, cols: u16, rows: u16) -> Result<(), SandboxError>;
|
||
/// Stops and removes the sandbox.
|
||
async fn destroy(&self, handle: &SandboxHandle) -> Result<(), SandboxError>;
|
||
/// Whether the sandbox container is currently running.
|
||
async fn health(&self, handle: &SandboxHandle) -> Result<bool, SandboxError>;
|
||
/// List sandboxes the engine currently holds for this kind
|
||
/// (`agent`/`browser`), so the manager can reap orphans whose owning
|
||
/// process died. Filtered by the [`SANDBOX_LABEL`] label.
|
||
async fn list_managed(&self, kind: &str) -> Result<Vec<ManagedSandbox>, SandboxError>;
|
||
}
|