refactor: Consolidate sandbox context functions, update default image, and enhance container configuration with environment variable support.
This commit is contained in:
parent
8762367ed3
commit
0186122a87
11 changed files with 65 additions and 84 deletions
3
Makefile
3
Makefile
|
|
@ -96,6 +96,9 @@ build-all: generate
|
||||||
GOOS=windows GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-windows-amd64.exe ./$(CMD_DIR)
|
GOOS=windows GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-windows-amd64.exe ./$(CMD_DIR)
|
||||||
@echo "All builds complete"
|
@echo "All builds complete"
|
||||||
|
|
||||||
|
build-docker-images:
|
||||||
|
docker build -t picoclaw-sandbox:bookworm-slim .
|
||||||
|
|
||||||
## install: Install picoclaw to system and copy builtin skills
|
## install: Install picoclaw to system and copy builtin skills
|
||||||
install: build
|
install: build
|
||||||
@echo "Installing $(BINARY_NAME)..."
|
@echo "Installing $(BINARY_NAME)..."
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ const defaultSandboxRegistryFile = "containers.json"
|
||||||
// NewContainerSandbox creates a container sandbox with normalized defaults and precomputed config hash.
|
// NewContainerSandbox creates a container sandbox with normalized defaults and precomputed config hash.
|
||||||
func NewContainerSandbox(cfg ContainerSandboxConfig) *ContainerSandbox {
|
func NewContainerSandbox(cfg ContainerSandboxConfig) *ContainerSandbox {
|
||||||
if strings.TrimSpace(cfg.Image) == "" {
|
if strings.TrimSpace(cfg.Image) == "" {
|
||||||
cfg.Image = "debian:bookworm-slim"
|
cfg.Image = "picoclaw-sandbox:bookworm-slim"
|
||||||
}
|
}
|
||||||
if strings.TrimSpace(cfg.ContainerPrefix) == "" {
|
if strings.TrimSpace(cfg.ContainerPrefix) == "" {
|
||||||
cfg.ContainerPrefix = "picoclaw-sandbox-"
|
cfg.ContainerPrefix = "picoclaw-sandbox-"
|
||||||
|
|
@ -204,7 +204,7 @@ func (c *ContainerSandbox) ExecStream(
|
||||||
execCtx := ctx
|
execCtx := ctx
|
||||||
cancel := func() {}
|
cancel := func() {}
|
||||||
if req.TimeoutMs > 0 {
|
if req.TimeoutMs > 0 {
|
||||||
execCtx, cancel = context.WithTimeout(ctx, durationMs(req.TimeoutMs))
|
execCtx, cancel = context.WithTimeout(ctx, time.Duration(req.TimeoutMs)*time.Millisecond)
|
||||||
} else if _, hasDeadline := ctx.Deadline(); !hasDeadline {
|
} else if _, hasDeadline := ctx.Deadline(); !hasDeadline {
|
||||||
execCtx, cancel = context.WithTimeout(ctx, 30*time.Second)
|
execCtx, cancel = context.WithTimeout(ctx, 30*time.Second)
|
||||||
}
|
}
|
||||||
|
|
@ -334,6 +334,7 @@ func (c *ContainerSandbox) createAndStart(ctx context.Context) error {
|
||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: c.cfg.Image,
|
Image: c.cfg.Image,
|
||||||
Cmd: []string{"sleep", "infinity"},
|
Cmd: []string{"sleep", "infinity"},
|
||||||
|
Entrypoint: []string{},
|
||||||
WorkingDir: c.cfg.Workdir,
|
WorkingDir: c.cfg.Workdir,
|
||||||
User: strings.TrimSpace(c.cfg.User),
|
User: strings.TrimSpace(c.cfg.User),
|
||||||
Env: c.containerEnv(),
|
Env: c.containerEnv(),
|
||||||
|
|
@ -396,7 +397,7 @@ func (c *ContainerSandbox) registryPath() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ContainerSandbox) sandboxStateDir() string {
|
func (c *ContainerSandbox) sandboxStateDir() string {
|
||||||
return filepath.Join(resolvePicoClawHomeDir(), "sandbox")
|
return filepath.Join(resolvePicoClawHomeDir(), "sandboxes")
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolvePicoClawHomeDir() string {
|
func resolvePicoClawHomeDir() string {
|
||||||
|
|
@ -890,6 +891,8 @@ func computeContainerConfigHash(cfg ContainerSandboxConfig) string {
|
||||||
DNS []string `json:"dns"`
|
DNS []string `json:"dns"`
|
||||||
ExtraHosts []string `json:"extra_hosts"`
|
ExtraHosts []string `json:"extra_hosts"`
|
||||||
Binds []string `json:"binds"`
|
Binds []string `json:"binds"`
|
||||||
|
Cmd []string `json:"cmd"`
|
||||||
|
Entrypoint []string `json:"entrypoint"`
|
||||||
}{
|
}{
|
||||||
Image: strings.TrimSpace(cfg.Image),
|
Image: strings.TrimSpace(cfg.Image),
|
||||||
ContainerPrefix: strings.TrimSpace(cfg.ContainerPrefix),
|
ContainerPrefix: strings.TrimSpace(cfg.ContainerPrefix),
|
||||||
|
|
@ -915,6 +918,8 @@ func computeContainerConfigHash(cfg ContainerSandboxConfig) string {
|
||||||
DNS: cfg.DNS,
|
DNS: cfg.DNS,
|
||||||
ExtraHosts: cfg.ExtraHosts,
|
ExtraHosts: cfg.ExtraHosts,
|
||||||
Binds: cfg.Binds,
|
Binds: cfg.Binds,
|
||||||
|
Cmd: []string{"sleep", "infinity"},
|
||||||
|
Entrypoint: []string{},
|
||||||
}
|
}
|
||||||
raw, _ := json.Marshal(payload)
|
raw, _ := json.Marshal(payload)
|
||||||
return computeConfigHash(string(raw))
|
return computeConfigHash(string(raw))
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ func TestContainerSandbox_RegistryPath_UsesSandboxStateDir(t *testing.T) {
|
||||||
Workspace: "/tmp/ws",
|
Workspace: "/tmp/ws",
|
||||||
WorkspaceRoot: "/tmp/sbx",
|
WorkspaceRoot: "/tmp/sbx",
|
||||||
})
|
})
|
||||||
want := filepath.Join(home, ".picoclaw", "sandbox", "containers.json")
|
want := filepath.Join(home, ".picoclaw", "sandboxes", "containers.json")
|
||||||
if got := sb.registryPath(); got != want {
|
if got := sb.registryPath(); got != want {
|
||||||
t.Fatalf("registryPath = %q, want %q", got, want)
|
t.Fatalf("registryPath = %q, want %q", got, want)
|
||||||
}
|
}
|
||||||
|
|
@ -280,7 +280,7 @@ func TestContainerSandbox_RegistryPath_UsesPicoClawHomeOverride(t *testing.T) {
|
||||||
picoHome := t.TempDir()
|
picoHome := t.TempDir()
|
||||||
t.Setenv("PICOCLAW_HOME", picoHome)
|
t.Setenv("PICOCLAW_HOME", picoHome)
|
||||||
sb := NewContainerSandbox(ContainerSandboxConfig{})
|
sb := NewContainerSandbox(ContainerSandboxConfig{})
|
||||||
want := filepath.Join(picoHome, "sandbox", "containers.json")
|
want := filepath.Join(picoHome, "sandboxes", "containers.json")
|
||||||
if got := sb.registryPath(); got != want {
|
if got := sb.registryPath(); got != want {
|
||||||
t.Fatalf("registryPath = %q, want %q", got, want)
|
t.Fatalf("registryPath = %q, want %q", got, want)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HostSandbox struct {
|
type HostSandbox struct {
|
||||||
|
|
@ -75,7 +76,7 @@ func (h *HostSandbox) ExecStream(
|
||||||
cmdCtx := ctx
|
cmdCtx := ctx
|
||||||
cancel := func() {}
|
cancel := func() {}
|
||||||
if req.TimeoutMs > 0 {
|
if req.TimeoutMs > 0 {
|
||||||
cmdCtx, cancel = context.WithTimeout(ctx, durationMs(req.TimeoutMs))
|
cmdCtx, cancel = context.WithTimeout(ctx, time.Duration(req.TimeoutMs)*time.Millisecond)
|
||||||
}
|
}
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
|
@ -165,8 +166,8 @@ func (h *HostSandbox) ExecStream(
|
||||||
|
|
||||||
exitCode := 0
|
exitCode := 0
|
||||||
if waitErr != nil {
|
if waitErr != nil {
|
||||||
var ee *exec.ExitError
|
ee, ok := waitErr.(*exec.ExitError)
|
||||||
if ok := asExitError(waitErr, &ee); ok {
|
if ok {
|
||||||
exitCode = ee.ExitCode()
|
exitCode = ee.ExitCode()
|
||||||
} else {
|
} else {
|
||||||
return nil, waitErr
|
return nil, waitErr
|
||||||
|
|
|
||||||
|
|
@ -121,13 +121,6 @@ func TestUnavailableSandboxAndUtilHelpers(t *testing.T) {
|
||||||
if err := sb.Fs().WriteFile(context.Background(), "a.txt", []byte("x"), true); err == nil {
|
if err := sb.Fs().WriteFile(context.Background(), "a.txt", []byte("x"), true); err == nil {
|
||||||
t.Fatal("expected Fs().WriteFile error")
|
t.Fatal("expected Fs().WriteFile error")
|
||||||
}
|
}
|
||||||
|
|
||||||
if got := durationMs(123).Milliseconds(); got != 123 {
|
|
||||||
t.Fatalf("durationMs() got %d, want 123", got)
|
|
||||||
}
|
|
||||||
if asExitError(errors.New("x"), nil) {
|
|
||||||
t.Fatal("asExitError should be false for non-exit errors")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHostFS_ReadFileWriteFile_Restricted(t *testing.T) {
|
func TestHostFS_ReadFileWriteFile_Restricted(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ func NewFromConfigWithAgent(workspace string, restrict bool, cfg *config.Config,
|
||||||
scope := "agent"
|
scope := "agent"
|
||||||
workspaceAccess := "none"
|
workspaceAccess := "none"
|
||||||
workspaceRoot := "~/.picoclaw/sandboxes"
|
workspaceRoot := "~/.picoclaw/sandboxes"
|
||||||
image := "debian:bookworm-slim"
|
image := "picoclaw-sandbox:bookworm-slim"
|
||||||
containerPrefix := "picoclaw-sandbox-"
|
containerPrefix := "picoclaw-sandbox-"
|
||||||
pruneIdleHours := 24
|
pruneIdleHours := 24
|
||||||
pruneMaxAgeDays := 7
|
pruneMaxAgeDays := 7
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
package sandbox
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type sessionContextKey struct{}
|
|
||||||
|
|
||||||
// WithSessionKey returns a derived context carrying the current routing session key.
|
|
||||||
func WithSessionKey(ctx context.Context, sessionKey string) context.Context {
|
|
||||||
return context.WithValue(ctx, sessionContextKey{}, sessionKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SessionKeyFromContext returns the session key attached by WithSessionKey.
|
|
||||||
func SessionKeyFromContext(ctx context.Context) string {
|
|
||||||
if ctx == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
v, _ := ctx.Value(sessionContextKey{}).(string)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
type sandboxContextKey struct{}
|
|
||||||
|
|
||||||
// WithSandbox returns a derived context carrying the current sandbox instance.
|
|
||||||
func WithSandbox(ctx context.Context, sb Sandbox) context.Context {
|
|
||||||
return context.WithValue(ctx, sandboxContextKey{}, sb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SandboxFromContext returns the sandbox instance attached by WithSandbox.
|
|
||||||
func SandboxFromContext(ctx context.Context) Sandbox {
|
|
||||||
if ctx == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
v, _ := ctx.Value(sandboxContextKey{}).(Sandbox)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
@ -74,6 +74,38 @@ type ExecEvent struct {
|
||||||
ExitCode int
|
ExitCode int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sessionContextKey struct{}
|
||||||
|
|
||||||
|
// WithSessionKey returns a derived context carrying the current routing session key.
|
||||||
|
func WithSessionKey(ctx context.Context, sessionKey string) context.Context {
|
||||||
|
return context.WithValue(ctx, sessionContextKey{}, sessionKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionKeyFromContext returns the session key attached by WithSessionKey.
|
||||||
|
func SessionKeyFromContext(ctx context.Context) string {
|
||||||
|
if ctx == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
v, _ := ctx.Value(sessionContextKey{}).(string)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
type sandboxContextKey struct{}
|
||||||
|
|
||||||
|
// WithSandbox returns a derived context carrying the current sandbox instance.
|
||||||
|
func WithSandbox(ctx context.Context, sb Sandbox) context.Context {
|
||||||
|
return context.WithValue(ctx, sandboxContextKey{}, sb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SandboxFromContext returns the sandbox instance attached by WithSandbox.
|
||||||
|
func SandboxFromContext(ctx context.Context) Sandbox {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v, _ := ctx.Value(sandboxContextKey{}).(Sandbox)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// FsBridge abstracts sandbox-scoped file I/O.
|
// FsBridge abstracts sandbox-scoped file I/O.
|
||||||
type FsBridge interface {
|
type FsBridge interface {
|
||||||
// ReadFile reads a file from sandbox-visible filesystem.
|
// ReadFile reads a file from sandbox-visible filesystem.
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package sandbox
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os/exec"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func durationMs(ms int64) time.Duration {
|
|
||||||
return time.Duration(ms) * time.Millisecond
|
|
||||||
}
|
|
||||||
|
|
||||||
func asExitError(err error, target **exec.ExitError) bool {
|
|
||||||
ee, ok := err.(*exec.ExitError)
|
|
||||||
if ok {
|
|
||||||
*target = ee
|
|
||||||
}
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
@ -177,7 +177,7 @@ type AgentDefaults struct {
|
||||||
MaxTokens int `json:"max_tokens" env:"PICOCLAW_AGENTS_DEFAULTS_MAX_TOKENS"`
|
MaxTokens int `json:"max_tokens" env:"PICOCLAW_AGENTS_DEFAULTS_MAX_TOKENS"`
|
||||||
Temperature *float64 `json:"temperature,omitempty" env:"PICOCLAW_AGENTS_DEFAULTS_TEMPERATURE"`
|
Temperature *float64 `json:"temperature,omitempty" env:"PICOCLAW_AGENTS_DEFAULTS_TEMPERATURE"`
|
||||||
MaxToolIterations int `json:"max_tool_iterations" env:"PICOCLAW_AGENTS_DEFAULTS_MAX_TOOL_ITERATIONS"`
|
MaxToolIterations int `json:"max_tool_iterations" env:"PICOCLAW_AGENTS_DEFAULTS_MAX_TOOL_ITERATIONS"`
|
||||||
Sandbox AgentSandboxConfig `json:"sandbox"`
|
Sandbox AgentSandboxConfig `json:"sandbox" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelsConfig struct {
|
type ChannelsConfig struct {
|
||||||
|
|
@ -508,22 +508,22 @@ type AgentSandboxDockerConfig struct {
|
||||||
ContainerPrefix string `json:"container_prefix" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_CONTAINER_PREFIX"`
|
ContainerPrefix string `json:"container_prefix" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_CONTAINER_PREFIX"`
|
||||||
Workdir string `json:"workdir" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_WORKDIR"`
|
Workdir string `json:"workdir" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_WORKDIR"`
|
||||||
ReadOnlyRoot bool `json:"read_only_root" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_READ_ONLY_ROOT"`
|
ReadOnlyRoot bool `json:"read_only_root" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_READ_ONLY_ROOT"`
|
||||||
Tmpfs []string `json:"tmpfs"`
|
Tmpfs []string `json:"tmpfs" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_TMPFS"`
|
||||||
Network string `json:"network" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_NETWORK"`
|
Network string `json:"network" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_NETWORK"`
|
||||||
User string `json:"user" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_USER"`
|
User string `json:"user" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_USER"`
|
||||||
CapDrop []string `json:"cap_drop"`
|
CapDrop []string `json:"cap_drop" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_CAP_DROP"`
|
||||||
Env map[string]string `json:"env"`
|
Env map[string]string `json:"env" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_ENV"`
|
||||||
SetupCommand string `json:"setup_command" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_SETUP_COMMAND"`
|
SetupCommand string `json:"setup_command" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_SETUP_COMMAND"`
|
||||||
PidsLimit int64 `json:"pids_limit" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_PIDS_LIMIT"`
|
PidsLimit int64 `json:"pids_limit" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_PIDS_LIMIT"`
|
||||||
Memory string `json:"memory" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_MEMORY"`
|
Memory string `json:"memory" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_MEMORY"`
|
||||||
MemorySwap string `json:"memory_swap" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_MEMORY_SWAP"`
|
MemorySwap string `json:"memory_swap" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_MEMORY_SWAP"`
|
||||||
Cpus float64 `json:"cpus" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_CPUS"`
|
Cpus float64 `json:"cpus" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_CPUS"`
|
||||||
Ulimits map[string]AgentSandboxDockerUlimitValue `json:"ulimits"`
|
Ulimits map[string]AgentSandboxDockerUlimitValue `json:"ulimits" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_ULIMITS"`
|
||||||
SeccompProfile string `json:"seccomp_profile" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_SECCOMP_PROFILE"`
|
SeccompProfile string `json:"seccomp_profile" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_SECCOMP_PROFILE"`
|
||||||
ApparmorProfile string `json:"apparmor_profile" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_APPARMOR_PROFILE"`
|
ApparmorProfile string `json:"apparmor_profile" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_APPARMOR_PROFILE"`
|
||||||
DNS []string `json:"dns"`
|
DNS []string `json:"dns" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_DNS"`
|
||||||
ExtraHosts []string `json:"extra_hosts"`
|
ExtraHosts []string `json:"extra_hosts" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_EXTRA_HOSTS"`
|
||||||
Binds []string `json:"binds"`
|
Binds []string `json:"binds" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER_BINDS"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AgentSandboxConfig struct {
|
type AgentSandboxConfig struct {
|
||||||
|
|
@ -531,17 +531,17 @@ type AgentSandboxConfig struct {
|
||||||
Scope string `json:"scope" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_SCOPE"`
|
Scope string `json:"scope" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_SCOPE"`
|
||||||
WorkspaceAccess string `json:"workspace_access" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_WORKSPACE_ACCESS"`
|
WorkspaceAccess string `json:"workspace_access" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_WORKSPACE_ACCESS"`
|
||||||
WorkspaceRoot string `json:"workspace_root" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_WORKSPACE_ROOT"`
|
WorkspaceRoot string `json:"workspace_root" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_WORKSPACE_ROOT"`
|
||||||
Docker AgentSandboxDockerConfig `json:"docker"`
|
Docker AgentSandboxDockerConfig `json:"docker" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_DOCKER"`
|
||||||
Prune AgentSandboxPruneConfig `json:"prune"`
|
Prune AgentSandboxPruneConfig `json:"prune" env:"PICOCLAW_AGENTS_DEFAULTS_SANDBOX_PRUNE"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SandboxToolPolicyConfig struct {
|
type SandboxToolPolicyConfig struct {
|
||||||
Allow []string `json:"allow"`
|
Allow []string `json:"allow" env:"PICOCLAW_TOOLS_SANDBOX_TOOLS_ALLOW"`
|
||||||
Deny []string `json:"deny"`
|
Deny []string `json:"deny" env:"PICOCLAW_TOOLS_SANDBOX_TOOLS_DENY"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SandboxToolsConfig struct {
|
type SandboxToolsConfig struct {
|
||||||
Tools SandboxToolPolicyConfig `json:"tools"`
|
Tools SandboxToolPolicyConfig `json:"tools" env:"PICOCLAW_TOOLS_SANDBOX_TOOLS"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ToolsConfig struct {
|
type ToolsConfig struct {
|
||||||
|
|
@ -549,7 +549,7 @@ type ToolsConfig struct {
|
||||||
Cron CronToolsConfig `json:"cron"`
|
Cron CronToolsConfig `json:"cron"`
|
||||||
Exec ExecConfig `json:"exec"`
|
Exec ExecConfig `json:"exec"`
|
||||||
Skills SkillsToolsConfig `json:"skills"`
|
Skills SkillsToolsConfig `json:"skills"`
|
||||||
Sandbox SandboxToolsConfig `json:"sandbox"`
|
Sandbox SandboxToolsConfig `json:"sandbox" env:"PICOCLAW_TOOLS_SANDBOX"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SkillsToolsConfig struct {
|
type SkillsToolsConfig struct {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ func DefaultConfig() *Config {
|
||||||
WorkspaceAccess: "none",
|
WorkspaceAccess: "none",
|
||||||
WorkspaceRoot: "~/.picoclaw/sandboxes",
|
WorkspaceRoot: "~/.picoclaw/sandboxes",
|
||||||
Docker: AgentSandboxDockerConfig{
|
Docker: AgentSandboxDockerConfig{
|
||||||
Image: "openclaw-sandbox:bookworm-slim",
|
Image: "picoclaw-sandbox:bookworm-slim",
|
||||||
ContainerPrefix: "picoclaw-sbx-",
|
ContainerPrefix: "picoclaw-sbx-",
|
||||||
Workdir: "/workspace",
|
Workdir: "/workspace",
|
||||||
ReadOnlyRoot: true,
|
ReadOnlyRoot: true,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue