Files
nanoclaw/.claude/skills/convert-to-apple-container/modify/src/container-runner.ts.intent.md
Gabi Simons 13ce4aaf67 feat: enhance container environment isolation via credential proxy (#798)
* feat: implement credential proxy for enhanced container environment isolation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review — bind proxy to loopback, scope OAuth injection, add tests

- Bind credential proxy to 127.0.0.1 instead of 0.0.0.0 (security)
- OAuth mode: only inject Authorization on token exchange endpoint
- Add 5 integration tests for credential-proxy.ts
- Remove dangling comment
- Extract host gateway into container-runtime.ts abstraction
- Update Apple Container skill for credential proxy compatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: scope OAuth token injection by header presence instead of path

Path-based matching missed auth probe requests the CLI sends before
the token exchange. Now the proxy replaces Authorization only when
the container actually sends one, leaving x-api-key-only requests
(post-exchange) untouched.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: bind credential proxy to docker0 bridge IP on Linux

On bare-metal Linux Docker, containers reach the host via the bridge IP
(e.g. 172.17.0.1), not loopback. Detect the docker0 interface address
via os.networkInterfaces() and bind there instead of 0.0.0.0, so the
proxy is reachable by containers but not exposed to the LAN.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: bind credential proxy to loopback on WSL

WSL uses Docker Desktop with the same VM routing as macOS, so
127.0.0.1 is correct and secure. Without this, the fallback to
0.0.0.0 was triggered because WSL has no docker0 interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: detect WSL via /proc instead of env var

WSL_DISTRO_NAME isn't set under systemd. Use
/proc/sys/fs/binfmt_misc/WSLInterop which is always present on WSL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 00:27:13 +02:00

2.2 KiB

Intent: src/container-runner.ts modifications

What changed

Updated buildContainerArgs to support Apple Container's .env shadowing mechanism. The function now accepts an isMain parameter and uses it to decide how container user identity is configured.

Why

Apple Container (VirtioFS) only supports directory mounts, not file mounts. The previous approach of mounting /dev/null over .env from the host causes a VZErrorDomain crash. Instead, main-group containers now start as root so the entrypoint can mount --bind /dev/null over .env inside the Linux VM, then drop to the host user via setpriv.

Key sections

buildContainerArgs (signature change)

  • Added: isMain: boolean parameter
  • Main containers: passes RUN_UID/RUN_GID env vars instead of --user, so the container starts as root
  • Non-main containers: unchanged, still uses --user flag

buildVolumeMounts

  • Removed: the /dev/null/workspace/project/.env shadow mount (was in the committed 37228a9 fix)
  • The .env shadowing is now handled inside the container entrypoint instead

runContainerAgent (call site)

  • Changed: buildContainerArgs(mounts, containerName)buildContainerArgs(mounts, containerName, input.isMain)

Invariants

  • All exported interfaces unchanged: ContainerInput, ContainerOutput, runContainerAgent, writeTasksSnapshot, writeGroupsSnapshot, AvailableGroup
  • Non-main containers behave identically (still get --user flag)
  • Mount list for non-main containers is unchanged
  • Credentials injected by host-side credential proxy, never in container env or stdin
  • Output parsing (streaming + legacy) unchanged

Must-keep

  • The isMain parameter on buildContainerArgs (consumed by runContainerAgent)
  • The RUN_UID/RUN_GID env vars for main containers (consumed by entrypoint.sh)
  • The --user flag for non-main containers (file permission compatibility)
  • CONTAINER_HOST_GATEWAY and hostGatewayArgs() imports from container-runtime.js
  • detectAuthMode() import from credential-proxy.js
  • CREDENTIAL_PROXY_PORT import from config.js
  • Credential proxy env vars: ANTHROPIC_BASE_URL, ANTHROPIC_API_KEY/CLAUDE_CODE_OAUTH_TOKEN