Documentation
¶
Overview ¶
Package gated wraps any sandbox.Sandbox with a confirmation gate on command execution — the trust layer that makes the agent usable on a REAL repo rather than only a throwaway eval fixture. It is a decorator, not a change to the loop: every effect the agent causes already flows through the sandbox.Sandbox interface (sandbox/sandbox.go), so gating `run` is just wrapping Exec. The loop and the tools never learn the gate exists.
Scope is deliberately Exec only. File writes route through WriteFile, which is already path-confined to the sandbox root AND reviewed as a diff before any commit (the cmd/agent -review flow), so gating them in-loop would add prompts without adding safety. Arbitrary shell — which on the local backend runs on the host (IsolationNone) — is the real escape surface, so that is what the gate guards.
A blocked command is NOT an error: it returns a non-zero Result the model sees as an observation and can adapt to (Principle 6 — tool failures are observations, not crashes), exactly like a command that exited non-zero on its own. The agent simply learns "that wasn't allowed" and tries another way.
Index ¶
- func Chained(line string) bool
- func Display(cmd sandbox.Command) string
- type Approver
- type ApproverFunc
- type Policy
- type Request
- 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) 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) Remove(ctx context.Context, path string) error
- func (s *Sandbox) Root() string
- func (s *Sandbox) Workdir() string
- func (s *Sandbox) WriteFile(ctx context.Context, path string, data []byte, mode fs.FileMode) error
- type Verdict
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Chained ¶
Chained reports whether a command line can run more than the one command its prefix suggests — the exported form of the guard DefaultPolicy applies, for callers building their OWN prefix allowlists (the driver's session "always allow" list): a chained line must never ride in on a trusted prefix.
Types ¶
type Approver ¶
Approver decides an Ask verdict. Approve returns true to run the command. An error (e.g. no interactive terminal to prompt on) is treated by the gate as a denial — failing closed, never open.
type ApproverFunc ¶
ApproverFunc adapts a plain func to an Approver.
type Policy ¶
Policy classifies a command into a Verdict. It is pure (no I/O): the human interaction lives in the Approver, so a Policy stays trivially testable and swappable (tighten it to AskAll, or loosen it per project).
type Request ¶
Request is what an Approver is asked to approve: the raw command plus a human-readable rendering of it (Display) so the prompt doesn't have to know the sh -c wrapping the run tool uses.
type Sandbox ¶
type Sandbox struct {
// contains filtered or unexported fields
}
Sandbox decorates an inner sandbox.Sandbox, gating Exec through a Policy and (on Ask) an Approver. Every other method passes straight through — the gate adds nothing to reads, writes, listing, capabilities, or teardown.
func New ¶
New wraps inner with a confirmation gate. A nil policy defaults to DefaultPolicy; a nil approver makes every Ask a denial (a fully un-attended gate that blocks anything not explicitly Allowed — fail closed).
func (*Sandbox) AppendFile ¶
AppendFile forwards the optional sandbox.Appender capability. An inner without it gets errors.ErrUnsupported so the CALLER (agent.writeFileOp) keeps one policy point for the degraded read+concat path — the gate never silently slurps a whole file itself.
func (*Sandbox) Capabilities ¶
func (s *Sandbox) Capabilities() sandbox.Capabilities
Capabilities, ReadFile, WriteFile, Remove, ListDir, Close all pass through unchanged.
func (*Sandbox) Exec ¶
Exec gates the command. Allow runs it; Deny blocks it; Ask consults the Approver. A blocked command returns a synthetic non-zero Result (never a Go error), so the agent observes the denial and continues (P6).
func (*Sandbox) MakeDirAll ¶ added in v0.2.0
func (*Sandbox) ReadFileLimit ¶
ReadFileLimit forwards the optional sandbox.LimitedReader capability when the inner sandbox has it (local and docker do). If it doesn't, degrade the same way agent.readBounded's own fallback does: full read, then cap what is KEPT — the read itself is unbounded, but the caller never holds more than max.
func (*Sandbox) Root ¶
Root forwards the inner sandbox's workspace root when it exposes one (the local backend does), so host-side Go introspection (agent.hostWorkspace → go doc / go list) resolves module versions against the project even under the gate. "" means "no root known" and callers fall back to the process cwd.
type Verdict ¶
type Verdict int
Verdict is a Policy's classification of a command before it runs. The zero value is Ask on purpose: a policy that doesn't recognize a command falls through to a human, so an unanticipated command is never silently allowed.
func AskAll ¶
AskAll is the strictest policy: every command is Ask. Use it when even reads should be confirmed (an untrusted task, a shared machine).
func DefaultPolicy ¶
DefaultPolicy auto-allows the read/build/test allowlist and asks for everything else. It never returns Deny — a human can approve anything; the policy only decides what is quiet enough to skip the prompt. An unrecognized command falls through to Ask (the zero Verdict), which is the fail-safe.
A line with shell chaining or redirection (`&&`, `;`, `|`, `>`, `$(`, …) is ALWAYS Ask even if it starts with a safe prefix: "go test ./... && rm -rf ~" must not ride in on "go test". The allowlist only trusts a single, simple command — anything that can hide a second one is shown to the human.