Summary
Add docker-sbx as a new sandbox.agent.runtime option in the gh-aw compiler, alongside the existing gvisor runtime (merged in #44796). This runtime runs the agent inside a Docker sbx microVM with hypervisor-level isolation (KVM), while infrastructure containers (Squid proxy, api-proxy, MCP gateway) remain in Docker Compose on the host.
The AWF (gh-aw-firewall) side is implemented in github/gh-aw-firewall#6101. This issue covers the compiler changes needed to generate the correct lock.yml for docker-sbx workflows.
Proposed Frontmatter
sandbox:
agent:
id: awf
runtime: docker-sbx
sudo: true # required — install step uses sudo
This follows the same pattern as runtime: gvisor (#44796). When sandbox.agent.runtime: docker-sbx is set, the compiler should generate the following additional steps and configuration changes in the lock.yml.
Required Compiler Changes
1. Early Fail-Fast Checks (new steps)
Generate steps that run before sbx installation:
- KVM availability: Check
lsmod | grep kvm and /dev/kvm writability. Fail immediately with a clear error if KVM is not available (runner must support nested virtualization).
- Docker secrets: Verify
secrets.DOCKER_PAT and secrets.DOCKER_USERNAME are non-empty. Fail with actionable error message if either is missing.
2. sbx Installation Step (analogous to generateGVisorInstallStep)
Like generateGVisorInstallStep(), add a generateDockerSbxInstallStep():
# Add Docker apt repo (REPO_ONLY=1 skips installing Docker Engine)
curl -fsSL https://get.docker.com | sudo REPO_ONLY=1 sh
sudo apt-get install -y docker-sbx
sbx version
# Fix KVM permissions for runner user
sudo chmod 666 /dev/kvm
3. sbx Authentication & Daemon Startup
# Start daemon
nohup sbx daemon start > /tmp/sbx-daemon.log 2>&1 &
# Wait for running state (poll up to 10s)
# Authenticate with Docker Hub
printf '%s' "$DOCKER_PAT_VAL" | docker login --username "$DOCKER_USERNAME_VAL" --password-stdin
printf '%s' "$DOCKER_PAT_VAL" | sbx login --username "$DOCKER_USERNAME_VAL" --password-stdin
# Reset policy and re-initialize (required for mount policy)
sbx daemon stop || true
sbx policy reset --force || true
sbx policy init allow-all
# Restart daemon + re-authenticate
# Pre-pull template image
docker pull docker/sandbox-templates:shell-docker
4. sbx Pre-Flight Smoke Test
After install and auth, verify the sbx stack works end-to-end before committing to the expensive MCP gateway and AWF container setup. This catches daemon failures, KVM issues, or image pull problems early:
# Create a throwaway sandbox, exec a command, then clean up
yes | sbx create shell --name test-sandbox-direct "$GITHUB_WORKSPACE"
sbx exec test-sandbox-direct uname -a
sbx stop test-sandbox-direct
sbx rm --force test-sandbox-direct
echo "✅ sbx ready"
If this fails, the step should error with a clear message indicating the sbx environment is not functional.
5. MCP Gateway Routing for microVM
The sbx microVM cannot resolve Docker container names. The MCP gateway must be accessible via host.docker.internal:
- Bind MCP gateway to
0.0.0.0 (not 127.0.0.1) so it is reachable from non-loopback addresses
- Set
MCP_GATEWAY_HOST_DOMAIN=host.docker.internal
- Use
host.docker.internal as gateway.domain in mcp-config.json
- Use
host.docker.internal as MCP_GATEWAY_DOMAIN in the "Mount MCP servers as CLIs" step (so generated CLI wrapper scripts point to the correct URL from inside the microVM)
6. AWF Config Generation
When docker-sbx runtime is selected:
- Pass
--container-runtime sbx to the awf CLI invocation
- Add
host.docker.internal to network.allowDomains
- Set
network.isolation: true (disables host iptables — enforcement is purely via Docker network topology, regardless of sudo: true)
- Keep
topologyAttach: ["awmg-mcpg"] (AWF connects the MCP gateway container to awf-net for infrastructure routing)
7. Credential Exclusion (Security-Critical)
The agent must never have access to real authentication tokens. Add these flags to the AWF invocation:
--exclude-env COPILOT_GITHUB_TOKEN
--exclude-env GITHUB_MCP_SERVER_TOKEN
--exclude-env MCP_GATEWAY_API_KEY
The api-proxy sidecar handles credential injection transparently. The agent receives:
COPILOT_API_URL=http://host.docker.internal:10002 (api-proxy)
COPILOT_PROVIDER_BASE_URL=http://host.docker.internal:10002
- A dummy BYOK key (never the real token)
8. Compile-Time Validation
Reject incompatible combinations at compile time:
| Combination |
Error |
runtime: docker-sbx + runner.topology: arc-dind |
sbx requires KVM; ARC DinD runners typically lack nested virt |
runtime: docker-sbx + sudo: false (default) |
Install step requires root; must set sudo: true |
runtime: docker-sbx without DOCKER_PAT/DOCKER_USERNAME secrets configured |
sbx requires Docker Hub authentication |
Like gVisor, sudo: true's deprecation warning/error should be suppressed when runtime: docker-sbx is set — sbx fundamentally requires root so the warning would be misleading.
Important: Despite requiring sudo: true, the network topology must always use network.isolation: true (no host iptables). The sudo is only for the install steps, not for network enforcement.
9. Schema & Documentation
- Add
docker-sbx to the sandbox.agent.runtime enum in main_workflow_schema.json (alongside gvisor)
- Add
AgentRuntimeDockerSbx AgentRuntime = "docker-sbx" constant in sandbox.go
- Add
isDockerSbxRuntime() helper in firewall.go
- Document required secrets:
DOCKER_PAT, DOCKER_USERNAME
- Document hardware requirement: KVM-capable runner (e.g., GitHub-hosted
ubuntu-latest 4-core+)
Architecture Reference
Host Runner
├── Docker Compose (awf-net, internal + awf-ext, bridge)
│ ├── awf-squid (172.30.0.10) — domain ACL filtering
│ ├── awf-api-proxy (172.30.0.30) — credential injection, on awf-ext
│ └── awmg-mcpg (bridge, published 0.0.0.0:8080) — MCP gateway
│
└── Docker sbx microVM (KVM-isolated)
├── eth0 gateway: 172.17.0.0
├── host.docker.internal → 172.17.0.1 (docker0 bridge)
├── Squid: via 172.17.0.0:3128 (port-published)
├── Api-proxy: via host.docker.internal:10000-10004 (docker0 bridge → awf-ext)
├── MCP gateway: via host.docker.internal:8080 (port-published)
└── Direct outbound: BLOCKED (proxy-only egress)
Key Differences from gVisor
| Aspect |
gVisor |
docker-sbx |
| Isolation |
Userspace kernel (OCI runtime) |
Hardware VM (KVM hypervisor) |
| Agent lifecycle |
Docker Compose service |
External sbx CLI |
| Docker runtime field |
runsc |
N/A (not OCI) |
| Sudo required |
Yes (install step) |
Yes (install step) |
| Network isolation |
network.isolation: true |
network.isolation: true (always, regardless of sudo) |
| Static DNS needed |
Yes (gVisor netstack quirk) |
No (sbx manages DNS) |
| Agent in compose |
Yes |
No (omitted from docker-compose.yml) |
| Extra secrets |
None |
DOCKER_PAT, DOCKER_USERNAME |
| Pre-pull required |
No |
Yes (docker/sandbox-templates:shell-docker) |
| Pre-flight test |
No |
Yes (create → exec → rm throwaway sandbox) |
Acceptance Criteria
Related
Summary
Add
docker-sbxas a newsandbox.agent.runtimeoption in the gh-aw compiler, alongside the existinggvisorruntime (merged in #44796). This runtime runs the agent inside a Docker sbx microVM with hypervisor-level isolation (KVM), while infrastructure containers (Squid proxy, api-proxy, MCP gateway) remain in Docker Compose on the host.The AWF (gh-aw-firewall) side is implemented in github/gh-aw-firewall#6101. This issue covers the compiler changes needed to generate the correct lock.yml for
docker-sbxworkflows.Proposed Frontmatter
This follows the same pattern as
runtime: gvisor(#44796). Whensandbox.agent.runtime: docker-sbxis set, the compiler should generate the following additional steps and configuration changes in the lock.yml.Required Compiler Changes
1. Early Fail-Fast Checks (new steps)
Generate steps that run before sbx installation:
lsmod | grep kvmand/dev/kvmwritability. Fail immediately with a clear error if KVM is not available (runner must support nested virtualization).secrets.DOCKER_PATandsecrets.DOCKER_USERNAMEare non-empty. Fail with actionable error message if either is missing.2. sbx Installation Step (analogous to
generateGVisorInstallStep)Like
generateGVisorInstallStep(), add agenerateDockerSbxInstallStep():3. sbx Authentication & Daemon Startup
4. sbx Pre-Flight Smoke Test
After install and auth, verify the sbx stack works end-to-end before committing to the expensive MCP gateway and AWF container setup. This catches daemon failures, KVM issues, or image pull problems early:
If this fails, the step should error with a clear message indicating the sbx environment is not functional.
5. MCP Gateway Routing for microVM
The sbx microVM cannot resolve Docker container names. The MCP gateway must be accessible via
host.docker.internal:0.0.0.0(not127.0.0.1) so it is reachable from non-loopback addressesMCP_GATEWAY_HOST_DOMAIN=host.docker.internalhost.docker.internalasgateway.domaininmcp-config.jsonhost.docker.internalasMCP_GATEWAY_DOMAINin the "Mount MCP servers as CLIs" step (so generated CLI wrapper scripts point to the correct URL from inside the microVM)6. AWF Config Generation
When
docker-sbxruntime is selected:--container-runtime sbxto theawfCLI invocationhost.docker.internaltonetwork.allowDomainsnetwork.isolation: true(disables host iptables — enforcement is purely via Docker network topology, regardless ofsudo: true)topologyAttach: ["awmg-mcpg"](AWF connects the MCP gateway container toawf-netfor infrastructure routing)7. Credential Exclusion (Security-Critical)
The agent must never have access to real authentication tokens. Add these flags to the AWF invocation:
The api-proxy sidecar handles credential injection transparently. The agent receives:
COPILOT_API_URL=http://host.docker.internal:10002(api-proxy)COPILOT_PROVIDER_BASE_URL=http://host.docker.internal:100028. Compile-Time Validation
Reject incompatible combinations at compile time:
runtime: docker-sbx+runner.topology: arc-dindruntime: docker-sbx+sudo: false(default)sudo: trueruntime: docker-sbxwithoutDOCKER_PAT/DOCKER_USERNAMEsecrets configuredLike gVisor,
sudo: true's deprecation warning/error should be suppressed whenruntime: docker-sbxis set — sbx fundamentally requires root so the warning would be misleading.Important: Despite requiring
sudo: true, the network topology must always usenetwork.isolation: true(no host iptables). Thesudois only for the install steps, not for network enforcement.9. Schema & Documentation
docker-sbxto thesandbox.agent.runtimeenum inmain_workflow_schema.json(alongsidegvisor)AgentRuntimeDockerSbx AgentRuntime = "docker-sbx"constant insandbox.goisDockerSbxRuntime()helper infirewall.goDOCKER_PAT,DOCKER_USERNAMEubuntu-latest4-core+)Architecture Reference
Key Differences from gVisor
runscnetwork.isolation: truenetwork.isolation: true(always, regardless of sudo)DOCKER_PAT,DOCKER_USERNAMEdocker/sandbox-templates:shell-docker)Acceptance Criteria
sandbox.agent.runtime: docker-sbxcompiles to a valid lock.yml0.0.0.0and CLI wrappers usehost.docker.internal--container-runtime sbxand credential exclusion flagshost.docker.internalin allowDomainsnetwork.isolation: truealways set (even withsudo: true)sudo: truerequired (error if omitted), deprecation warning suppressedmain_workflow_schema.json)Related
github/gh-aw-firewall:.github/workflows/smoke-docker-sbx.lock.yml