Skip to content

allow linux/amd64 images#105

Open
erikswedberg wants to merge 2 commits into
banksean:mainfrom
erikswedberg:boxer-auto-platform
Open

allow linux/amd64 images#105
erikswedberg wants to merge 2 commits into
banksean:mainfrom
erikswedberg:boxer-auto-platform

Conversation

@erikswedberg

Copy link
Copy Markdown
Contributor

container build --platform linux/amd64 ...

when you try to sand new this image you see the error

error is: sand: error: failed to create container for sandbox 8effcd05-18ca-4aa9-b12d-0cb76eda4fad: exit status 1: Error: platform linux/arm64

this PR detects the architecture of your image and passes it through / doesn't error. it doesn't add a --platform switch (or --arch or --os) to sand new

erikswedberg and others added 2 commits June 3, 2026 22:22
* Add --host-port to expose host loopback services into sandboxes

Apple's container CLI puts each sandbox on a vmnet bridge with its own
IP. Services bound to 127.0.0.1 on the host (like the Figma desktop
app's MCP server at 127.0.0.1:3845) are therefore unreachable from
inside a sandbox.

This adds a repeatable --host-port flag to 'sand new' (and the
oneshot/exec creation paths). For each requested port:

  * The daemon spawns an in-process TCP forwarder bound to the sandbox's
    bridge gateway IP, forwarding to 127.0.0.1:<port> on the host. The
    listener is scoped to the bridge interface (not 0.0.0.0).
  * An iptables DNAT + MASQUERADE rule is installed inside the sandbox
    so 127.0.0.1:<port> is rewritten to <gateway>:<port>, with
    route_localnet=1 to allow the kernel to route the redirected
    loopback packet. The agent sees the service at the same loopback
    address it would use on the host -- no client reconfiguration.

Lifecycle: forwarders and rules are set up by a start hook and torn
down on StopContainer / SoftDelete / daemon Close.

  * new package internal/hostport: Forwarder + Manager
  * new migration 000010_host_ports + sqlc regen
  * proto: CreateSandboxRequest.host_ports (field 16)
  * doc/HOST_SERVICES.md

Co-authored-by: Shelley <shelley@exe.dev>

* Run host-port iptables setup as root via Exec User=0

The container hook abstraction execs as the container's default user,
which by the time post-bootstrap hooks run is usually the non-root
agent user. iptables (and route_localnet sysctl) need CAP_NET_ADMIN /
root, so the hook was failing with:

  iptables: Could not fetch rule set generation id: Permission denied
  (you must be root)

Switch to calling ContainerService.Exec directly with User="0" so
the script always runs as uid 0 inside the sandbox.

Co-authored-by: Shelley <shelley@exe.dev>

* Run host-port setup via doas; add host.sand fallback

Recent sand changes mean the container's default user is no longer
root, so ExecContainer.User=0 alone wasn't enough. The base image
configures 'permit nopass :wheel' for doas and adds the sandbox user
to wheel, so switch to 'doas sh -c ...' for both the iptables setup
and the /etc/hosts edit.

Also make the iptables step best-effort: Apple's container runtime
typically does not grant CAP_NET_ADMIN, so DNAT will fail anyway.
When it does, fall back to a 'host.sand' /etc/hosts entry pointing
at the bridge gateway IP. Agents can then reach the host service at
http://host.sand:<port>/ instead of http://127.0.0.1:<port>/.

Co-authored-by: Shelley <shelley@exe.dev>

* Make host-port forwarder HTTP Host-aware; clean up UX

The proxy now sniffs the first bytes of each connection; if they look
like an HTTP/1.x request and a rewrite target is configured (always
the case when started via the Manager), it parses each request,
rewrites the Host header to 127.0.0.1:<port>, and re-serializes it
upstream. Non-HTTP traffic falls back to a plain TCP pipe. WebSocket
and other Upgrade requests have their initial Host header rewritten
and then switch to raw passthrough.

This means a sandbox client can use http://host.sand:<port>/ with no
custom headers; servers like Figma's MCP that validate Host are happy.

Also: * Demote the expected iptables/CAP_NET_ADMIN failure from a warning
    to an info log; print a single positive '[sand] host services
    exposed at...' line on start.
  * Rewrite doc/HOST_SERVICES.md to lead with host.sand:<port> as the
    user-facing entry point and document the HTTP Host rewrite.
Co-authored-by: Shelley <shelley@exe.dev>

---------

Co-authored-by: Erik Swedberg <erik@swed.org>
Co-authored-by: Shelley <shelley@exe.dev>
The Apple 'container' CLI defaults to --arch arm64. Creating a sandbox
from an image that only ships linux/amd64 variants (e.g. the android
sandbox image built with --platform linux/amd64 on an arm64 host) failed
with 'Error: platform linux/arm64'.

Inspect the image manifest at create time; if no variant matches the
host arch, pass --platform <os>/<arch> from the first available variant
so 'container create' selects a real variant instead of the arm64
default.

Co-authored-by: Shelley <shelley@exe.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant