From 350b0f4d4e1ec0c17d51e24b804c80ba0e1e1f35 Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Fri, 6 Feb 2026 01:46:18 +0000 Subject: [PATCH 1/2] fix: create resolv.conf in chroot when not mounted When using selective /etc mounts in chroot mode, /etc/resolv.conf is not included in the mount list. This causes DNS queries inside the chroot to fall back to the host's systemd-resolved (127.0.0.53), which is blocked by iptables (only 8.8.8.8, 8.8.4.4, 127.0.0.11 are allowed). As a result, agents like Codex cannot resolve domains like api.openai.com. Fix: when /host/etc/resolv.conf doesn't exist, create it from the container's /etc/resolv.conf (which already has the correct AWF DNS config). Clean up on exit by removing the created file. Co-Authored-By: Claude Opus 4.6 (1M context) --- containers/agent/entrypoint.sh | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/containers/agent/entrypoint.sh b/containers/agent/entrypoint.sh index 9598f19c..9eadefee 100644 --- a/containers/agent/entrypoint.sh +++ b/containers/agent/entrypoint.sh @@ -162,15 +162,28 @@ if [ "${AWF_CHROOT_ENABLED}" = "true" ]; then # NOTE: We backup the host's original resolv.conf and set up a trap to restore it RESOLV_BACKUP="/host/etc/resolv.conf.awf-backup-$$" RESOLV_MODIFIED=false - if cp /host/etc/resolv.conf "$RESOLV_BACKUP" 2>/dev/null; then - if cp /etc/resolv.conf /host/etc/resolv.conf.awf 2>/dev/null; then - mv /host/etc/resolv.conf.awf /host/etc/resolv.conf 2>/dev/null && RESOLV_MODIFIED=true - echo "[entrypoint] DNS configuration copied to chroot (backup at $RESOLV_BACKUP)" + RESOLV_CREATED=false + if [ -f /host/etc/resolv.conf ]; then + # File exists: backup original and replace with AWF DNS configuration + if cp /host/etc/resolv.conf "$RESOLV_BACKUP" 2>/dev/null; then + if cp /etc/resolv.conf /host/etc/resolv.conf.awf 2>/dev/null; then + mv /host/etc/resolv.conf.awf /host/etc/resolv.conf 2>/dev/null && RESOLV_MODIFIED=true + echo "[entrypoint] DNS configuration copied to chroot (backup at $RESOLV_BACKUP)" + else + echo "[entrypoint][WARN] Could not copy DNS configuration to chroot" + fi else - echo "[entrypoint][WARN] Could not copy DNS configuration to chroot" + echo "[entrypoint][WARN] Could not backup host resolv.conf, skipping DNS override" fi else - echo "[entrypoint][WARN] Could not backup host resolv.conf, skipping DNS override" + # File doesn't exist: selective /etc mounts don't include resolv.conf + # Create it from the container's resolv.conf (which has AWF DNS config) + if cp /etc/resolv.conf /host/etc/resolv.conf 2>/dev/null; then + RESOLV_CREATED=true + echo "[entrypoint] DNS configuration created in chroot (/host/etc/resolv.conf)" + else + echo "[entrypoint][WARN] Could not create DNS configuration in chroot" + fi fi # Determine working directory inside the chroot @@ -291,6 +304,10 @@ AWFEOF CHROOT_RESOLV_BACKUP="${RESOLV_BACKUP#/host}" CLEANUP_CMD="${CLEANUP_CMD}; mv '${CHROOT_RESOLV_BACKUP}' /etc/resolv.conf 2>/dev/null || true" echo "[entrypoint] DNS configuration will be restored on exit" + elif [ "$RESOLV_CREATED" = "true" ]; then + # File was created by us; remove it on exit to leave no trace + CLEANUP_CMD="${CLEANUP_CMD}; rm -f /etc/resolv.conf 2>/dev/null || true" + echo "[entrypoint] DNS configuration will be removed on exit" fi exec chroot /host /bin/bash -c " From 6972b0c87e3b1f04a6d018db4eb144df0dece1d0 Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Fri, 6 Feb 2026 02:01:07 +0000 Subject: [PATCH 2/2] fix: use curl -f in chroot HTTP blocking test The test used curl -s which silently receives Squid's 403 error page (a valid HTTP response, exit 0). Use curl -f instead, which returns non-zero for HTTP 4xx/5xx responses. This matches the pattern used in the non-chroot integration tests (protocol-support.test.ts). Previously this test only passed because DNS was broken in chroot mode, causing curl to fail at DNS resolution rather than actually testing HTTP blocking behavior. Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/integration/chroot-edge-cases.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/chroot-edge-cases.test.ts b/tests/integration/chroot-edge-cases.test.ts index 821c9814..b75dba11 100644 --- a/tests/integration/chroot-edge-cases.test.ts +++ b/tests/integration/chroot-edge-cases.test.ts @@ -272,7 +272,7 @@ describe('Chroot Edge Cases', () => { }, 60000); test('should block HTTP to non-whitelisted domains', async () => { - const result = await runner.runWithSudo('curl -s --connect-timeout 5 http://example.com 2>&1', { + const result = await runner.runWithSudo('curl -f --connect-timeout 5 http://example.com 2>&1', { allowDomains: ['github.com'], logLevel: 'debug', timeout: 30000,