sandbox

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package sandbox provides isolation for untrusted tool/skill execution.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Backend added in v0.3.0

type Backend string

Backend identifies a sandbox backend type.

const (
	BackendProcess   Backend = "process"
	BackendContainer Backend = "container"
	BackendWASM      Backend = "wasm"
	BackendK8sJob    Backend = "k8s"
)

func ParseBackend added in v0.3.0

func ParseBackend(s string) Backend

ParseBackend parses a backend string.

type Config added in v0.3.0

type Config struct {
	Backend Backend `json:"backend"`
	WorkDir string  `json:"work_dir,omitempty"`
	// Container-specific
	Image   string `json:"image,omitempty"`
	Network string `json:"network,omitempty"`
	// Runtime selects a hardened OCI runtime for the container backend
	// (e.g. "runsc" for gVisor, "kata-runtime"). Empty uses the daemon default.
	Runtime string `json:"runtime,omitempty"`
	// K8s-specific
	Namespace  string `json:"namespace,omitempty"`
	ServiceAcc string `json:"service_account,omitempty"`
	// WASM-specific
	WASMPath string `json:"wasm_path,omitempty"`
}

Config holds configuration for sandbox creation.

type ContainerConfig

type ContainerConfig struct {
	Image       string
	SocketPath  string
	MemoryBytes int64
	CPUQuota    int64
	NetworkMode string
	// Hardening. Zero values fall back to hardened defaults.
	User           string
	PidsLimit      int64
	NofileLimit    int64
	NprocLimit     int64
	CapAdd         []string
	SeccompProfile string
	// Runtime selects a hardened OCI runtime such as "runsc" (gVisor) or
	// "kata-runtime". Empty uses the daemon default (runc). It is never required.
	Runtime string
	// Tmpfs overrides the default writable /tmp mount. Nil uses the default.
	Tmpfs map[string]string
	// WritableRootfs disables the read-only rootfs hardening when true.
	WritableRootfs bool
}

ContainerConfig holds container sandbox configuration.

type ContainerPool added in v0.3.0

type ContainerPool struct {
	// contains filtered or unexported fields
}

ContainerPool maintains a pool of pre-warmed containers for reduced cold-start latency.

Idle containers are reclaimed lazily: any container that has sat in the pool longer than maxIdle is closed and dropped the next time the pool is touched (Acquire or Release). This avoids a background goroutine while still bounding how long stale containers linger.

func NewPool added in v0.3.0

func NewPool(cfg PoolConfig) (*ContainerPool, error)

NewPool creates a ContainerPool with the given configuration.

func (*ContainerPool) Acquire added in v0.3.0

func (p *ContainerPool) Acquire() (Sandbox, error)

Acquire returns a ready sandbox from the pool. If the pool is empty, a new sandbox is created. Returns immediately if a warm container is available.

func (*ContainerPool) Close added in v0.3.0

func (p *ContainerPool) Close() error

Close shuts down the pool and all containers.

func (*ContainerPool) InUse added in v0.3.0

func (p *ContainerPool) InUse() int

InUse returns the number of containers currently in use.

func (*ContainerPool) Release added in v0.3.0

func (p *ContainerPool) Release(sb Sandbox) error

Release returns a sandbox to the pool. If the pool is full, the sandbox is closed.

func (*ContainerPool) Size added in v0.3.0

func (p *ContainerPool) Size() int

Size returns the current number of available containers.

func (*ContainerPool) Warmup added in v0.3.0

func (p *ContainerPool) Warmup(ctx context.Context, n int) error

Warmup pre-creates n containers in the pool.

type ContainerSandbox

type ContainerSandbox struct {
	Image string

	// Resource limits
	MemoryBytes int64
	CPUQuota    int64
	NetworkMode string
	// Hardening
	User           string            // non-root user/uid:gid the workload runs as
	PidsLimit      int64             // max processes inside the container
	NofileLimit    int64             // RLIMIT_NOFILE (open files)
	NprocLimit     int64             // RLIMIT_NPROC (processes/threads)
	ReadonlyRootfs bool              // mount the container root filesystem read-only
	CapAdd         []string          // capabilities to re-add on top of CapDrop ALL
	SeccompProfile string            // custom seccomp profile JSON; empty keeps Docker's default
	Runtime        string            // OCI runtime (e.g. "runsc" for gVisor, "kata-runtime")
	Tmpfs          map[string]string // writable tmpfs mounts (path -> mount options)
	// contains filtered or unexported fields
}

ContainerSandbox implements Sandbox using Docker Engine API for production-grade isolation.

func NewContainerSandbox

func NewContainerSandbox(cfg ContainerConfig) *ContainerSandbox

NewContainerSandbox creates a Docker-based sandbox with a hardened default profile: non-root user, all capabilities dropped, no-new-privileges, the default seccomp profile, a pids limit, file/process ulimits, a read-only rootfs backed by a small tmpfs /tmp, and memory/CPU limits.

func (*ContainerSandbox) Close

func (c *ContainerSandbox) Close() error

func (*ContainerSandbox) Execute

func (c *ContainerSandbox) Execute(ctx context.Context, command string, args []string, timeout time.Duration) (*Result, error)

type K8sJobConfig added in v0.3.0

type K8sJobConfig struct {
	// Image is the container image the Job's pod runs. Required.
	Image string
	// Namespace is where Jobs are created. Empty defaults to "default".
	Namespace string
	// ServiceAccount, when set, is the pod's service account. Empty uses the
	// namespace default.
	ServiceAccount string
}

K8sJobConfig holds Kubernetes Job sandbox configuration.

type K8sJobSandbox added in v0.3.0

type K8sJobSandbox struct {
	// contains filtered or unexported fields
}

K8sJobSandbox runs untrusted commands as one-shot Kubernetes Jobs. Each Execute creates a Job whose pod runs the command in the configured image, waits for it to finish (or hit its deadline), collects the pod's logs and exit code, and deletes the Job. The pod runs with a hardened security context (non-root, all capabilities dropped, no privilege escalation, read-only root filesystem) so a compromised workload has minimal reach into the cluster.

func NewK8sJobSandbox added in v0.3.0

func NewK8sJobSandbox(cfg K8sJobConfig) (*K8sJobSandbox, error)

NewK8sJobSandbox builds a sandbox backed by the ambient Kubernetes cluster. It resolves credentials from the in-cluster service account when running inside a pod, otherwise from the local kubeconfig (KUBECONFIG or ~/.kube/config). It returns an error when no cluster configuration is reachable, so a misconfigured environment fails at construction rather than at execution time.

func (*K8sJobSandbox) Close added in v0.3.0

func (s *K8sJobSandbox) Close() error

Close releases the sandbox. The Kubernetes client holds no long-lived resources that require teardown, so this is a no-op.

func (*K8sJobSandbox) Execute added in v0.3.0

func (s *K8sJobSandbox) Execute(ctx context.Context, command string, args []string, timeout time.Duration) (*Result, error)

Execute runs command (with args) as a Kubernetes Job and returns its combined logs and exit code. The timeout bounds the run both client-side (via ctx) and server-side (via the Job's activeDeadlineSeconds). A workload that exits non-zero yields a Result with the matching ExitCode and a nil error; only orchestration failures (create, timeout, API errors) return an error.

type PoolConfig added in v0.3.0

type PoolConfig struct {
	// MaxSize is the maximum number of containers in the pool (default 5).
	MaxSize int
	// MaxIdleTime is how long an idle container is kept before being destroyed (default 5m).
	MaxIdleTime time.Duration
	// Factory creates new sandbox instances.
	Factory func() (Sandbox, error)
}

PoolConfig configures a container pool.

type ProcessSandbox

type ProcessSandbox struct {
	WorkDir string
}

ProcessSandbox runs commands in a subprocess with timeouts. For production, replace with container-based isolation (gVisor, Firecracker, etc.).

func NewProcessSandbox

func NewProcessSandbox(workDir string) *ProcessSandbox

func (*ProcessSandbox) Close

func (s *ProcessSandbox) Close() error

func (*ProcessSandbox) Execute

func (s *ProcessSandbox) Execute(ctx context.Context, command string, args []string, timeout time.Duration) (*Result, error)

type Result

type Result struct {
	Stdout   string `json:"stdout"`
	Stderr   string `json:"stderr"`
	ExitCode int    `json:"exit_code"`
}

Result captures the output of a sandboxed execution.

type Sandbox

type Sandbox interface {
	Execute(ctx context.Context, command string, args []string, timeout time.Duration) (*Result, error)
	Close() error
}

Sandbox defines the interface for executing untrusted code.

func NewFromConfig added in v0.3.0

func NewFromConfig(cfg Config) (Sandbox, error)

NewFromConfig creates a sandbox based on the configuration. This is the factory function that selects the backend by config string.

type WASMConfig added in v0.7.0

type WASMConfig struct {
	// WASMPath is the filesystem path to the .wasm module to run. Required.
	WASMPath string
	// MemoryLimitPages caps the module's linear memory in 64 KiB pages. Zero
	// applies defaultWASMMemoryPages.
	MemoryLimitPages uint32
	// FSDir, when set, is mounted read-write at the module's root ("/"). Empty
	// grants the module no filesystem access at all.
	FSDir string
}

WASMConfig holds optional configuration for a WASM sandbox.

type WASMSandbox added in v0.3.0

type WASMSandbox struct {
	// contains filtered or unexported fields
}

WASMSandbox runs untrusted WASI (WebAssembly System Interface) modules using the pure-Go wazero runtime. WebAssembly gives strong isolation for free: a module executes in a linear memory space it cannot escape, and it reaches the host only through the capabilities the sandbox explicitly grants. By default no filesystem, network, environment, or clock access is provided, so a module can compute and read/write its own stdio and nothing more.

The module is compiled once at construction (so an invalid module is rejected immediately) and instantiated fresh for each Execute call, keeping executions isolated from one another.

func NewWASMSandbox added in v0.3.0

func NewWASMSandbox(wasmPath string) (*WASMSandbox, error)

NewWASMSandbox reads and compiles the module at wasmPath with default limits. It returns an error if the file cannot be read or is not a valid WebAssembly module, so callers discover a bad module at construction rather than at execution time.

func NewWASMSandboxWithConfig added in v0.7.0

func NewWASMSandboxWithConfig(cfg WASMConfig) (*WASMSandbox, error)

NewWASMSandboxWithConfig creates a WASM sandbox from an explicit configuration.

func (*WASMSandbox) Close added in v0.3.0

func (s *WASMSandbox) Close() error

Close releases the wazero runtime and all instantiated modules.

func (*WASMSandbox) Execute added in v0.3.0

func (s *WASMSandbox) Execute(ctx context.Context, command string, args []string, timeout time.Duration) (*Result, error)

Execute instantiates the compiled module and runs it to completion. command becomes argv[0] and args the remaining arguments visible to the module via WASI. The timeout bounds the run: when it elapses the module is interrupted and its partial stdout/stderr returned. A module that exits non-zero yields a Result with the matching ExitCode and a nil error; only host-side failures (instantiation, interruption) return an error.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL