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
+6
View File
@@ -32,6 +32,12 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
gate **only** the studio tags, so a studio build/smoke failure can
never block the core `:latest` / `:vX.Y.Z` release.
- `STUDIO_PORT=8765` baked as an advisory default.
- **`studio-expose` helper + `socat` (base).** Because pi-studio binds the
container's loopback, a published Docker port can't reach it. The new
`studio-expose` helper (socat, added to the base) bridges the container's
loopback to its egress interface on the same port; set `STUDIO_EXPOSE=1`
in compose to auto-start it on boot (default off — Studio stays
loopback-only otherwise). `socat` is in the base for all variants.
- **README "Using pi-studio" section.** Documents the container access
reality: pi-studio hard-binds `127.0.0.1` inside the container
(`.listen(port,"127.0.0.1")`, no `--host` flag), so a plain `-p`