feat(studio): bundle studio-expose bridge + socat (opt-in STUDIO_EXPOSE)

pi-studio binds the container's 127.0.0.1, which a published Docker port
can't reach. Add a robust, portable bridge rather than a doc-only one-liner:

- Dockerfile.base: add socat (~1 MB, generally useful TCP relay).
- rootfs/usr/local/bin/studio-expose: socat TCP relay listening on the
  container's egress IPv4 (not 0.0.0.0 — that would EADDRINUSE against
  Studio's loopback listener) forwarding to 127.0.0.1:PORT on the SAME
  port, so Studio's printed token URL works verbatim. Robust egress-IP
  detection (hostname -I, loopback-filtered; ip route get fallback),
  --help, port validation, foreground.
- entrypoint-user.sh: opt-in STUDIO_EXPOSE=1 auto-starts the bridge in the
  background (studio variant only). Default OFF — Studio stays loopback-only
  (its secure default) unless explicitly opted in.
- README: 'Using pi-studio' now documents host-networking (A) and the
  studio-expose/STUDIO_EXPOSE bridge (B) with a security note; ssh -L for
  remote, mosh caveat retained.
- smoke-test: assert socat + studio-expose present (base-level).
- CHANGELOG/AGENTS updated.

No tag — stopping for review.
This commit is contained in:
pi
2026-06-10 23:33:44 +02:00
parent a78e59fb5b
commit 7d8ee4cea1
7 changed files with 131 additions and 12 deletions
+2 -1
View File
@@ -120,7 +120,8 @@ deprecated artifacts (to be removed in opencode-devbox v2.0.0).
`pi install /opt/pi-studio` (see Dockerfile.variant `INSTALL_STUDIO`).
The default `:latest` image stays studio-free. Note: pi-studio binds
`127.0.0.1` inside the container, so browser access needs host
networking or a loopback bridge — see README "Using pi-studio".
networking or the bundled `studio-expose` bridge (socat; auto-starts
when `STUDIO_EXPOSE=1`) — see README "Using pi-studio".
- **No Julia/R/GHCi/Clojure runtimes**. Use `uv run --with X` for
Python REPLs; `apt install` other-language runtimes ad-hoc per
container if needed.