[awf] ARC/DinD chroot: auto-stage runner binary and critical /etc files for split-filesystem Docker hosts#3852
[awf] ARC/DinD chroot: auto-stage runner binary and critical /etc files for split-filesystem Docker hosts#3852Copilot wants to merge 3 commits into
Conversation
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 96.58% | 96.52% | 📉 -0.06% |
| Statements | 96.44% | 96.39% | 📉 -0.05% |
| Functions | 98.19% | 98.21% | 📈 +0.02% |
| Branches | 90.86% | 90.51% | 📉 -0.35% |
📁 Per-file Coverage Changes (4 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/services/agent-volumes/workspace-mounts.ts |
100.0% → 97.8% (-2.23%) | 100.0% → 97.8% (-2.23%) |
src/services/agent-volumes/hosts-file.ts |
79.5% → 80.5% (+1.00%) | 81.0% → 81.8% (+0.86%) |
src/services/host-path-prefix.ts |
87.0% → 88.0% (+1.05%) | 88.9% → 89.7% (+0.77%) |
src/config-writer.ts |
89.3% → 90.9% (+1.65%) | 89.3% → 90.9% (+1.65%) |
✨ New Files (1 files)
src/services/agent-volumes/docker-host-staging.ts: 85.4% lines
Coverage comparison generated by scripts/ci/compare-coverage.ts
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
This PR improves ARC + DinD “split runner/daemon filesystem” support for AWF chroot mode by automatically staging a few runner-side artifacts into a daemon-visible shared /tmp location when --docker-host-path-prefix points under /tmp, reducing manual bootstrap steps.
Changes:
- Adds a Docker-host staging helper to copy
/etc/passwd,/etc/group, the invoked CLI binary, and the generated chroot/etc/hostsinto a shared staging root under the configured/tmpprefix. - Updates agent volume generation and tool-specific environment wiring to use staged artifacts and to pass
AWF_STAGED_RUNNER_BINARY_NAMEto the container for chroot bootstrap. - Updates bind-mount host-path translation to avoid re-prefixing mounts that are already under the configured docker-host prefix; adds docs for ARC/DinD behavior.
Show a summary per file
| File | Description |
|---|---|
| src/services/host-path-prefix.ts | Prevents double-prefixing bind-mount sources already under the configured prefix. |
| src/services/agent-volumes/workspace-mounts.ts | Stages the invoked CLI binary into a docker-host-visible location and mounts it into the agent. |
| src/services/agent-volumes/volume-builder.ts | Passes config into /etc mounts to enable staging behavior. |
| src/services/agent-volumes/hosts-file.ts | Writes generated chroot /etc/hosts under the staging root when enabled. |
| src/services/agent-volumes/etc-mounts.ts | Stages /etc/passwd and /etc/group under the shared /tmp prefix when enabled. |
| src/services/agent-volumes/docker-host-staging.ts | New staging utility module (prefix detection, stage root management, file copy, command binary extraction). |
| src/services/agent-volumes-mounts.test.ts | Adds coverage asserting staged mounts under a /tmp docker-host-path-prefix. |
| src/services/agent-environment/tool-specific-environment.ts | Wires AWF_STAGED_RUNNER_BINARY_NAME for chroot to consume staged runner binary. |
| src/services/agent-environment/excluded-vars.ts | Excludes AWF_STAGED_RUNNER_BINARY_NAME from host env passthrough. |
| src/services/agent-environment-runtime.test.ts | Adds coverage for AWF_STAGED_RUNNER_BINARY_NAME env wiring in /tmp prefix mode. |
| docs/arc-dind.md | Documents ARC + DinD staging behavior and remaining Node.js requirement. |
| containers/agent/entrypoint.sh | Consumes AWF_STAGED_RUNNER_BINARY_NAME to copy staged binary into chroot PATH under /tmp/awf-lib. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 12/12 changed files
- Comments generated: 5
| STAGED_RUNNER_BINARY_CHROOT="" | ||
| if [ -n "${AWF_STAGED_RUNNER_BINARY_NAME:-}" ] && [ -f "/tmp/awf-runner-bin/${AWF_STAGED_RUNNER_BINARY_NAME}" ]; then | ||
| if mkdir -p /host/tmp/awf-lib 2>/dev/null; then | ||
| if cp "/tmp/awf-runner-bin/${AWF_STAGED_RUNNER_BINARY_NAME}" "/host/tmp/awf-lib/${AWF_STAGED_RUNNER_BINARY_NAME}" 2>/dev/null && \ | ||
| chmod +x "/host/tmp/awf-lib/${AWF_STAGED_RUNNER_BINARY_NAME}" 2>/dev/null; then |
| const hostsRootDir = shouldUseDockerHostStaging(config.dockerHostPathPrefix) | ||
| ? getDockerHostStageRoot(config) | ||
| : config.workDir; | ||
| const chrootHostsDir = fs.mkdtempSync(path.join(hostsRootDir, 'chroot-')); |
| export function stageHostFile(config: WrapperConfig, sourcePath: string, relativeTargetPath: string, mode = 0o644): string | undefined { | ||
| try { | ||
| if (!fs.statSync(sourcePath).isFile()) { | ||
| return undefined; | ||
| } | ||
| } catch { | ||
| return undefined; | ||
| } | ||
|
|
||
| try { | ||
| const stageRoot = getDockerHostStageRoot(config); | ||
| const targetPath = path.join(stageRoot, relativeTargetPath.replace(/^\/+/, '')); | ||
| fs.mkdirSync(path.dirname(targetPath), { recursive: true }); | ||
| fs.copyFileSync(sourcePath, targetPath); | ||
| fs.chmodSync(targetPath, mode); |
| const stagedGroupPath = stageHostFile(config, '/etc/group', 'etc/group'); | ||
| mounts.push(`${stagedPasswdPath || '/etc/passwd'}:/host/etc/passwd:ro`); | ||
| mounts.push(`${stagedGroupPath || '/etc/group'}:/host/etc/group:ro`); | ||
|
|
| function resolveBinaryPath(binaryName: string): string | undefined { | ||
| if (!binaryName) { | ||
| return undefined; | ||
| } | ||
| const pathEntries = (process.env.PATH || '').split(path.delimiter).filter(Boolean); | ||
| for (const entry of pathEntries) { | ||
| const candidate = path.join(entry, binaryName); | ||
| try { | ||
| const stat = fs.statSync(candidate); | ||
| if (stat.isFile()) { | ||
| return candidate; | ||
| } | ||
| } catch { | ||
| // Keep scanning PATH entries. |
This comment has been minimized.
This comment has been minimized.
|
@copilot address review feedback and make sure that all docs, specs, and schema are consistent with the implementation |
Addressed in a929b96. I fixed the review feedback around staged-path validation, staged runner binary safety, stale chroot-host staging cleanup, executable binary resolution, and the |
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 96.58% | 96.48% | 📉 -0.10% |
| Statements | 96.44% | 96.35% | 📉 -0.09% |
| Functions | 98.19% | 98.22% | 📈 +0.03% |
| Branches | 90.86% | 90.54% | 📉 -0.32% |
📁 Per-file Coverage Changes (4 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/services/agent-volumes/workspace-mounts.ts |
100.0% → 96.3% (-3.71%) | 100.0% → 96.3% (-3.71%) |
src/config-writer.ts |
89.3% → 90.9% (+1.65%) | 89.3% → 90.9% (+1.65%) |
src/services/host-path-prefix.ts |
87.0% → 89.3% (+2.33%) | 88.9% → 90.6% (+1.74%) |
src/services/agent-volumes/hosts-file.ts |
79.5% → 82.1% (+2.66%) | 81.0% → 83.0% (+2.10%) |
✨ New Files (1 files)
src/services/agent-volumes/docker-host-staging.ts: 87.2% lines
Coverage comparison generated by scripts/ci/compare-coverage.ts
| const stageRoot = '/tmp/gh-aw/awf-docker-host-stage'; | ||
| const staleDir = path.join(stageRoot, 'chroot-stale'); | ||
| fs.mkdirSync(staleDir, { recursive: true }); | ||
| fs.writeFileSync(path.join(staleDir, 'hosts'), '127.0.0.1 localhost\n'); |
🧪 Smoke Test: Copilot BYOK (Offline) Mode
Running in BYOK offline mode ( Author: Overall: PARTIAL PASS (BYOK inference + MCP confirmed ✅; pre-step variables not expanded)
|
🔥 Smoke Test Results
Overall: PASS PR: [awf] ARC/DinD chroot: auto-stage runner binary and critical /etc files for split-filesystem Docker hosts
|
|
[awf] ARC/DinD chroot: auto-stage runner binary and critical /etc files for split-filesystem Docker hosts ✅ Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "registry.npmjs.org"See Network Configuration for more information.
|
Chroot Runtime Version Comparison
Result: FAILED — Python and Node.js versions differ between host and chroot.
|
Gemini Smoke Test Results
Overall status: FAIL Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "localhost"See Network Configuration for more information.
|
🏗️ Build Test Suite Results
Overall: 8/8 ecosystems passed — ✅ PASS
|
Smoke Test Results
Overall: FAIL —
|
Smoke Test: Claude Engine — ✅ PASS
Total: PASS
|
ARC/DinD split-filesystem setups still required manual bootstrap to make chrooted agent runs work (copying binaries and core
/etcfiles into daemon-visible storage). This change removes those manual workarounds by auto-staging required assets when--docker-host-path-prefixtargets a shared/tmppath.Problem surface reduced in ARC/DinD mode
copilot,claude,codex)/etc/passwd/etc/group/etc/hosts/tmphost-prefix scenarios.Compose volume generation now supports staged artifacts
src/services/agent-volumes/docker-host-staging.tsfor:agentCommandEntrypoint chroot bootstrap now consumes staged runner binary
AWF_STAGED_RUNNER_BINARY_NAMEenvironment wiring./tmp/awf-runner-bin/<binary>into/tmp/awf-lib/<binary>and prepends/tmp/awf-libto chroot PATH./usr/local/bin.Host-path prefix safety improvement
translateBindMountHostPathnow avoids re-prefixing paths already under the configured docker host prefix.Documentation
docs/arc-dind.mdwith ARC/DinD behavior and explicit remaining Node.js requirement for Copilot CLI, including recommended base image guidance.