Documentation
¶
Overview ¶
Package local is the IsolationNone sandbox backend: it runs commands as child processes on the host and confines file access to a root directory with a path fence. It is the lifted, generalized form of cmd/agent's old confineToRoot.
IsolationNone means there is NO real isolation for Exec — a shell command runs on the host with the agent's own privileges; the fence only governs the ReadFile/WriteFile/ListDir paths, not what a spawned process can touch. So this backend is for TRUSTED code only (code we wrote). Running untrusted, model-authored code requires a stronger backend (container/gVisor/microVM) behind the same sandbox.Sandbox interface — see ../../docs/specs/SANDBOX.md.
Index ¶
- type Options
- type Sandbox
- func (s *Sandbox) AppendFile(ctx context.Context, path string, data []byte, mode fs.FileMode) error
- func (s *Sandbox) Capabilities() sandbox.Capabilities
- func (s *Sandbox) Close() error
- func (s *Sandbox) Exec(ctx context.Context, cmd sandbox.Command) (*sandbox.Result, error)
- func (s *Sandbox) ListDir(ctx context.Context, path string) ([]sandbox.DirEntry, error)
- func (s *Sandbox) MakeDirAll(ctx context.Context, path string, mode fs.FileMode) error
- func (s *Sandbox) NewSession(_ context.Context) (sandbox.Session, error)
- func (s *Sandbox) ReadFile(ctx context.Context, path string) ([]byte, error)
- func (s *Sandbox) ReadFileLimit(ctx context.Context, path string, max int64) ([]byte, bool, error)
- func (s *Sandbox) RealRoot() string
- func (s *Sandbox) RelInRoot(path string) (string, error)
- func (s *Sandbox) Remove(ctx context.Context, path string) error
- func (s *Sandbox) Root() string
- func (s *Sandbox) SetMountAlias(prefix string)
- func (s *Sandbox) StartProcess(ctx context.Context, cmd sandbox.Command) (sandbox.Process, error)
- func (s *Sandbox) Workdir() string
- func (s *Sandbox) WriteFile(ctx context.Context, path string, data []byte, mode fs.FileMode) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Options ¶ added in v0.2.0
type Options struct {
// EnvAllowlist limits inherited command environment variables by name. A nil
// allowlist preserves the full ambient environment.
EnvAllowlist []string
}
Options configures a local sandbox.
type Sandbox ¶
type Sandbox struct {
// contains filtered or unexported fields
}
Sandbox is a host-local sandbox confined to a single root directory.
func New ¶
New creates a local sandbox rooted at dir. dir must exist and be a directory; it is resolved to an absolute, cleaned path that becomes the fence boundary. It preserves the full ambient environment for commands.
func NewWithOptions ¶ added in v0.2.0
NewWithOptions creates a local sandbox rooted at dir with opts.
func (*Sandbox) AppendFile ¶
AppendFile implements sandbox.Appender: shell `>>` semantics inside the fence — data lands at the end of the file (created with mode if missing) without the existing contents ever entering memory.
func (*Sandbox) Capabilities ¶
func (s *Sandbox) Capabilities() sandbox.Capabilities
Capabilities reports the truth: no isolation, host network. The runner can use this to refuse running untrusted code here.
func (*Sandbox) Close ¶
Close releases resources. For plain Exec the local backend holds none; but any long-lived StartProcess children are killed here so an abandoned run can't leak host processes (the local counterpart to docker's `rm -f`). Callers should still Kill processes they own; this is the backstop.
func (*Sandbox) Exec ¶
Exec runs a command to completion. A non-zero exit (or a Timeout kill) is a normal *Result, not an error — only a genuine failure to start the command is returned as err (Principle 6: failures are observations).
func (*Sandbox) MakeDirAll ¶ added in v0.2.0
MakeDirAll creates a directory tree within the fence.
func (*Sandbox) NewSession ¶
NewSession opens a stateful session whose shell state persists in a per-session dir under the host temp dir (unique via pid + counter). The state lives OUTSIDE the workspace fence on purpose — it is our bookkeeping, not workspace content, and a local Exec subprocess writes there directly (the fence governs ReadFile/ WriteFile, not what a spawned process touches). Close removes the dir.
func (*Sandbox) ReadFileLimit ¶
ReadFileLimit implements sandbox.LimitedReader: a bounded read that never pulls more than max bytes into memory (Principle 4). It reads max+1 bytes — one past the limit — to detect whether the file continued, without copying the tail.
func (*Sandbox) RealRoot ¶
RealRoot returns the fence root with all symlinks resolved. The docker backend bind-mounts THIS (not the lexical Root) into the container, so the mounted host path is the canonical one the symlink-safe fence checks against — they can't disagree, and a symlinked root dir can't later be swapped to redirect the mount.
func (*Sandbox) RelInRoot ¶
RelInRoot fences path exactly as ReadFile/Exec do, then returns it cleaned and RELATIVE to the root ("." for the root itself). The docker backend uses this to translate a sandbox-relative working dir into an in-container path while reusing the tested fence — an escaping path is REFUSED here, not silently clamped, so the container's working dir can't be aimed outside the workspace.
func (*Sandbox) Remove ¶ added in v0.2.0
Remove removes one file or empty directory within the fence. It is never recursive.
func (*Sandbox) Root ¶
Root returns the absolute, cleaned fence root. It exists so a backend that COMPOSES this one — the docker backend embeds *local.Sandbox and must bind-mount the same resolved directory into the container (so a host write and an in-container read hit the same inode) — can read the path the fence resolved to, rather than re-resolving dir itself and risking a mismatch.
func (*Sandbox) SetMountAlias ¶
SetMountAlias declares an absolute prefix that aliases the root: the in-container bind-mount point (e.g. "/workspace") when this backend is composed under a container backend. Paths arriving with that prefix are translated to root-relative before fencing, so a model that (correctly) believes it lives at the mount point can use absolute paths without being refused (DUET-DOGFOOD F4). A trailing slash is trimmed; "" disables the alias.
func (*Sandbox) StartProcess ¶
StartProcess launches cmd as a long-lived child confined to the workspace dir (cwd fenced like Exec). Streams are wired with explicit os.Pipe and caller-owned ends so reaping the process never races an in-flight reader (the os/exec StdoutPipe/Wait hazard). The child runs in its OWN process group so Kill can take down any grandchildren it spawned. cmd.Stdin/cmd.Timeout are ignored (P: live stdin + caller-managed lifetime).
func (*Sandbox) Workdir ¶
Workdir reports the directory Exec commands start in, as the model should name it (sandbox.WorkdirReporter). Plain host use: the absolute root. When a mount alias is set this backend is composed under a container and the model lives at the mount point, so the alias IS the model-visible cwd.