opencode-sandbox: OpenCode 2 in a sandbox for any project
Runs OpenCode 2 with full permissions while containing its mistakes: - egress filter: squid in a container per project; squid.conf is rendered from layered egress.conf files (package, user, project, local) with allow/block/connect rules and expect-pass/expect-block self-tests - netlock: nftables rejects direct egress for the opencode-sandbox group (installed once with sudo as a systemd unit) - bubblewrap: read-only host, writable project, worktrees and state; credentials hidden; ssh keys via the host's ssh-agent; session bus replaced by an xdg-dbus-proxy limited to notifications; no permission prompts (sudo and systemd-run denied); refuses to run unsandboxed - per-project state in ~/.local/share/opencode-sandbox/<name> - worktrees: `wt add|rm|list` with project hooks - skills mounted per project; the opencode-sandbox skill explains the environment to the agent - plugins as submodules: context-panel, skill-compact-resurrect; global config adds opencode-notifier and cc-safety-net - README in English and Russian
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
---
|
||||
name: opencode-sandbox
|
||||
description: "How the opencode-sandbox environment works: what is writable, how network access is filtered (proxy, 403, connect rules, git over SSH), hidden credentials, Docker, worktrees (opencode-sandbox wt add/rm). Use when a command fails with 'Read-only file system', 'Permission denied', a proxy 403 or a connection error, before touching git remotes, Docker or files outside the project, and before creating or removing a worktree (worktrees are only for changing code on a new branch — not for questions, search, analysis or review)."
|
||||
---
|
||||
|
||||
# Working inside opencode-sandbox
|
||||
|
||||
The project directory is `$OCSB_PROJECT`. `$OCSB_IN_SANDBOX` is `1` when the filesystem
|
||||
sandbox is on.
|
||||
|
||||
## Files
|
||||
|
||||
| Path | Access |
|
||||
|---|---|
|
||||
| The project, its worktrees directory, paths from `OCSB_RW` in `.opencode-sandbox/sandbox.conf` | read-write, real disk |
|
||||
| Toolchain caches in `~` (`.cache`, `.npm`, `.asdf`, `.bundle`, `.gem`, …) | read-write |
|
||||
| `/tmp` | read-write, shared with the host |
|
||||
| Everything else | read-only |
|
||||
| Private SSH keys, `~/.gnupg`, cloud CLI credentials, `~/.kube/config`, browser profiles, other agents' configs, `OCSB_HIDE` paths | hidden (empty) |
|
||||
|
||||
- `Read-only file system` / `EROFS` means the path is outside the writable set. Do not retry,
|
||||
do not look for another way to write there. If the task really needs it, tell the user
|
||||
which path and why — they can add it to `OCSB_RW`.
|
||||
- A hidden credential is not a bug either; ask the user instead of searching for it.
|
||||
|
||||
## Network
|
||||
|
||||
- All HTTP(S) goes through the egress proxy (`HTTPS_PROXY`). Direct connections (ping, raw
|
||||
TCP, IP literals, SSH without the proxy) are rejected by the kernel.
|
||||
- A `403` from the proxy, or `CONNECT tunnel failed, response 403`, is policy. Tell the user
|
||||
the exact host (and port) you need and why. Rules live in `.opencode-sandbox/egress.conf`
|
||||
(`allow`, `block`, `connect host:port`); do not edit them yourself unless asked.
|
||||
- Private networks, names without a dot and ports other than 80/443 are blocked unless the
|
||||
project allows them with `connect`.
|
||||
- git over SSH works through the proxy (`GIT_SSH_COMMAND` is set) when the host and port are
|
||||
allowed with `connect`; the key is in the host's ssh-agent, not on disk.
|
||||
- Containers get the proxy through `DOCKER_CONFIG` (builds and `docker run`).
|
||||
|
||||
## Things you cannot do
|
||||
|
||||
- Open a browser (`xdg-open` is disabled): print the link for the user.
|
||||
- `sudo`, `systemd-run`: denied.
|
||||
- Start processes outside the sandbox through the session bus: only desktop notifications
|
||||
are reachable.
|
||||
|
||||
## Docker
|
||||
|
||||
The Docker socket is available, so Docker can see the whole host. Mount only paths inside
|
||||
the project or its worktrees; never mount `/`, `~` or system directories.
|
||||
|
||||
## Worktrees
|
||||
|
||||
A worktree is for **changing code on a new branch** — and only that. Do not create one for
|
||||
questions, search, reading code, analysis, review or planning: work in the current tree
|
||||
read-only. Do not create one "just in case" before you know changes are needed, and do not
|
||||
create a second one if your session already has a worktree for the task.
|
||||
|
||||
When you do change code: one session — one worktree. Create and remove them with the
|
||||
package's command; the project's hooks start and stop its stack:
|
||||
|
||||
```shell
|
||||
opencode-sandbox wt add feature-PROJ-42-login --seed # extra args go to the project hook
|
||||
opencode-sandbox wt rm 42 # refuses if there are uncommitted changes
|
||||
opencode-sandbox wt rm 42 --force # discards them
|
||||
opencode-sandbox wt list
|
||||
```
|
||||
|
||||
Worktrees live in the worktrees directory next to the project (writable). Remove yours
|
||||
after the merge, and right away if it turned out no changes were needed; `wt list` shows
|
||||
leftovers.
|
||||
Reference in New Issue
Block a user