- read-only in the sandbox: .opencode-sandbox/, .cc-safety-net/, .git/hooks, .git/config, an in-project core.hooksPath, the egress rules and the safety-net home; .git is pinned by a bind onto itself so it cannot be swapped - only trusted projects are loaded (init / trust): a .opencode-sandbox/ in a worktree or a subdirectory is no longer sourced on the host - run (before and after the session) and doctor report planted .git entries, redirected worktrees and per-worktree overrides - hide Firefox, Claude, VS Code, Cursor and Codex configs
26 KiB
opencode-sandbox
English · Русский
Дайте OpenCode 2 работать над проектом с полными правами — без вопросов «разрешить этот путь?», — а его ошибки пусть остаются внутри песочницы.
cd my-project
opencode-sandbox init # один раз на проект
opencode-sandbox run # фильтр → netlock → самопроверки → веб-интерфейс OpenCode
Что это даёт
| Изоляция файлов | bubblewrap: агент пишет только в проект, его worktree и разрешённые вами пути. Остальная система — только чтение; SSH-ключи, облачные учётки, ~/.kube/config, профили браузеров и конфиги других агентов скрыты |
| Сетевой фильтр | весь HTTP(S) идёт через squid с правилами проекта; прод и внутренние сети недоступны, пока вы их не разрешите |
| Netlock | nftables на уровне ядра отклоняет всё, что идёт в обход фильтра: прямой TCP, IP-адреса, ping, обычный SSH |
| Без подтверждений | внутри песочницы агенту разрешено всё, кроме sudo и systemd-run |
| Worktree | одна сессия — одно дерево; создаются и удаляются командой opencode-sandbox wt, с хуками проекта (порты, .env, запуск стека) |
| Дополнительно | панель «Токены» в веб-интерфейсе (состав контекста, расход, скорость модели), скилы после compaction возвращаются, cc-safety-net против разрушительных git/rm, уведомления на рабочий стол |
Только Linux: bubblewrap, nftables, systemd, Docker.
Содержание
- Требования · Установка · Быстрый старт
- Файлы проекта · Настройки · Сетевые правила
- Worktree · Скилы и плагины
- Как это устроено · Модель безопасности и ограничения
- Решение проблем · Удаление · Команды
Требования
- Linux с непривилегированными user namespaces (bubblewrap должен работать от обычного пользователя)
docker,bwrap(bubblewrap),sg(shadow-utils),curl,jq,ncat(nmap-ncat),gitsudoодин раз — для установки netlock- OpenCode 2:
npm i -g @opencode/cliили локальная установка, путь — вOCSB_OPENCODE_BIN - по желанию:
xdg-dbus-proxy— уведомления из песочницы
Установка
git clone --recursive https://git.neotokai.ru/public/opencode-sandbox.git ~/opencode-sandbox
cd ~/opencode-sandbox
make install # ссылка opencode-sandbox в ~/.local/bin, плагины
opencode-sandbox doctor # проверка зависимостей и настроек хоста
Первый run ставит netlock через sudo (или вручную: opencode-sandbox netlock setup).
Вас добавят в группу opencode-sandbox; перелогиниваться не нужно.
Обновление: git pull && make plugins.
Быстрый старт
cd my-project
opencode-sandbox init # создаст .opencode-sandbox/ и .cc-safety-net/policy.json
$EDITOR .opencode-sandbox/egress.conf # разрешите хосты, которые нужны проекту
ssh-add # только если агенту нужен git по SSH
opencode-sandbox run
run поднимает фильтр, проверяет netlock, прогоняет самопроверки и запускает OpenCode.
Браузер откроется на http://127.0.0.1:4196/: логин opencode, пароль — в
~/.local/share/opencode-sandbox/<проект>/password (выводится при первом запуске).
Закоммитьте .opencode-sandbox/ (кроме local/) и .cc-safety-net/ — каждый, кто
склонирует проект, получит ту же песочницу. sandbox.conf и хуки — это bash, который
выполняется на вашем хосте, поэтому загружаются только доверенные проекты: init доверяет
созданному проекту, а в клоне прочитайте .opencode-sandbox/ и выполните
opencode-sandbox trust (список — ~/.config/opencode-sandbox/projects).
.opencode-sandbox/ в worktree или подкаталоге игнорируется.
Файлы проекта
my-project/
├── .opencode-sandbox/
│ ├── sandbox.conf настройки (bash) в git
│ ├── egress.conf сетевые правила в git
│ ├── hooks/
│ │ ├── wt-post-add после создания worktree в git
│ │ └── wt-pre-rm перед удалением worktree в git
│ └── local/ личные переопределения, не в git
│ ├── sandbox.conf
│ └── egress.conf
└── .cc-safety-net/policy.json исключения cc-safety-net в git
Состояние проекта лежит вне репозитория, в ~/.local/share/opencode-sandbox/<имя>/:
база сессий OpenCode, кэши, пароль веб-интерфейса, конфиг Docker-клиента, сгенерированный
squid.conf.
Настройки
sandbox.conf — файл bash. Слои, побеждает последний:
- умолчания пакета
~/.config/opencode-sandbox/sandbox.conf— ваши, для всех проектов.opencode-sandbox/sandbox.conf— проекта.opencode-sandbox/local/sandbox.conf— ваши, для этого проектаOCSB_<ИМЯ>=…в окружении — на один запуск (только скаляры)
opencode-sandbox config показывает итоговые значения. Когда файлы читаются,
OCSB_PROJECT_DIR уже задан — его можно использовать в значениях. Относительные пути —
от проекта; ~/ работает.
| Настройка | По умолчанию | Что задаёт |
|---|---|---|
OCSB_NAME |
имя каталога проекта | имя каталога состояния и контейнера фильтра |
OCSB_WEB_PORT |
4196 |
порт веб-интерфейса; сам OpenCode — на следующем |
OCSB_EGRESS_PORT |
3128 |
порт фильтра на 127.0.0.1 и шлюзе docker0 |
OCSB_OPENCODE_BIN |
opencode из PATH |
бинарник OpenCode 2 |
OCSB_ENV_FILE |
— | файл KEY=VALUE с токенами MCP-серверов и провайдера модели |
OCSB_KUBECONFIG |
— | kubeconfig агента (~/.kube/config остаётся скрытым) |
OCSB_ENV |
() |
дополнительные KEY=VALUE для OpenCode |
OCSB_RW |
() |
дополнительные пути на запись |
OCSB_HIDE |
() |
дополнительные скрытые пути |
OCSB_RW_HOME |
.cache .npm .asdf .bundle .gem … |
каталоги инструментов в ~ на запись (если есть) |
OCSB_HIDE_HOME |
.gnupg .aws .kube/config .claude … |
скрытые пути в ~ |
OCSB_SKILLS |
(opencode-sandbox) |
скилы, которые монтируются агенту |
OCSB_SKILL_DIRS |
() |
дополнительные каталоги со скилами |
OCSB_PLUGINS |
skill-compact-resurrect | файлы плагинов из plugins/ (или абсолютные пути) |
OCSB_PANEL |
1 |
панель «Токены» в веб-интерфейсе |
OCSB_NOTIFICATIONS |
1 |
уведомления через фильтрующий прокси D-Bus |
OCSB_DISPLAY |
0 |
1 — окна агента (например, браузер Playwright) на вашем экране через сокет Wayland |
OCSB_TMP |
private |
private — свой /tmp агента в каталоге состояния; shared — /tmp хоста |
OCSB_SANDBOX |
1 |
0 — только фильтр и netlock, без bubblewrap |
OCSB_WORKTREES_DIR |
../<проект>-worktrees |
куда класть worktree |
OCSB_WT_PREFIX |
— | каталог дерева = <префикс><slug> |
OCSB_WT_BASE |
текущий HEAD |
от какой ветки создаются деревья |
OCSB_WT_SLUG_REGEX |
— | регулярка с одной группой: slug из имени ветки |
OCSB_OPENCODE_CONFIG |
~/.config/opencode-sandbox/opencode.jsonc или пакета |
глобальный конфиг OpenCode |
OCSB_STATE_DIR |
~/.local/share/opencode-sandbox/<имя> |
каталог состояния |
OCSB_NETLOCK_GROUP |
opencode-sandbox |
группа netlock |
OCSB_DOCKER_GW |
адрес docker0 | где контейнеры видят фильтр |
Пример — проект с внутренними сервисами, файлом токенов и worktree:
OCSB_NAME=shop
OCSB_WEB_PORT=4296 # разные порты — несколько проектов одновременно
OCSB_EGRESS_PORT=3138
OCSB_ENV_FILE=~/.config/shop/agent.env
OCSB_HIDE=(../shop-secrets)
OCSB_ENV=("SHOP_ENV=dev")
OCSB_WT_PREFIX=shop-wt-
OCSB_WT_BASE=main
OCSB_WT_SLUG_REGEX='SHOP-([0-9]+)'
Сетевые правила
Политика — чёрный список: что не запрещено, то разрешено. Всегда запрещены, если не разрешены явно: внутренние сети (10/8, 172.16/12, 192.168/16, 100.64/10, link-local, loopback), имена без точки, порты кроме 80 и 443.
allow jira.example.com gitlab.example.com # побеждает block
allow-regex ^[a-z0-9-]+\.staging\.example\.com$
block .example.com # домен и все поддомены
block-regex ^prod-
connect git.example.com:2222 10.0.0.5:6443 # туннели: git по SSH, API Kubernetes
expect-block https://prod.example.com/ # самопроверки для `run` и `egress verify`
expect-pass https://gitlab.example.com/
expect-pass https://10.0.0.5:6443/version -k # опции curl — после URL
Порядок проверки: connect → порты кроме 80/443 запрещены → allow → block → имена без
точки и внутренние сети запрещены → остальное разрешено.
Слои (правила складываются): egress/defaults.conf →
~/.config/opencode-sandbox/egress.conf → .opencode-sandbox/egress.conf →
.opencode-sandbox/local/egress.conf.
Куда класть хосты компании. В egress.conf проекта: он лежит в репозитории компании,
и новый коллега получает рабочие правила вместе с git clone. То, что нельзя коммитить, —
в local/egress.conf. В самом пакете хостов компаний нет.
Изменения применяются при следующем run или сразу командой opencode-sandbox egress up
(перечитывает правила без перезапуска squid). egress render показывает сгенерированный
squid.conf, egress logs — каждый запрос и отказ в реальном времени.
Worktree
opencode-sandbox wt add feature-SHOP-42-cart --seed # аргументы после ветки — хуку
opencode-sandbox wt rm 42 # откажет, если есть незакоммиченное
opencode-sandbox wt rm 42 --force # выбросит незакоммиченное
opencode-sandbox wt list
wt add создаёт <OCSB_WORKTREES_DIR>/<OCSB_WT_PREFIX><slug> в новой ветке от
OCSB_WT_BASE и запускает в нём hooks/wt-post-add. wt rm запускает hooks/wt-pre-rm,
проверяет незакоммиченные изменения и удаляет дерево (ветка остаётся). Хуки получают
WT_DIR, WT_BRANCH, WT_SLUG, MAIN_ROOT и дополнительные аргументы; ошибка хука
прерывает команду. Шаблоны — hooks/*.example после init.
Агенту сказано создавать worktree только для изменений кода в новой ветке — не для вопросов, поиска и ревью.
Скилы и плагины
- Скилы.
OCSB_SKILLS— каталоги скилов (сSKILL.md), которые монтируются агенту только на чтение как глобальные: из skills/ или вашихOCSB_SKILL_DIRS. Скиллopencode-sandboxобъясняет агенту среду: что доступно на запись, что значит 403 от прокси, как попросить хост, как работать с worktree. - Плагины пакета — git submodules в plugins/: context-panel (панель «Токены») и skill-compact-resurrect (скилы переживают compaction).
- Глобальный конфиг OpenCode opencode/opencode.jsonc
добавляет opencode-notifier и cc-safety-net. Замените его своим
~/.config/opencode-sandbox/opencode.jsonc. Собственныйopencode.jsoncпроекта (модель, MCP-серверы, плагины проекта) работает как обычно.
Как это устроено
opencode-sandbox run
├─ docker: opencode-sandbox-egress-<имя> squid, сеть хоста, 127.0.0.1 + docker0
├─ xdg-dbus-proxy сессионная шина — только уведомления
└─ sg opencode-sandbox netlock: группе доступны только loopback и DNS
└─ bwrap / только чтение; проект, worktree, состояние — запись
└─ opencode serve :4197 прокси в окружении, свои XDG, права = allow
браузер → :4196 (панель внутри OpenCode) → :4197
Внутри песочницы:
- На запись: проект, каталог worktree, каталог состояния,
OCSB_RW,OCSB_RW_HOMEи собственный/tmp. Всё остальное — только чтение. - Свой
/tmp: в/tmpхоста лежат сокеты, через которые можно выйти из песочницы (tmux, X11, сокеты браузеров, других программ), поэтому у агента свой/tmp— в<состояние>/tmp(файлы старше 7 дней удаляются при запуске). Скриншоты и логи агента ищите там. Docker смонтирует путь из/tmpиз/tmpхоста — монтируйте пути проекта. - Только чтение внутри проекта: то, что хост выполняет вне песочницы, —
.opencode-sandbox/,.cc-safety-net/,.git/hooks,.git/config(core.fsmonitorоттуда срабатывает при любомgit status, хватит prompt'а оболочки),core.hooksPath, если он внутри проекта, — а также правила egress и домашний каталог safety-net в каталоге состояния. Сам.git— точка монтирования, его нельзя переименовать и подменить. git работает; не проходит только записьgit config(например,push -uне запишет upstream). После каждой сессииrunсообщает о других.gitв проекте и worktree, о worktree, чей.gitуказывает в другое место, и о переопределениях для отдельных worktree;doctorпроверяет то же. - Скрыто:
OCSB_HIDE_HOME,OCSB_HIDE, приватные ключи в~/.ssh(config,known_hostsи*.pubвидны; подписывает ssh-agent хоста). - Сеть:
HTTP(S)_PROXYуказывают на фильтр.GIT_SSH_COMMANDпускает ssh через него с-F ~/.ssh/config(внутри user namespace системные конфиги ssh, принадлежащие root, выглядят как принадлежащиеnobody, и ssh их отвергает).DOCKER_CONFIGпередаёт прокси сборкам и контейнерам. - OpenCode: свои каталоги
XDG_*в каталоге состояния (ваш~/.config/opencodeне используется); права — черезOPENCODE_CONFIG_CONTENT: разрешено всё,sudoиsystemd-runзапрещены. - Сессионная шина: заменена на
xdg-dbus-proxy, который пропускает толькоorg.freedesktop.Notifications; настоящая шина позволила бы агенту запускать процессы вне песочницы черезsystemd-run --user. - Экран: по умолчанию нет —
DISPLAY,WAYLAND_DISPLAYиXAUTHORITYпустые, cookie X скрыт; браузеры — headless. СOCSB_DISPLAY=1агент получает только сокет Wayland (и/dev/driдля видеокарты): его окна появляются на вашем экране, но, в отличие от X11, клиент Wayland не может читать чужие окна и подделывать в них ввод. X11 не пробрасывается никогда.xdg-openотключён; интерфейс открываетrunиз вашей обычной сессии. - Без тихого отката: при
OCSB_SANDBOX=1и неработающем bubblewraprunне запустится.
Netlock (netlock setup, sudo) создаёт группу opencode-sandbox, добавляет в неё вас и
ставит opencode-sandbox-netlock.service: таблица nftables разрешает сокетам этой группы
только 127.0.0.0/8, ::1 и DNS-серверы из resolv.conf, остальное отклоняет. OpenCode
запускается с этой группой — под правило попадают агент и всё, что он запускает.
Модель безопасности и ограничения
Цель — удержать агента, который ошибается (не тот путь, rm -rf не там, запрос в прод), а
не остановить целенаправленного злоумышленника.
- Docker — выход наружу. Агенту доступен сокет Docker, а Docker может смонтировать любой
путь хоста (
docker run -v /:/host). Если это важно — не давайте агенту Docker; закрыть это можно фильтрующим прокси для сокета или rootless Podman. - Общее ядро. bubblewrap — это namespaces, а не виртуальная машина.
- Разрешённые хосты — канал утечки. Данные могут уйти на любой хост, который пропускают правила.
- Проект доступен на запись. Ошибки внутри него настоящие; cc-safety-net блокирует типичные разрушительные команды, git хранит историю — коммитьте чаще.
- Файлы, которые вы запускаете сами. Хуки, конфиги и метаданные git защищены (см. выше),
но код агент правит: изменённый
Makefile, скрипт вpackage.jsonили файл вbin/выполнится с вашими правами, когда вы его запустите. Смотритеgit diff, прежде чем запускать команды проекта на хосте. - Подложенные репозитории обнаруживаются, а не предотвращаются.
.git, созданный агентом в новом каталоге или новом worktree, найдёт проверка после сессии; не запускайте там git, пока не посмотрели. - С
OCSB_TMP=sharedдоступны/tmpхоста и его сокеты. - С
OCSB_DISPLAY=1агент может открывать окна на вашем экране и пользоваться буфером обмена, пока его окно в фокусе.
Решение проблем
| Симптом | Причина и что делать |
|---|---|
Read-only file system |
путь вне разрешённых на запись. Если агенту он правда нужен — добавьте в OCSB_RW |
403 от прокси, CONNECT tunnel failed |
хост не разрешён: добавьте allow (или connect host:port для порта не 443) в egress.conf, выполните opencode-sandbox egress up |
git по SSH: Permission denied (publickey) |
в ssh-agent нет ключей: ssh-add перед run |
git по SSH: 403 |
добавьте connect <хост>:<порт> в egress.conf |
port … is busy |
другой проект или старый экземпляр: задайте другие OCSB_WEB_PORT / OCSB_EGRESS_PORT |
netlock is NOT working |
opencode-sandbox netlock setup, затем netlock verify |
bubblewrap cannot create a sandbox |
отключены непривилегированные user namespaces (kernel.unprivileged_userns_clone, ограничения AppArmor) |
| нет панели «Токены» | открывайте порт 4196, а не 4197; журнал — <состояние>/data/opencode/log/context-panel.log |
| нет уведомлений | установите xdg-dbus-proxy |
браузерные инструменты падают (Missing X server, Failed to connect to Wayland display) |
в песочнице нет экрана: включите OCSB_DISPLAY=1 (сессия Wayland) или запускайте браузер headless (Playwright MCP: --headless) |
не найти файл, который агент положил в /tmp |
он в ~/.local/share/opencode-sandbox/<имя>/tmp |
docker build не скачивает образы |
реестры доступны через squid: смотрите egress logs |
Удаление
opencode-sandbox egress down # в каждом проекте
opencode-sandbox netlock teardown # sudo; группа остаётся: sudo groupdel opencode-sandbox
cd ~/opencode-sandbox && make uninstall
rm -rf ~/.local/share/opencode-sandbox # состояние: сессии, кэши, пароли
docker rmi opencode-sandbox-egress
Команды
opencode-sandbox init добавить .opencode-sandbox/ в текущий репозиторий
opencode-sandbox trust [каталог] доверять существующему .opencode-sandbox/ (клон)
opencode-sandbox config итоговые настройки
opencode-sandbox doctor зависимости и настройки хоста
opencode-sandbox run [аргументы opencode] всё сразу, затем OpenCode
opencode-sandbox prepare фильтр + netlock + самопроверки, без OpenCode
opencode-sandbox egress up|down|status|logs|verify|render
opencode-sandbox netlock setup|teardown|status|verify
opencode-sandbox wt add <ветка> [аргументы] | rm <имя|путь> [--force] | list