Files
nanoclaw/.claude/skills/convert-to-apple-container/modify/src/container-runtime.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.0 KiB

Intent: src/container-runtime.ts modifications

What changed

Replaced Docker runtime with Apple Container runtime. This is a full file replacement — the exported API is identical, only the implementation differs.

Key sections

CONTAINER_RUNTIME_BIN

  • Changed: 'docker''container' (the Apple Container CLI binary)

readonlyMountArgs

  • Changed: Docker -v host:container:ro → Apple Container --mount type=bind,source=...,target=...,readonly

ensureContainerRuntimeRunning

  • Changed: docker infocontainer system status for checking
  • Added: auto-start via container system start when not running (Apple Container supports this; Docker requires manual start)
  • Changed: error message references Apple Container instead of Docker

cleanupOrphans

  • Changed: docker ps --filter name=nanoclaw- --format '{{.Names}}'container ls --format json with JSON parsing
  • Apple Container returns JSON with { status, configuration: { id } } structure

CONTAINER_HOST_GATEWAY

  • Set to '192.168.64.1' — the default gateway for Apple Container VMs to reach the host
  • Docker uses 'host.docker.internal' which is resolved differently

hostGatewayArgs

  • Returns [] — Apple Container provides host networking natively on macOS
  • Docker version returns ['--add-host=host.docker.internal:host-gateway'] on Linux

Invariants

  • All exports remain identical: CONTAINER_RUNTIME_BIN, CONTAINER_HOST_GATEWAY, readonlyMountArgs, stopContainer, hostGatewayArgs, ensureContainerRuntimeRunning, cleanupOrphans
  • stopContainer implementation is unchanged (<bin> stop <name>)
  • Logger usage pattern is unchanged
  • Error handling pattern is unchanged

Must-keep

  • The exported function signatures (consumed by container-runner.ts and index.ts)
  • The error box-drawing output format
  • The orphan cleanup logic (find + stop pattern)
  • CONTAINER_HOST_GATEWAY must match the address the credential proxy is reachable at from within the VM