feat(sandbox): pluggable ISandboxProvider with auto-detection (Docker/gVisor/Firecracker)#1
feat(sandbox): pluggable ISandboxProvider with auto-detection (Docker/gVisor/Firecracker)#1jamtujest wants to merge 1 commit into
Conversation
…ection Introduces a pluggable sandbox provider architecture that allows OpenClaw to use different isolation backends (Docker, gVisor, Firecracker) through a unified interface, with automatic detection of the strongest available backend on the host. New files: - provider.ts: ISandboxProvider interface with types for SandboxInstance, SandboxExecRequest/Result, SandboxStatus - providers/docker-provider.ts: DockerProvider wrapping existing docker.ts - providers/gvisor-provider.ts: GVisorProvider stub with runsc detection - providers/index.ts: re-exports - provider-resolver.ts: auto-detect best backend (Firecracker > gVisor > Docker) Modified: - types.ts: add SandboxBackend type and backend field to SandboxConfig Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: afb22127dc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (hasGVisorRuntime()) { | ||
| log.info("gVisor (runsc) runtime detected"); | ||
| return "gvisor"; | ||
| } |
There was a problem hiding this comment.
Skip auto-selecting gVisor until provider is implemented
When backend is auto and runsc is present, this resolver returns "gvisor", but the selected provider still throws not yet implemented for instance creation and command execution (src/agents/sandbox/providers/gvisor-provider.ts). In environments with gVisor installed, sandbox startup will fail instead of falling back to the working Docker path, so auto-detection should not choose gVisor until those core methods are implemented.
Useful? React with 👍 / 👎.
| ["info", "--format", `{{index .Runtimes "${this.runtime}"}}`], | ||
| { allowFailure: true }, | ||
| ); | ||
| return runtimeCheck.code === 0 && runtimeCheck.stdout.trim().length > 0; |
There was a problem hiding this comment.
Treat missing runtime probe output as unavailable
This availability check treats any non-empty output from {{index .Runtimes "..."}} as success, but Docker templates emit <no value> when a map key is missing, so hosts without the configured runtime can still be marked as available. That makes initialize() incorrectly succeed and pushes the failure to later sandbox operations instead of raising the intended runtime-not-installed error early.
Useful? React with 👍 / 👎.
Critical: - #1: VNC proxy now validates Origin header, requires per-sandbox auth token, defaults to localhost-only origins High: - openclaw#2: VNC proxy: add 1 MiB read limit, 30s pong deadline, 10s write deadline, ping/pong keepalive handler - openclaw#3: URLPolicy.Validate now resolves DNS hostnames and blocks if any resolved IP is private/loopback/link-local/metadata - openclaw#4: BrowserService.Navigate re-validates final URL after redirect, navigates to about:blank if blocked - openclaw#5: FileService restricts all paths to /workspace via resolvePath() that rejects absolute paths, .., and symlink escapes - openclaw#6: TypeScript browser-security.ts now detects decimal/hex IPv4, IPv4-mapped IPv6, ULA fc00::/7, link-local fe80::/10 - openclaw#7: HTTP server binds 127.0.0.1 (not 0.0.0.0), VNC proxy disabled by default (port 0), /debug/vars implicitly protected - openclaw#8: chroot linkOrCopy only falls back on EXDEV, copyFile uses O_EXCL+O_WRONLY to prevent symlink-following writes Medium: - openclaw#9: Streaming rootfs hash via io.Copy+sha256.New instead of os.ReadFile into memory - openclaw#10: Shell-escape each exec argument before joining to prevent injection via sh -lc - openclaw#11: envd TCP mode prints explicit development-only warning - openclaw#12: Pool.Acquire now returns release callback, eviction skips leased (in-flight) snapshot directories Low: - openclaw#13: Validate snapshot metadata vcpu_count [1,32] and mem_size_mib [128,65536] before restore - openclaw#14: Use lastIndexOf for Playwright end marker, truncate raw stdout in error messages to 4KB Co-Authored-By: Claude Opus 4.6 <[email protected]>
1. ProcessService: kill entire process group on context cancel (not just DeadlineExceeded), add SIGTERM→SIGKILL escalation, make streamPipe exit on ctx.Done() to prevent orphaned processes and hung RPCs (#1) 2. Unix socket: chmod 0600 after Listen to restrict access to owner (openclaw#2) 3. SSRF: detect and reject octal IPv4 notation (e.g. 0177.0.0.1) that Chromium/WHATWG interprets differently than Go's net.ParseIP (openclaw#6) 4. Screenshot: enforce 10MB hard limit on buffer to prevent memory exhaustion from full-page captures on attacker-controlled pages (openclaw#8) 5. Firecracker version: capture prerelease suffix in regex and reject prerelease builds (e.g. 1.14.1-rc1) at the minimum version gate (openclaw#14) Co-Authored-By: Claude Opus 4.6 <[email protected]>
1. ProcessService: kill entire process group on context cancel (not just DeadlineExceeded), add SIGTERM→SIGKILL escalation, make streamPipe exit on ctx.Done() to prevent orphaned processes and hung RPCs (#1) 2. Unix socket: chmod 0600 after Listen to restrict access to owner (openclaw#2) 3. SSRF: detect and reject octal IPv4 notation (e.g. 0177.0.0.1) that Chromium/WHATWG interprets differently than Go's net.ParseIP (openclaw#6) 4. Screenshot: enforce 10MB hard limit on buffer to prevent memory exhaustion from full-page captures on attacker-controlled pages (openclaw#8) 5. Firecracker version: capture prerelease suffix in regex and reject prerelease builds (e.g. 1.14.1-rc1) at the minimum version gate (openclaw#14) Co-Authored-By: Claude Opus 4.6 <[email protected]>
Summary
ISandboxProviderinterface for pluggable sandbox backends (Docker, gVisor, Firecracker MicroVM)DockerProviderwrapping existingdocker.tswith zero behavior changesGVisorProviderstub with--runtime=runscdetection for user-space kernel isolationprovider-resolver.tswith auto-detection of strongest available backend (Firecracker > gVisor > Docker)SandboxBackendtype andbackendfield toSandboxConfigWhy?
Current sandbox (openclaw#29974) relies on Docker socket, sharing the host kernel. This PR enables:
runscruntime/dev/kvmAuto-detection picks the strongest available backend.
Files
src/agents/sandbox/provider.tsISandboxProviderinterface + typessrc/agents/sandbox/providers/docker-provider.tssrc/agents/sandbox/providers/gvisor-provider.tssrc/agents/sandbox/providers/index.tssrc/agents/sandbox/provider-resolver.tssrc/agents/sandbox/types.tsSandboxBackendtype +backendfieldTest plan
Generated with Claude Code