Class ContainerSandbox

java.lang.Object
com.tnsai.quality.sandbox.ContainerSandbox
All Implemented Interfaces:
Sandbox, AutoCloseable

public final class ContainerSandbox extends Object implements Sandbox
Sandbox backend that runs commands inside a fresh container per execute(com.tnsai.quality.sandbox.Command) call (TNS-296). Uses the configured container CLI (docker or podman); each invocation is <runtime> run --rm with all sandbox policy translated to runtime flags.

Provides (vs ProcessSandbox)

  • Real network isolation — --network=none for NetPolicy.DenyAll, --network=host for NetPolicy.Inherit.
  • CPU + memory + pids caps via --cpus, --memory, --pids-limit.
  • Read-write mounts — sandbox writes propagate back to the host because we use a real bind mount, not copy-in.
  • Root FS read-only — --read-only + --tmpfs /tmp:size=<diskMb>m for scratch.

Cannot provide (deferred)

  • NetPolicy.AllowList — implementing host whitelisting requires either a custom network with iptables rules or a proxy sidecar; v2. The factory rejects AllowList specs at create time so consumers can't build a silently-permissive sandbox.

Lifetime

Per-execute container model: each execute(com.tnsai.quality.sandbox.Command) invocation spins up a fresh container (with --rm) and tears it down when the command exits. This trades the ~150–300 ms cold-start cost per call for simpler lifecycle and zero leaked containers on JVM crash. SandboxPool (phase 4) reuses sandboxes when warmable, but the underlying container is still per-execute today.
Since:
0.10.0 (TNS-296)
  • Method Details

    • spec

      public SandboxSpec spec()
      Description copied from interface: Sandbox
      The SandboxSpec this instance was created from. Useful for downstream tooling (audit, observability) that needs to record the configured policy alongside the result.
      Specified by:
      spec in interface Sandbox
    • execute

      public SandboxResult execute(Command command)
      Description copied from interface: Sandbox
      Run command to completion (or until the sandbox kills it for exceeding ResourceLimits.timeout). Always returns a SandboxResult; failures inside the sandbox are reflected in SandboxResult.exitCode and SandboxResult.stderr, not thrown.

      Throws if the sandbox itself has been terminated, or if the backend layer cannot dispatch the command (image missing, runtime crash). Those are infrastructure failures, distinct from "the user's command exited non-zero".

      Specified by:
      execute in interface Sandbox
    • stop

      public void stop()
      Description copied from interface: Sandbox
      Graceful shutdown. Backends SHOULD send SIGTERM (or the platform equivalent), wait a short grace period, then promote to Sandbox.terminate() if the process is still running.
      Specified by:
      stop in interface Sandbox
    • terminate

      public void terminate()
      Description copied from interface: Sandbox
      Forcibly kill the sandbox and release its resources. Idempotent — calling on an already-terminated sandbox is a no-op. Safe in finally blocks.
      Specified by:
      terminate in interface Sandbox