Skip to content

feat: Docker provider with full Provider interface - #4

Merged
mainadwitiya merged 1 commit into
mainfrom
docker-provider
Mar 16, 2026
Merged

mainadwitiya merged 1 commit into
mainfrom
docker-provider

Conversation

@mainadwitiya

Copy link
Copy Markdown
Contributor

Summary

  • Full Docker provider using Go Docker SDK v27 (no CLI) — implements all 16 Provider interface methods
  • Security hardened: cap_drop: ALL, network isolation, read-only rootfs, seccomp, cgroup limits (memory + CPU quota + pids)
  • Runtime swappable: runc (default) → runsc (gVisor) → kata-runtime (Kata) — one config line
  • Pool mode: scoped /workspace/{sandbox-id}/ paths with path traversal prevention
  • Shell injection safe: GlobFiles passes pattern via $GLOB_PATTERN env var, never string-interpolated
  • 20 tests: unit tests (no Docker needed) + integration suite (auto-skips if Docker unavailable)
  • README overhaul: SVG architecture diagram, Docker provider docs, comparison table, E2B removed from provider diagram (partial implementation)

Key implementation details

  • Exec/ExecStream: uses stdcopy.StdCopy to demux Docker's multiplexed stdout/stderr stream
  • WriteFile: in-memory tar archive → CopyToContainer
  • ReadFile: CopyFromContainer → tar extraction via tarFileReader
  • ListFiles: shell while read loop with stat -c '%n|%s|%a|%F|%Y' (BusyBox-safe, | separator)
  • ExecStream: ctxChanWriter with select { ctx.Done() } prevents goroutine leaks on cancelled context
  • Destroy: removes from sandboxes map before Docker API call — guarantees cleanup even on error
  • ensureImage: checks local image cache before pulling; detects partial pulls via io.Copy error

Test plan

  • go test ./internal/providers/ -run TestDockerProvider -v — unit tests pass without Docker
  • go test ./internal/providers/ -run TestDockerIntegration -v — integration tests with Docker running
  • go build ./... — clean build
  • Start server with forgevm.yaml (docker provider enabled) and run scripts/test_multiuser_pool.py
  • Verify gVisor: set runtime: runsc in config, confirm containers start with gVisor runtime

- Implement all 16 Provider interface methods using Go Docker SDK v27
  (no CLI exec — pure API via github.com/docker/docker/client)
- Spawn: ContainerCreate + ContainerStart with full security hardening
  (cap_drop, network isolation, read-only rootfs, seccomp, cgroup limits)
- Exec/ExecStream: ContainerExecCreate + ContainerExecAttach with
  stdcopy.StdCopy for proper stdout/stderr demultiplexing
- WriteFile: in-memory tar archive via CopyToContainer
- ReadFile: CopyFromContainer + tar extraction via tarFileReader
- ListFiles: shell loop with stat -c and | separator (BusyBox-safe)
- GlobFiles: pattern passed via $GLOB_PATTERN env var (injection-safe)
- StatFile: ContainerStatPath + exec stat for full metadata
- Runtime field supports runc (default), runsc (gVisor), kata-runtime
- Pool mode: scoped workspace paths with traversal prevention
- 20 tests: unit (no Docker needed) + integration (skipIfNoDocker)
- Register Docker provider in cmd_serve.go
- Add DockerConfig + PoolSecurityConfig to internal/config
- Update README: SVG architecture diagram, Docker provider docs,
  comparison table, remove E2B from provider diagram (partial impl)
@mainadwitiya
mainadwitiya merged commit 41b644f into main Mar 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant