add generic sandbox interface

This commit is contained in:
Ollie Agent 2026-08-18 13:22:52 +02:00
parent 7ce880021a
commit 7acaebdaaa
4 changed files with 15 additions and 6 deletions

View File

@ -90,6 +90,10 @@ Tool execution uses the configured native Landlock sandbox. Operations requiring
Persistent memory is provided by [OptMem](https://github.com/VictorTaelin/OptMem) through `memory_recall` and `memory_remember`; Ollie does not maintain a second memory-file format. History management renders context, tracks usage and cost, caps oversized tool output, and compacts older material when necessary. Persistent memory is provided by [OptMem](https://github.com/VictorTaelin/OptMem) through `memory_recall` and `memory_remember`; Ollie does not maintain a second memory-file format. History management renders context, tracks usage and cost, caps oversized tool output, and compacts older material when necessary.
### Future work: portable toolsrv hosts
`toolsrv` should be extensible to other host operating systems so Ollie tools remain useful on as many systems as possible. This includes the host-specific execution, filesystem, process, networking, and sandbox integrations required on BSD systems, macOS, and other Unix-like platforms. `olliesrv` may remain Linux-specific; its role is the agent runtime and orchestration service, while `toolsrv` is the platform-dependent execution boundary. WSL2 should work through its Linux kernel and use the existing Linux implementation.
## Frontends ## Frontends
Shell scripts, Acme, KDE components, and other clients create sessions, write prompts, and read files such as `chat`, `statewait`, `context`, and `feed`. They do not embed provider, tool, or agent-loop logic. Shell scripts, Acme, KDE components, and other clients create sessions, write prompts, and read files such as `chat`, `statewait`, `context`, and `feed`. They do not embed provider, tool, or agent-loop logic.

View File

@ -125,7 +125,7 @@ func executeSandboxed(ctx context.Context, toolPath, stdinData, cwd string, envE
} }
}() }()
var sandboxCfg *sandbox.Config var sandboxCfg sandbox.Sandbox
if !yolo { if !yolo {
cfgPath := filepath.Join(util.CfgDir(), "sandbox.yaml") cfgPath := filepath.Join(util.CfgDir(), "sandbox.yaml")
f, err := os.Open(cfgPath) f, err := os.Open(cfgPath)
@ -133,11 +133,11 @@ func executeSandboxed(ctx context.Context, toolPath, stdinData, cwd string, envE
return "", fmt.Errorf("sandbox config not found: %w", err) return "", fmt.Errorf("sandbox config not found: %w", err)
} }
defer f.Close() defer f.Close()
var loadErr error cfg, loadErr := sandbox.LoadSandbox(f)
sandboxCfg, loadErr = sandbox.LoadSandbox(f)
if loadErr != nil { if loadErr != nil {
return "", loadErr return "", loadErr
} }
sandboxCfg = cfg
} }
if timeout > 0 { if timeout > 0 {
@ -176,7 +176,7 @@ func executeSandboxed(ctx context.Context, toolPath, stdinData, cwd string, envE
if yolo { if yolo {
cmd = osExec.CommandContext(ctx, interpreter[0], interpreter[1:]...) cmd = osExec.CommandContext(ctx, interpreter[0], interpreter[1:]...)
} else { } else {
wrapped, wrapErr := sandbox.NativeCommand(sandboxCfg, interpreter, cwd, envMap) wrapped, wrapErr := sandboxCfg.Command(interpreter, cwd, envMap)
if wrapErr != nil { if wrapErr != nil {
return "", wrapErr return "", wrapErr
} }

View File

@ -13,6 +13,11 @@ import (
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
// Sandbox prepares a command for restricted execution.
type Sandbox interface {
Command(originalCmd []string, cwd string, env map[string]string) ([]string, error)
}
// Config represents the sandbox configuration // Config represents the sandbox configuration
type Config struct { type Config struct {
General GeneralConfig `yaml:"general"` General GeneralConfig `yaml:"general"`

View File

@ -6,8 +6,8 @@ import (
"os" "os"
) )
// NativeCommand encodes a native sandbox helper invocation. // Command encodes a native sandbox helper invocation.
func NativeCommand(cfg *Config, originalCmd []string, cwd string, env map[string]string) ([]string, error) { func (cfg *Config) Command(originalCmd []string, cwd string, env map[string]string) ([]string, error) {
envCopy := make(map[string]string, len(env)) envCopy := make(map[string]string, len(env))
for k, v := range env { for k, v := range env {
envCopy[k] = v envCopy[k] = v