summaryrefslogtreecommitdiff
path: root/internal/config/config.go
diff options
context:
space:
mode:
authorClaude Sonnet 5 <noreply@anthropic.com>2026-07-03 09:21:32 +0000
committerClaude Sonnet 5 <noreply@anthropic.com>2026-07-03 09:21:32 +0000
commit767ddade57f189827fa956ff8081ca47404a4798 (patch)
treee2b44d0e943e1cc5cf2b11e0b826902a24b63802 /internal/config/config.go
parent81ae7d598e7ec6afe8afb5bbdbfe807042298559 (diff)
feat(sandbox): add DockerSandbox + pre-tool-use guardrail hooks (Phase 3)
Gives native-API-driven agents (currently just the Phase 2 Anthropic adapter) real container isolation, decoupled from model invocation -- the model call happens in the Go process via provider.Provider, only tool execution happens in the container, unlike the CLI-subprocess ContainerRunner (left completely untouched) where the claude/gemini CLI runs inside the container. - internal/sandbox/dockersandbox.go: Sandbox via a long-lived `docker run -d ... sleep infinity` container (started once per execution, not per tool call), host-side git clone + bind-mount matching ContainerRunner's existing pattern, docker exec for read/write/bash/glob. Reuses images/agent-base (claudomator-agent:latest) rather than standing up a second image. WorkDir()/resume persists the host bind-mount directory (matching HostSandbox's contract); a resumed sandbox lazily starts a fresh container against that directory rather than trying to reattach to a possibly-gone one. - internal/sandbox/guard.go, hooks.go: Hook interface (CheckBash/CheckWrite), Guarded wrapper, DenylistBashHook (rm -rf /, force-push, curl|sh, sudo, chmod 777, dd if=) and ProtectedPathHook (.git/**, .env*, credentials/, .github/workflows/**). A rejection returns *RejectionError, which agentloop/tools.go now recognizes and feeds back to the model as a normal (non-fatal) tool-error result instead of aborting the run. - NativeRunner wraps whichever Sandbox it builds (Host or Docker) in Guarded{Hooks: DefaultHooks()} uniformly. The "anthropic" runner now uses DockerSandbox; "local" stays on HostSandbox by design (local models are the harness's more-trusted, lower-stakes-to-run tier). Docker is not installed in this dev environment (no docker/podman/containerd on PATH), so DockerSandbox's real container-lifecycle behavior is verified via mocked-command unit tests only -- go test -race ./... passes throughout, with the two real-daemon integration tests gated behind a dockerAvailable(t) check and skipping here. Live verification against an actual Docker host is a follow-up before relying on the "anthropic" agent type in production. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V1moSNCJRcP6kykA4tyUSs
Diffstat (limited to 'internal/config/config.go')
-rw-r--r--internal/config/config.go59
1 files changed, 34 insertions, 25 deletions
diff --git a/internal/config/config.go b/internal/config/config.go
index de087d6..afbd12e 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -89,31 +89,39 @@ type ProviderConfig struct {
}
type Config struct {
- DataDir string `toml:"data_dir"`
- DBPath string `toml:"-"`
- LogDir string `toml:"-"`
- DropsDir string `toml:"-"`
- SSHAuthSock string `toml:"ssh_auth_sock"`
- ClaudeBinaryPath string `toml:"claude_binary_path"`
- GeminiBinaryPath string `toml:"gemini_binary_path"`
- ClaudeImage string `toml:"claude_image"`
- GeminiImage string `toml:"gemini_image"`
- MaxConcurrent int `toml:"max_concurrent"`
- ShutdownTimeout time.Duration `toml:"shutdown_timeout"`
- DefaultTimeout string `toml:"default_timeout"`
- ServerAddr string `toml:"server_addr"`
- WebhookURL string `toml:"webhook_url"`
- WorkspaceRoot string `toml:"workspace_root"`
- WebhookSecret string `toml:"webhook_secret"`
- APIToken string `toml:"api_token"` // shared bearer for web UI + chatbot MCP; empty disables both auth and the chatbot MCP endpoint
- Projects []Project `toml:"projects"`
- VAPIDPublicKey string `toml:"vapid_public_key"`
- VAPIDPrivateKey string `toml:"vapid_private_key"`
- VAPIDEmail string `toml:"vapid_email"`
- ClaudeConfigDir string `toml:"claude_config_dir"`
- LocalModel LocalModel `toml:"local_model"`
- Runners RunnersConfig `toml:"runners"`
- Budget BudgetConfig `toml:"budget"`
+ DataDir string `toml:"data_dir"`
+ DBPath string `toml:"-"`
+ LogDir string `toml:"-"`
+ DropsDir string `toml:"-"`
+ SSHAuthSock string `toml:"ssh_auth_sock"`
+ ClaudeBinaryPath string `toml:"claude_binary_path"`
+ GeminiBinaryPath string `toml:"gemini_binary_path"`
+ ClaudeImage string `toml:"claude_image"`
+ GeminiImage string `toml:"gemini_image"`
+ // SandboxImage is the docker image used by sandbox.DockerSandbox (the
+ // tool-execution sandbox for native-API-driven runners, e.g. the
+ // "anthropic" NativeRunner) — distinct from ClaudeImage/GeminiImage,
+ // which are for ContainerRunner's claude/gemini CLI-subprocess path.
+ // Defaults to the same image (images/agent-base) since it already has
+ // everything a generic git/bash sandbox needs; see
+ // internal/sandbox/dockersandbox.go's package doc for the tradeoff.
+ SandboxImage string `toml:"sandbox_image"`
+ MaxConcurrent int `toml:"max_concurrent"`
+ ShutdownTimeout time.Duration `toml:"shutdown_timeout"`
+ DefaultTimeout string `toml:"default_timeout"`
+ ServerAddr string `toml:"server_addr"`
+ WebhookURL string `toml:"webhook_url"`
+ WorkspaceRoot string `toml:"workspace_root"`
+ WebhookSecret string `toml:"webhook_secret"`
+ APIToken string `toml:"api_token"` // shared bearer for web UI + chatbot MCP; empty disables both auth and the chatbot MCP endpoint
+ Projects []Project `toml:"projects"`
+ VAPIDPublicKey string `toml:"vapid_public_key"`
+ VAPIDPrivateKey string `toml:"vapid_private_key"`
+ VAPIDEmail string `toml:"vapid_email"`
+ ClaudeConfigDir string `toml:"claude_config_dir"`
+ LocalModel LocalModel `toml:"local_model"`
+ Runners RunnersConfig `toml:"runners"`
+ Budget BudgetConfig `toml:"budget"`
// Providers configures native/OpenAI-compatible LLM backends by name (see
// ProviderConfig). Unused by runner construction in Phase 1.
Providers map[string]ProviderConfig `toml:"providers"`
@@ -147,6 +155,7 @@ func Default() (*Config, error) {
GeminiBinaryPath: "gemini",
ClaudeImage: "claudomator-agent:latest",
GeminiImage: "claudomator-agent:latest",
+ SandboxImage: "claudomator-agent:latest",
MaxConcurrent: 3,
DefaultTimeout: "15m",
ServerAddr: "127.0.0.1:8484",