Documentation
¶
Index ¶
- Constants
- Variables
- func ApplySandboxdProtection(ctx context.Context, binaryPath, capabilitySID string, paths []string) error
- func PrepareMicroVM(ctx context.Context, cfg MicroVMConfig, onOutput func(string)) error
- func RegisterRemoteExecutor(sessionID string, executor Executor)
- func RemoveMicroVMEnvironments(ctx context.Context, cfg MicroVMConfig) error
- func RemoveSandboxdProtection(ctx context.Context, binaryPath, capabilitySID string, paths []string) error
- func StopMicroVMEnvironments(ctx context.Context, cfg MicroVMConfig) error
- func UnregisterRemoteExecutor(sessionID string)
- type EnvironmentKind
- type Executor
- type ExecutorConfig
- type MicroVMConfig
- type MicroVMExecutor
- type RunRequest
- type RunResult
- type SandboxdConfig
- type SandboxdExecutor
Constants ¶
const ( // SandboxdProfileStrict refuses reads and writes outside the workdir and has no // network, but cannot run git init, npm or a Node script. SandboxdProfileStrict = "strict" // SandboxdProfileProject refuses writes outside the workdir and the reads named // in DenyRead, and leaves other reads and the network open. It runs real projects. SandboxdProfileProject = "project" )
const ( // DefaultMicroVMImage has git, python, a compiler and node. Smaller images lack them, // and an agent would spend its first turns installing them. DefaultMicroVMImage = "node:22-bookworm" )
Variables ¶
var DefaultMicroVMPorts = []string{"3000-3003:3000-3003", "4200:4200", "4321:4321", "5000:5000", "5173-5175:5173-5175", "8000:8000", "8080:8080"}
DefaultMicroVMPorts covers the usual dev servers.
Functions ¶
func ApplySandboxdProtection ¶ added in v1.13.2
func ApplySandboxdProtection(ctx context.Context, binaryPath, capabilitySID string, paths []string) error
ApplySandboxdProtection writes the deny ACEs of the project profile on paths ahead of a session. A session's handshake also writes them but is bounded, and a first protection walks every file below a path, so an embedder protects a large folder here, with a ctx as long as it can wait. Paths that do not exist are skipped, and doing it twice changes nothing.
func PrepareMicroVM ¶ added in v1.14.0
func PrepareMicroVM(ctx context.Context, cfg MicroVMConfig, onOutput func(string)) error
PrepareMicroVM checks that this host can run a sandbox and pulls the image. A pull takes minutes, so it belongs where the user turned the mode on and not inside a command's timeout. onOutput, when set, receives msb's progress.
func RegisterRemoteExecutor ¶
RegisterRemoteExecutor attaches executor as sessionID's remote execution backend. A re-registration (e.g. a reconnect) replaces any previous one.
func RemoveMicroVMEnvironments ¶ added in v1.14.0
func RemoveMicroVMEnvironments(ctx context.Context, cfg MicroVMConfig) error
RemoveMicroVMEnvironments deletes every sandbox and volume of this backend, which is how an embedder gives the disk back. The projects' folders are not touched.
func RemoveSandboxdProtection ¶ added in v1.13.0
func RemoveSandboxdProtection(ctx context.Context, binaryPath, capabilitySID string, paths []string) error
RemoveSandboxdProtection takes back the deny ACEs the project profile wrote on paths. It needs no session, so it also works after a crash. Paths that are gone or were never protected are not an error.
func StopMicroVMEnvironments ¶ added in v1.14.0
func StopMicroVMEnvironments(ctx context.Context, cfg MicroVMConfig) error
StopMicroVMEnvironments stops every sandbox of this backend. A sandbox outlives the process that started it, so an embedder calls this at startup in case the last run did not close.
func UnregisterRemoteExecutor ¶
func UnregisterRemoteExecutor(sessionID string)
UnregisterRemoteExecutor detaches sessionID's remote execution backend — subsequent bash calls for that session fall back to local execution.
Types ¶
type EnvironmentKind ¶
type EnvironmentKind string
EnvironmentKind describes where a tool executes. The policy layer should know this, even if the actual backend runtime (local process, sidecar, microVM, remote host) is implemented elsewhere.
const ( EnvironmentLocal EnvironmentKind = "local" EnvironmentRemote EnvironmentKind = "remote" // EnvironmentSandboxed runs commands through the seshat-sandboxd sidecar, // the Rust half of the runtime. Unlike EnvironmentLocal it has an OS-level // boundary, with no daemon: the sidecar is // a process the runtime starts and stops with the session. EnvironmentSandboxed EnvironmentKind = "sandboxd" // EnvironmentMicroVM runs commands in a Linux microVM per project, through the msb // command line. See docs/adr/0003-microvm-environment.md. EnvironmentMicroVM EnvironmentKind = "microvm" )
type Executor ¶
type Executor interface {
// Run executes a command inside the sandbox and streams its output.
// Implementations must respect ctx cancellation and RunRequest.Timeout.
Run(ctx context.Context, req RunRequest) (RunResult, error)
// Kind identifies which backend this is.
Kind() EnvironmentKind
// Healthy returns nil when the executor is ready to accept work.
// A non-nil error means the backend is unavailable. The engine calls this once at startup.
Healthy(ctx context.Context) error
}
Executor is the interface all sandbox backends implement. The engine routes bash/shell execution through the active Executor.
Backends:
- SandboxdExecutor — runs commands through the seshat-sandboxd sidecar (rust/sandboxd), which owns OS-level confinement and resource limits
- MicroVMExecutor — runs commands in a Linux microVM per project, through msb
With none of them, the bash tool runs commands itself, under Landlock where the host has it. Selection at startup via ExecutorConfig.Kind. Tools that are read-only (file read, glob, grep) bypass the Executor and go directly to the host FS.
func NewExecutor ¶
func NewExecutor(cfg ExecutorConfig) (Executor, error)
NewExecutor creates the Executor selected by cfg.Kind. Returns an error when the requested backend is unavailable.
func NewUnavailableExecutor ¶ added in v1.12.5
func NewUnavailableExecutor(kind EnvironmentKind, err error) Executor
NewUnavailableExecutor returns an Executor that fails every call with err.
func RemoteExecutorFor ¶
RemoteExecutorFor looks up sessionID's registered remote executor, if any.
type ExecutorConfig ¶
type ExecutorConfig struct {
// Kind selects the backend.
Kind EnvironmentKind
// Sandboxd holds sidecar configuration.
// Only used when Kind == EnvironmentSandboxed.
Sandboxd SandboxdConfig
// MicroVM configures the microVM backend when Kind is EnvironmentMicroVM.
MicroVM MicroVMConfig
}
ExecutorConfig is the configuration passed to NewExecutor at startup.
type MicroVMConfig ¶ added in v1.14.0
type MicroVMConfig struct {
// BinaryPath is the msb executable. Required. The embedder provides it.
BinaryPath string
// Home holds msb's images, sandboxes and volumes, and this backend's records.
// Required: a default under the user's profile would mix with a separate install.
Home string
// Image is the OCI image of the environment. Empty means DefaultMicroVMImage.
Image string
// CPUs and MemoryMB size each sandbox. Zero means the defaults below.
CPUs int
MemoryMB int
// Ports are msb port mappings published when a sandbox is created. Nil means
// DefaultMicroVMPorts: a command does not announce its port, so they are set ahead.
Ports []string
// Shell runs a command in the guest. Empty means bash, which the default image has.
Shell []string
// Env is added to every command. The host's environment is never passed in.
Env map[string]string
}
MicroVMConfig configures the microVM backend. See docs/adr/0003-microvm-environment.md.
type MicroVMExecutor ¶ added in v1.14.0
type MicroVMExecutor struct {
// contains filtered or unexported fields
}
MicroVMExecutor runs commands in a microVM per project through the msb command line.
func NewMicroVMExecutor ¶ added in v1.14.0
func NewMicroVMExecutor(cfg MicroVMConfig) (*MicroVMExecutor, error)
NewMicroVMExecutor checks the configuration. It starts nothing.
func (*MicroVMExecutor) BackgroundExecutor ¶ added in v1.14.0
func (e *MicroVMExecutor) BackgroundExecutor() Executor
BackgroundExecutor returns an executor for one background task. It shares this executor's sandboxes and leaves them running when the task ends. A task needs no sandbox of its own: unlike the sidecar, a sandbox runs commands side by side.
func (*MicroVMExecutor) Close ¶ added in v1.14.0
func (e *MicroVMExecutor) Close() error
Close stops the sandboxes no other executor is using. A stopped sandbox keeps its disk, so the next session starts in a second.
func (*MicroVMExecutor) Healthy ¶ added in v1.14.0
func (e *MicroVMExecutor) Healthy(ctx context.Context) error
Healthy implements Executor: msb reports whether this host can run a sandbox.
func (*MicroVMExecutor) Kind ¶ added in v1.14.0
func (e *MicroVMExecutor) Kind() EnvironmentKind
Kind implements Executor.
func (*MicroVMExecutor) Run ¶ added in v1.14.0
func (e *MicroVMExecutor) Run(ctx context.Context, req RunRequest) (RunResult, error)
Run implements Executor.
type RunRequest ¶
type RunRequest struct {
// Command is the shell command string to execute.
// Passed as-is to the interpreter defined by Shell.
Command string
// Shell specifies the interpreter. Empty means the backend's default.
Shell []string
// Env is a set of KEY=VALUE pairs injected into the command environment
// on top of the executor's base environment.
Env map[string]string
// WorkDir is the host working directory for the command. A microVM maps it into
// the guest, and mounts it if it is a new project.
WorkDir string
// Stdin is connected to the command's standard input (may be nil).
Stdin io.Reader
// Timeout is the maximum duration for the command.
// Zero means no timeout beyond the parent context deadline.
Timeout time.Duration
// OnOutput, when set, receives output as the command produces it, with the
// stream ("stdout" or "stderr"). The RunResult still holds all of it. A remote
// executor may hand output over only when the command ends.
OnOutput func(stream string, data []byte)
}
RunRequest is the input to Executor.Run.
type RunResult ¶
type RunResult struct {
// Stdout and Stderr capture the command output.
// Empty when Background=true.
Stdout string
Stderr string
// ExitCode is the process exit code. Non-zero indicates failure.
ExitCode int
// Duration is the wall-clock time the command took.
Duration time.Duration
// Cwd is the working directory the command left the environment in.
// Only populated by executors backed by a persistent shell (e.g.
// RemoteExecutor) where a `cd` genuinely changes state for the next
// command; empty for one-shot-per-call executors, where WorkDir never changes
// out from under the caller.
Cwd string
}
RunResult is the output of Executor.Run.
type SandboxdConfig ¶ added in v1.12.5
type SandboxdConfig struct {
// BinaryPath is the seshat-sandboxd executable. Required.
BinaryPath string
// Shell is the interpreter used when a RunRequest does not name one,
// e.g. []string{"/bin/bash", "-c"}. Empty lets the sidecar pick the
// platform default (/bin/sh on Unix, cmd.exe /C on Windows).
Shell []string
// MaxOutputBytes caps each stream *inside* the sidecar, protecting this
// process from a runaway command. Zero means no cap: the tools' own
// output handling applies, exactly as on the unsandboxed path.
MaxOutputBytes int64
// DefaultTimeout applies when RunRequest.Timeout is zero. Zero means no
// deadline beyond the caller's context.
DefaultTimeout time.Duration
// HandshakeTimeout bounds startup plus the hello exchange.
HandshakeTimeout time.Duration
// Profile names the identity on Windows: SandboxdProfileProject or
// SandboxdProfileStrict. Empty means strict. See ADR-0002.
Profile string
// CapabilitySID is the SID the project profile's token carries and its deny
// ACEs name, random and made once per install. The embedder keeps it: taking an
// ACE back later needs the same one. Required by the project profile.
CapabilitySID string
// DenyRead names what the project profile refuses to read. A path that exists
// and cannot be protected refuses the whole session. The model never sets this,
// nor the profile: a command cannot widen its own sandbox.
DenyRead []string
}
SandboxdConfig configures the seshat-sandboxd backend: the Rust sidecar that owns confinement and execution.
The binary is a separate process on purpose. The alternative — a cgo library — would make `go build` depend on a C toolchain on every platform and would let a fault in the sandbox take the runtime down with it. A process boundary costs one extra binary in the release and buys a boundary that survives a crash.
func DefaultSandboxdConfig ¶ added in v1.12.5
func DefaultSandboxdConfig() SandboxdConfig
DefaultSandboxdConfig returns the configuration used when an embedder enables the backend without tuning anything.
type SandboxdExecutor ¶ added in v1.12.5
type SandboxdExecutor struct {
// contains filtered or unexported fields
}
SandboxdExecutor runs commands through the seshat-sandboxd sidecar.
One sidecar per executor, one run at a time: the protocol is a single conversation, and a sandbox that interleaves commands makes a violation report ambiguous about which command caused it.
func NewSandboxdExecutor ¶ added in v1.12.5
func NewSandboxdExecutor(cfg SandboxdConfig) (*SandboxdExecutor, error)
NewSandboxdExecutor returns an executor that starts its sidecar lazily, on the first Healthy or Run call.
func (*SandboxdExecutor) Close ¶ added in v1.12.5
func (e *SandboxdExecutor) Close() error
Close stops the sidecar. It is idempotent.
func (*SandboxdExecutor) Healthy ¶ added in v1.12.5
func (e *SandboxdExecutor) Healthy(ctx context.Context) error
Healthy starts the sidecar if needed and confirms the handshake.
It fails when the binary is missing, when the protocol major version differs, or when the sidecar reports that it confines nothing. In each case running is refused; there is no fall back to an unconfined path, because a sandbox that silently degrades is the failure mode this backend exists to remove.
func (*SandboxdExecutor) Kind ¶ added in v1.12.5
func (e *SandboxdExecutor) Kind() EnvironmentKind
func (*SandboxdExecutor) Run ¶ added in v1.12.5
func (e *SandboxdExecutor) Run(ctx context.Context, req RunRequest) (RunResult, error)
Run executes req through the sidecar.
func (*SandboxdExecutor) Status ¶ added in v1.12.5
func (e *SandboxdExecutor) Status() *sandboxdHelloAck
Status reports what the sidecar said it can enforce, or nil before a successful handshake.