AWF supports ARC runners where the runner filesystem and Docker daemon filesystem are split (DinD sidecar patterns).
The simplest way to configure AWF for ARC/DinD is through the runner.topology config key:
{
"runner": {
"topology": "arc-dind"
}
}When runner.topology is set to "arc-dind", AWF enables ARC/DinD-specific sysroot staging behavior:
| Behavior | Default | Override |
|---|---|---|
Sysroot image for /host base |
build-tools:<tag> |
runner.sysrootImage |
Tool cache warning if under /opt |
Emitted | Set RUNNER_TOOL_CACHE to shared path |
Other ARC/DinD settings (for example network.isolation and dind.preStageDirs) are configured explicitly through their own fields.
On ARC/DinD, the standard system mounts (/usr:/host/usr:ro, etc.) resolve to the runner container's filesystem, which is invisible to the Docker daemon's split filesystem. The build-tools sysroot image solves this by providing a pre-built Ubuntu 22.04 image containing system-level build infrastructure:
- Compilers & linkers: gcc, g++, make, cmake, autoconf, binutils
- Dev libraries: libssl-dev, libc6-dev, libicu-dev, zlib1g-dev
- System utilities: bash, coreutils, git, curl, wget, jq
- Agent dependencies: libcap2-bin (capsh), gosu, gnupg, gh
- AWF emits a
sysroot-stageinit service in the compose file - The init container copies the build-tools image FS into a named
sysrootvolume - The agent mounts the
sysrootvolume read-only at/host entrypoint.shfinds/host/bin/shandcapsh, chroots successfully
# Generated docker-compose.yml (simplified)
services:
sysroot-stage:
image: ghcr.io/github/gh-aw-firewall/build-tools:0.28.0
volumes: ["sysroot:/sysroot"]
entrypoint: ["/bin/sh", "-c"]
command: ["cp -a /usr /lib /bin /sbin /etc /sysroot/ ..."]
agent:
depends_on:
sysroot-stage: { condition: service_completed_successfully }
volumes:
- sysroot:/host:rw
- /tmp/gh-aw/tool-cache:/host/tmp/gh-aw/tool-cache:ro
volumes:
sysroot: {}Override the default build-tools image:
{
"runner": {
"topology": "arc-dind",
"sysrootImage": "ghcr.io/my-org/custom-sysroot:latest"
}
}Language SDKs (Go, Node, Java, .NET) are NOT baked into the sysroot image. They are installed on-demand by setup-* actions into a shared tool cache volume.
Important: On ARC, RUNNER_TOOL_CACHE must point to a shared path visible to both the runner container and the DinD daemon (e.g., /tmp/gh-aw/tool-cache). The default /opt/hostedtoolcache is invisible to the DinD daemon.
# Early in workflow, before setup-* actions:
- run: echo "RUNNER_TOOL_CACHE=/tmp/gh-aw/tool-cache" >> "$GITHUB_ENV"- Split-filesystem probing for
--docker-host-path-prefix - Chroot staging for:
- invoking CLI binary (
copilot,claude,codex, etc.) /etc/passwd/etc/group- generated chroot
/etc/hosts
- invoking CLI binary (
- DinD
DOCKER_HOSTpropagation into agent/MCP environments when DinD is detected
For fine-grained control (or when not using runner.topology):
{
"container": {
"enableDind": true,
"dockerHostPathPrefix": "/tmp/gh-aw"
},
"chroot": {
"binariesSourcePath": "/tmp/gh-aw/runner-bin",
"identity": {
"home": "/tmp/gh-aw/home",
"user": "runner",
"uid": 1001,
"gid": 1001
}
},
"dind": {
"preStageDirs": true,
"workDir": "/tmp/gh-aw",
"stagingImage": "ghcr.io/github/gh-aw-firewall/agent:latest",
"stageEngineBinary": {
"path": "/usr/local/bin/copilot",
"targetPath": "/usr/local/bin/copilot"
}
},
"runner": {
"topology": "arc-dind",
"sysrootImage": "ghcr.io/github/gh-aw-firewall/build-tools:latest"
}
}chroot.identity.*: applied inside entrypoint afterchroot /hostto override HOME/USER/LOGNAME and identity mapping hints.chroot.binariesSourcePath: mounts a runner-side binaries directory over/usr/local/bininside chroot mode so runner-installed CLIs are visible even when/usrcomes from the DinD daemon filesystem.dind.preStageDirs: runs a short-lived staging container in DinD mode to create required workdir tree with open permissions.dind.stageEngineBinary: copies an engine binary from the runner path into daemon-visible filesystem before compose startup.dind.stagingImage: image used for short-lived staging containers.dind.workDir: target root for DinD pre-staged directory tree (/tmp/gh-awdefault).runner.topology: "arc-dind": enables sysroot staging (sysroot-stageinit service +sysrootvolume mounted on agent at/host:rw).runner.sysrootImage: optional override for the sysroot image used byrunner.topology=arc-dind.
When runner.topology is arc-dind, AWF starts a one-shot sysroot-stage service that copies
the filesystem from a build-tools image derived from the same --image-registry and --image-tag
settings as the other AWF containers (unless runner.sysrootImage overrides it) into a named
sysroot volume. The agent mounts that volume at /host:rw.
This image pre-installs root-required system build dependencies (for example gcc/make/cmake, libssl-dev/libc6-dev/libicu-dev, capsh/gosu/gh) so ARC workflow steps can stay non-root.
If RUNNER_TOOL_CACHE points under /opt (for example /opt/hostedtoolcache) AWF logs a warning
in runner.topology=arc-dind mode because /opt is commonly not visible from the DinD daemon
filesystem. Prefer a shared runner/daemon path under /tmp/gh-aw when possible.
AWF detects likely ARC/DinD environments at startup and warns when --docker-host-path-prefix is missing:
- non-default unix
DOCKER_HOSTsocket paths (outside/var/run/docker.sockand/run/docker.sock) - loopback TCP
DOCKER_HOSTendpoints (tcp://localhost:*ortcp://127.0.0.1:*) — the standard ARC RunnerScaleSet DinD sidecar configuration AWF_DIND=1
For ARC DinD chroot workloads, prefer the glibc companion image:
ghcr.io/github/gh-aw-firewall/dind-ubuntu:latest
It includes docker-ce, libcap2-bin (capsh), and Node.js preinstalled.
Copilot CLI still requires node to be available inside the chrooted runtime PATH.
- docs/awf-config-spec.md — Normative field reference and CLI mapping for all ARC/DinD config fields (
container.dockerHostPathPrefix,container.enableDind,container.dockerHost,chroot.*,dind.*,runner.*) - docs/awf-config.schema.json — Machine-readable JSON Schema for IDE validation
- docs/environment.md —
DOCKER_HOSThandling,AWF_DIND, and split-filesystem guidance