Documentation
¶
Overview ¶
Package sandbox – exec_direct.go implements the direct executor (IsolationNone). Runs scripts via os/exec without any sandboxing. Use only for trusted/builtin skills.
Package sandbox – exec_docker.go implements the Docker-based executor for maximum script isolation.
This executor provides:
- Full filesystem isolation (container image)
- Network isolation (configurable)
- CPU and memory limits via Docker
- Read-only workspace mount
- Writable temp directory mount
- Automatic sandbox image building
Package sandbox – exec_restricted.go implements the restricted executor using Linux namespaces for lightweight process isolation.
This executor provides:
- PID namespace isolation (process can't see other processes)
- Network namespace isolation (optional, blocks network by default)
- Mount namespace with read-only bind mounts
- Resource limits via setrlimit
- Filtered environment variables
Requires Linux with user namespaces enabled (most modern distros). Falls back to DirectExecutor on non-Linux systems.
Package sandbox – policy.go implements the security policy for script execution: command allowlisting, environment variable filtering, and script content scanning.
Package sandbox – runner.go implements the main ScriptRunner that dispatches execution to the appropriate sandbox backend.
Package sandbox provides secure script execution for DevClaw.
It supports multiple isolation levels for running Python, Node.js, and Shell scripts from skills (including ClawdHub community skills):
- none: Direct exec.Command (trusted/builtin skills only)
- restricted: Linux namespaces + resource limits (community skills)
- container: Docker-based full isolation (untrusted scripts)
The sandbox enforces:
- Execution timeouts
- Memory and CPU limits
- Filesystem scoping (read-only workspace, writable tmpdir)
- Environment variable filtering (blocks dangerous vars)
- Command allowlisting
- Output size limits
Index ¶
- func HasCritical(results []ScanResult) bool
- type Config
- type DirectExecutor
- type DockerConfig
- type DockerExecutor
- type ExecRequest
- type ExecResult
- type Executor
- type IsolationLevel
- type Policy
- func (p *Policy) AddAllowedBin(bin string)
- func (p *Policy) FilterEnv(env map[string]string) map[string]string
- func (p *Policy) IsBinAllowed(bin string) bool
- func (p *Policy) IsEnvAllowed(name string) bool
- func (p *Policy) ScanScript(content string) []ScanResult
- func (p *Policy) ScanShellScript(content string) []ScanResult
- func (p *Policy) Validate(req *ExecRequest) error
- type RestrictedExecutor
- type Runner
- func (r *Runner) Close() error
- func (r *Runner) Run(ctx context.Context, req *ExecRequest) (*ExecResult, error)
- func (r *Runner) RunNode(ctx context.Context, script string, args []string, skillDir string) (*ExecResult, error)
- func (r *Runner) RunPython(ctx context.Context, script string, args []string, skillDir string) (*ExecResult, error)
- func (r *Runner) RunShell(ctx context.Context, script string, args []string, skillDir string) (*ExecResult, error)
- type Runtime
- type ScanResult
- type ScanRule
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func HasCritical ¶
func HasCritical(results []ScanResult) bool
HasCritical checks if any scan result is critical severity.
Types ¶
type Config ¶
type Config struct {
// DefaultIsolation is the isolation level for skills that don't
// specify one. Defaults to IsolationRestricted.
DefaultIsolation IsolationLevel `yaml:"default_isolation"`
// Timeout is the maximum execution time for a single script run.
// Defaults to 60s.
Timeout time.Duration `yaml:"timeout"`
// MaxOutputBytes limits stdout+stderr capture size.
// Defaults to 1MB.
MaxOutputBytes int64 `yaml:"max_output_bytes"`
// MaxMemoryMB limits memory usage (restricted/container modes).
// Defaults to 256MB.
MaxMemoryMB int `yaml:"max_memory_mb"`
// MaxCPUPercent limits CPU usage as percentage (0-100).
// Defaults to 50.
MaxCPUPercent int `yaml:"max_cpu_percent"`
// WorkDir is the working directory for script execution.
// Scripts get read-only access to this directory.
WorkDir string `yaml:"work_dir"`
// TempDir is the writable temporary directory for scripts.
// Each execution gets its own subdirectory.
TempDir string `yaml:"temp_dir"`
// Docker contains container-specific settings.
Docker DockerConfig `yaml:"docker"`
// AllowedEnv is a list of environment variable names that scripts
// are allowed to access. If empty, uses the default safe list.
AllowedEnv []string `yaml:"allowed_env"`
// BlockedEnv is a list of environment variable names that are
// always stripped. Takes precedence over AllowedEnv.
BlockedEnv []string `yaml:"blocked_env"`
// AllowNetwork controls whether scripts can make network requests.
// Defaults to false for restricted, true for none.
AllowNetwork *bool `yaml:"allow_network"`
// Runtimes maps Runtime to interpreter paths.
// Defaults: python→python3, node→node, shell→/bin/sh
Runtimes map[Runtime]string `yaml:"runtimes"`
}
Config holds the sandbox configuration.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns a Config with sensible defaults.
type DirectExecutor ¶
type DirectExecutor struct {
// contains filtered or unexported fields
}
DirectExecutor runs scripts directly via exec.Command.
func NewDirectExecutor ¶
func NewDirectExecutor(cfg Config, logger *slog.Logger) *DirectExecutor
NewDirectExecutor creates a new direct executor.
func (*DirectExecutor) Available ¶
func (e *DirectExecutor) Available() bool
Available always returns true — direct execution is always possible.
func (*DirectExecutor) Close ¶
func (e *DirectExecutor) Close() error
Close is a no-op for the direct executor.
func (*DirectExecutor) Execute ¶
func (e *DirectExecutor) Execute(ctx context.Context, req *ExecRequest) (*ExecResult, error)
Execute runs the script directly.
func (*DirectExecutor) Name ¶
func (e *DirectExecutor) Name() string
Name returns the executor name.
type DockerConfig ¶
type DockerConfig struct {
// Image is the Docker image to use for sandboxed execution.
// Defaults to "devclaw-sandbox:latest".
Image string `yaml:"image"`
// BuildOnStart builds the sandbox image on startup if missing.
BuildOnStart bool `yaml:"build_on_start"`
// Network is the Docker network mode.
// Defaults to "none" (no network access).
Network string `yaml:"network"`
// ExtraVolumes are additional volume mounts (host:container:mode).
ExtraVolumes []string `yaml:"extra_volumes"`
}
DockerConfig holds Docker-specific sandbox settings.
type DockerExecutor ¶
type DockerExecutor struct {
// contains filtered or unexported fields
}
DockerExecutor runs scripts inside Docker containers.
func NewDockerExecutor ¶
func NewDockerExecutor(cfg Config, logger *slog.Logger) *DockerExecutor
NewDockerExecutor creates a new Docker executor.
func (*DockerExecutor) Available ¶
func (e *DockerExecutor) Available() bool
Available checks if Docker is installed and running.
func (*DockerExecutor) BuildImage ¶
func (e *DockerExecutor) BuildImage(ctx context.Context, dockerfilePath string) error
BuildImage builds the sandbox Docker image.
func (*DockerExecutor) Close ¶
func (e *DockerExecutor) Close() error
Close is a no-op for Docker executor.
func (*DockerExecutor) Execute ¶
func (e *DockerExecutor) Execute(ctx context.Context, req *ExecRequest) (*ExecResult, error)
Execute runs the script inside a Docker container.
func (*DockerExecutor) Name ¶
func (e *DockerExecutor) Name() string
Name returns the executor name.
type ExecRequest ¶
type ExecRequest struct {
// Runtime is the script interpreter to use.
Runtime Runtime
// Isolation overrides the default isolation level.
// If empty, uses Config.DefaultIsolation.
Isolation IsolationLevel
// Script is the path to the script file to execute.
Script string
// Args are command-line arguments passed to the script.
Args []string
// Stdin provides data to the script's standard input.
Stdin string
// Env are additional environment variables for this execution.
// Subject to filtering by the security policy.
Env map[string]string
// WorkDir overrides the working directory for this execution.
WorkDir string
// Timeout overrides the default timeout for this execution.
Timeout time.Duration
// SkillDir is the skill's base directory (replaces {baseDir}).
SkillDir string
}
ExecRequest describes a script execution request.
type ExecResult ¶
type ExecResult struct {
// Stdout is the captured standard output.
Stdout string
// Stderr is the captured standard error.
Stderr string
// ExitCode is the process exit code.
ExitCode int
// Duration is how long the execution took.
Duration time.Duration
// Killed is true if the process was killed (timeout, OOM, etc.).
Killed bool
// KillReason explains why the process was killed.
KillReason string
// OutputFiles lists files created in the temp directory.
OutputFiles []string
}
ExecResult holds the outcome of a script execution.
type Executor ¶
type Executor interface {
// Execute runs a script with the given request.
Execute(ctx context.Context, req *ExecRequest) (*ExecResult, error)
// Available reports whether this executor is usable on the system.
Available() bool
// Name returns the executor name for logging.
Name() string
// Close releases resources held by the executor.
Close() error
}
Executor is the interface for sandbox implementations.
type IsolationLevel ¶
type IsolationLevel string
IsolationLevel defines how strictly a script is sandboxed.
const ( // IsolationNone runs scripts directly via exec.Command. // Use only for trusted/builtin skills. IsolationNone IsolationLevel = "none" // IsolationRestricted uses Linux namespaces, seccomp, and cgroups // for lightweight isolation without Docker. IsolationRestricted IsolationLevel = "restricted" // IsolationContainer runs scripts inside a Docker container // with a purpose-built sandbox image. IsolationContainer IsolationLevel = "container" )
type Policy ¶
type Policy struct {
// contains filtered or unexported fields
}
Policy enforces security rules on script execution requests.
func (*Policy) AddAllowedBin ¶
AddAllowedBin adds a binary to the safe execution list.
func (*Policy) FilterEnv ¶
FilterEnv filters environment variables based on the policy. Returns a new map with only allowed variables.
func (*Policy) IsBinAllowed ¶
IsBinAllowed checks if a binary is in the allowlist.
func (*Policy) IsEnvAllowed ¶
IsEnvAllowed checks if an environment variable is allowed.
func (*Policy) ScanScript ¶
func (p *Policy) ScanScript(content string) []ScanResult
ScanScript analyzes script content for dangerous patterns. Returns a list of findings. Critical findings should block execution.
func (*Policy) ScanShellScript ¶
func (p *Policy) ScanShellScript(content string) []ScanResult
ScanShellScript analyzes shell script content for dangerous patterns. Shell scripts are scanned with a separate rule set because $VAR syntax is valid in shell and should not trigger the shell-env-injection rule.
func (*Policy) Validate ¶
func (p *Policy) Validate(req *ExecRequest) error
Validate checks whether an execution request is allowed.
type RestrictedExecutor ¶
type RestrictedExecutor struct {
// contains filtered or unexported fields
}
RestrictedExecutor runs scripts with Linux namespace isolation.
func NewRestrictedExecutor ¶
func NewRestrictedExecutor(cfg Config, logger *slog.Logger) *RestrictedExecutor
NewRestrictedExecutor creates a new restricted executor.
func (*RestrictedExecutor) Available ¶
func (e *RestrictedExecutor) Available() bool
Available checks if Linux namespaces are supported.
func (*RestrictedExecutor) Execute ¶
func (e *RestrictedExecutor) Execute(ctx context.Context, req *ExecRequest) (*ExecResult, error)
Execute runs the script with namespace isolation.
func (*RestrictedExecutor) Name ¶
func (e *RestrictedExecutor) Name() string
Name returns the executor name.
type Runner ¶
type Runner struct {
// contains filtered or unexported fields
}
Runner is the main script execution manager. It selects the appropriate sandbox backend based on isolation level and dispatches execution requests.
func (*Runner) Run ¶
func (r *Runner) Run(ctx context.Context, req *ExecRequest) (*ExecResult, error)
Run executes a script with the configured sandbox.
func (*Runner) RunNode ¶
func (r *Runner) RunNode(ctx context.Context, script string, args []string, skillDir string) (*ExecResult, error)
RunNode is a convenience method for running a Node.js script.
type Runtime ¶
type Runtime string
Runtime identifies the script interpreter.
func DetectRuntime ¶
DetectRuntime guesses the runtime from a script path.
type ScanResult ¶
ScanResult reports a detected issue in script content.