Files
clawmates/crates/tc-runtime/tests/warm_pool.rs
T
Omar SobhandClaude Fable 5 05e9612688 Post-1.0: Localhost seccomp on K8s, warm sandbox pool, server HPA
- K8sDriver.with_localhost_seccomp(profile): sandbox pods run under the
  STRICT allowlist instead of the runtime default. Proven live on kind:
  the harness installs the profile onto the node, a pod runs ordinary
  work as uid 10001, and unshare is kernel-denied inside the pod — the
  same probe the Docker suite uses, now passing on both targets
- Helm: sandbox.seccomp=localhost renders a DaemonSet that installs the
  chart-shipped profile into /var/lib/kubelet/seccomp on every node
  (ConfigMap + hostPath); ci/check-helm.sh enforces the chart copy stays
  byte-identical to images/seccomp/agent-profile.json and asserts the
  hardened render (DaemonSet + profile + HPA)
- server HPA (autoscaling/v2, CPU target) behind
  server.autoscaling.enabled
- SandboxManager.warm(n): a background warmer keeps n pre-provisioned
  sandboxes ready so an agent's first exec skips container startup;
  unhealthy pool entries are discarded, reuse never drains the pool,
  shutdown destroys assigned AND pooled. [sandbox] warm_pool config
  (default 0). Real-Docker test: prefill -> assign -> refill -> reuse ->
  clean shutdown

160 Rust tests + 4 live kind tests.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 11:15:49 -05:00

81 lines
2.4 KiB
Rust

//! Warm sandbox pool: pre-provisioned containers absorb the first-exec
//! latency. Real Docker — the pool fills in the background, an exec
//! takes a sandbox from it, and the warmer restores the target.
use std::process::Command;
use std::sync::Arc;
use std::time::Duration;
use tc_domain::AgentId;
use tc_runtime::SandboxManager;
use tc_sandbox::DockerDriver;
const IMAGE: &str = "teamclaw/agent-base:dev";
fn ensure_image() {
let exists = Command::new("docker")
.args(["image", "inspect", IMAGE])
.output()
.expect("docker available")
.status
.success();
if !exists {
let root = env!("CARGO_MANIFEST_DIR");
let status = Command::new("docker")
.args([
"build",
"-t",
IMAGE,
"-f",
&format!("{root}/../../images/agent-base/Dockerfile"),
&format!("{root}/../../images/agent-base"),
])
.status()
.expect("docker build runs");
assert!(status.success());
}
}
async fn pool_reaches(manager: &SandboxManager, target: usize) {
for _ in 0..120 {
if manager.pool_size().await == target {
return;
}
tokio::time::sleep(Duration::from_millis(250)).await;
}
panic!(
"pool never reached {target} (now {})",
manager.pool_size().await
);
}
#[tokio::test]
async fn the_pool_prefills_assigns_and_refills() {
ensure_image();
let driver: Arc<dyn tc_sandbox::SandboxDriver> =
Arc::new(DockerDriver::connect().expect("docker reachable"));
let manager = Arc::new(SandboxManager::new(driver, IMAGE)).warm(2);
// The warmer fills the pool without any exec happening.
pool_reaches(&manager, 2).await;
// An exec is served from the pool — and works.
let agent = AgentId::new();
let result = manager.exec(agent, "id -u").await.unwrap();
assert_eq!(result.stdout.trim(), "10001");
// The warmer restores the target while the agent keeps its sandbox.
pool_reaches(&manager, 2).await;
let again = manager.exec(agent, "echo still-mine").await.unwrap();
assert_eq!(again.stdout.trim(), "still-mine");
assert_eq!(
manager.pool_size().await,
2,
"reuse must not drain the pool"
);
// Shutdown destroys assigned AND pooled sandboxes.
manager.shutdown().await;
assert_eq!(manager.pool_size().await, 0);
}