Private /tmp, no display, git over SSH and netlock check fixes

- /tmp: the agent gets its own (<state>/tmp, files older than 7 days are
  removed on start) — the host's /tmp holds sockets that lead out of the
  sandbox (tmux, X11, browsers' singleton sockets, other tools).
  OCSB_TMP=shared keeps the old behaviour. /tmp is mounted before the
  project and state binds so they stay visible if they live under /tmp
- DISPLAY, WAYLAND_DISPLAY, XAUTHORITY are empty in the sandbox and
  ~/.Xauthority is hidden; browsers must run headless
- GIT_SSH_COMMAND uses -F ~/.ssh/config: in the user namespace root-owned
  system ssh configs look owned by nobody and ssh refuses them
- netlock self-test checks that the proxy opens the tunnel, not that a
  remote site answers; failed self-tests now say so instead of exiting
  silently
- doctor: no false error for opencode outside a project
- skill and READMEs: worktrees only for code changes, private /tmp,
  headless browsers, troubleshooting entries
This commit is contained in:
2026-10-30 01:09:53 -07:00
parent 5193dbe573
commit 6dec88641a
5 changed files with 48 additions and 14 deletions
+12 -4
View File
@@ -124,6 +124,7 @@ files are read, so you can use it in values. Relative paths are relative to the
| `OCSB_PLUGINS` | skill-compact-resurrect | plugin files from `plugins/` (or absolute paths) |
| `OCSB_PANEL` | `1` | "Tokens" panel in the web UI |
| `OCSB_NOTIFICATIONS` | `1` | desktop notifications through a filtered D-Bus proxy |
| `OCSB_TMP` | `private` | `private`: the agent's own `/tmp` in the state directory; `shared`: the host's `/tmp` |
| `OCSB_SANDBOX` | `1` | `0` = filter and netlock only, no bubblewrap |
| `OCSB_WORKTREES_DIR` | `../<project>-worktrees` | where worktrees go |
| `OCSB_WT_PREFIX` | — | worktree directory = `<prefix><slug>` |
@@ -226,7 +227,11 @@ browser → :4196 (context panel inside OpenCode) → :4197
Inside the sandbox:
- **Writable:** the project, the worktrees directory, the state directory, `OCSB_RW`,
`OCSB_RW_HOME`, `/tmp`. Everything else is read-only.
`OCSB_RW_HOME` and a private `/tmp`. Everything else is read-only.
- **Private `/tmp`:** the host's `/tmp` holds sockets that lead out of a sandbox (tmux, X11,
browsers' singleton sockets, other tools), so the agent gets its own, stored in
`<state>/tmp` (files older than 7 days are removed on start). Look there for its screenshots
and logs. Docker mounts of `/tmp` paths would point at the host's `/tmp` — mount project paths.
- **Hidden:** `OCSB_HIDE_HOME`, `OCSB_HIDE`, private keys in `~/.ssh` (`config`, `known_hosts`
and `*.pub` stay visible; the host's ssh-agent signs).
- **Network:** `HTTP(S)_PROXY` point to the filter. `GIT_SSH_COMMAND` sends ssh through it with
@@ -238,8 +243,9 @@ Inside the sandbox:
- **Session bus:** replaced by `xdg-dbus-proxy` that talks only to
`org.freedesktop.Notifications`; the real bus would let the agent start processes outside
the sandbox with `systemd-run --user`.
- **Browser:** `xdg-open` is disabled for the agent; the UI is opened by `run` from your
normal session.
- **No display:** `DISPLAY`, `WAYLAND_DISPLAY` and `XAUTHORITY` are empty and the X cookie is
hidden, so GUI programs cannot reach your desktop; run browsers (Playwright MCP, Chrome)
headless. `xdg-open` is disabled; the UI is opened by `run` from your normal session.
- **No silent fallback:** with `OCSB_SANDBOX=1` and no working bubblewrap, `run` refuses to
start.
@@ -260,7 +266,7 @@ place, requests to production — not to hold a determined attacker.
- **Allowed hosts are a channel.** Data can leave through any host the rules allow.
- **The project is writable.** Mistakes inside it are real; cc-safety-net blocks the common
destructive commands, git keeps history — commit often.
- `/tmp` is shared with the host.
- With `OCSB_TMP=shared` the host's `/tmp` and its sockets are reachable.
## Troubleshooting
@@ -275,6 +281,8 @@ place, requests to production — not to hold a determined attacker.
| `bubblewrap cannot create a sandbox` | unprivileged user namespaces are disabled (`kernel.unprivileged_userns_clone`, AppArmor userns restrictions) |
| no "Tokens" panel | open port 4196, not 4197; see `<state>/data/opencode/log/context-panel.log` |
| no notifications | install `xdg-dbus-proxy` |
| browser tools fail (`Missing X server`, `Failed to connect to Wayland display`) | no display in the sandbox: run the browser headless (Playwright MCP: `--headless`) |
| can't find a file the agent put in `/tmp` | it is in `~/.local/share/opencode-sandbox/<name>/tmp` |
| `docker build` fails pulling images | the proxy reaches registries through squid: check `egress logs` |
## Uninstall