
Песочница для агентов ИИ-кодирования. Запускает Copilot CLI, Claude Code, OpenCode, Gemini CLI, Antigravity, Pi, goose или обычную оболочку внутри песочницы на уровне ядра, с защитой git и gh и политикой песочницы, зафиксированной в репозитории.
Песочница с принудительным применением на уровне ядра для ИИ-агентов, пишущих код. cplt оборачивает GitHub Copilot CLI, OpenCode, Gemini CLI, Antigravity CLI, Pi, Claude Code, goose, DeepSeek Harness или любую оболочку, чтобы агент мог писать код, но не мог украсть учётные данные, запушить в main, слить PR или вынести секреты.
sandbox-exec
ИИ-агенты выполняют произвольный код. Скомпрометированный агент — будь то через инъекцию промпта, атаку на цепочку поставок или вредоносный MCP-сервер — может прочитать ~/.ssh, запушить в main, слить PR или вынести ваш код, если только сама ОС не скажет «нет».
cplt даёт вам принудительное применение на уровне ядра с настраиваемой командой политикой:
.cplt.toml, закоммиченная в систему контроля версий, что делает её защищённой от подмены и поддающейся аудитуПодробная документация: Конфигурация · Прокси и фильтрация доменов · Защита команды gh · Защита команды git · Известные последствия · Детали безопасности · Модель безопасности
brew install navikt/tap/cplt # macOS. On Debian or Ubuntu, see apt below cplt --shell-install # make 'copilot' run sandboxed (persistent) # --agent opencode for any other agent cplt doctor # check your environment cplt -- -p "fix the tests" # run Copilot in sandbox
Другие агенты и команды песочницы:```bash
cplt --agent opencode # OpenCode (Copilot subscription)
cplt --agent opencode --pass-env ANTHROPIC_API_KEY # third-party provider
cplt --agent shell # interactive sandboxed shell (no AI)
cplt exec -- npm install # sandbox any command directly
cplt exec -c "npm install && npm test" # compound commands in sandbox
alias npm="cplt exec -- npm" # sandboxed npm for every invocation
cplt init --write
cplt trust accept --all
cplt config set git_guard.protect_default_branch_only false # block every push, not just main cplt config set git_guard.mode warn # observe instead of blocking
## Что блокируется
Песочница блокирует доступ к учётным данным и секретам в ядре. Командные защиты блокируют деструктивные операции. Каждое ограничение применяется к агенту и к каждому процессу, который он порождает.
| Ресурс | Статус | Примечания |
| --- | --- | --- |
| Чтение/запись каталога проекта | ✅ Разрешено | |
| Чтение/запись/удаление `.env*`, `.pem`, `.key` в проекте | 🔒 Заблокировано ядром | Предотвращает эксфильтрацию и уничтожение секретов. `--allow-env-files` отменяет |
| Запись `.git/hooks`, `.git/config`, `.gitmodules` | 🔒 Заблокировано ядром (macOS), ⚠️ частично на Linux | Предотвращает персистентность через git hooks, перенаправление hooksPath, перехват submodule. **Linux:** Landlock не может запретить подпуть внутри разрешённого дерева, поэтому на пути только с Landlock они остаются доступными для записи. `bwrap` перепривязывает `.git/hooks` только для чтения, но намеренно оставляет `.git/config` и `.gitmodules` доступными для записи, поэтому `core.hooksPath` остаётся маршрутом персистентности, см. [Ограничения Linux](https://github.com/navikt/cplt/blob/main/docs/security.md#linux). Применяется к **каждому** корню с правом записи, проекту и каждому гранту `allow.write`, включая предоставленный worktree или bare repo, чьи реальные hooks находятся вне `<root>/.git` |
| Выполнение из `/tmp`, `/var/folders` | 🔒 Заблокировано ядром | Предотвращает write-then-exec. Каталог scratch перенаправляет TMPDIR в безопасное место, включено по умолчанию |
| Запись в разрешаемые через PATH каталоги bin/shim (`~/.bun/bin`, `~/.deno/bin`, `$PNPM_HOME`, mise `shims/` и весь `installs/`) | 🔒 Заблокировано ядром (macOS), ⚠️ mise частично на Linux | Предотвращает подмену бинарника, который ваша следующая *неизолированная* команда разрешает через PATH. По той же причине `~/.cargo/bin` и `~/go/bin` всегда были доступны только для чтения. Ломает `bun install -g`, `deno install`, `pnpm add -g`, `mise install`, `mise upgrade`, `mise use -g` внутри cplt, намеренно, и репозиторий, закрепляющий неустановленный toolchain, больше не загружается автоматически. Локальные для проекта установки не затронуты. **Linux:** два каталога mise работают через read-only overlay `bwrap`; остальные удерживаются нативно. См. [Глобальные установки инструментов](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#global-tool-installs) |
| Выполнение из `~/Library/Caches` | 🔒 Заблокировано ядром по умолчанию | Предотвращает размещение бинарников. Нативные модули Copilot исключены через carve-out. Добавляйте точечные исключения с помощью `--allow-cache-exec <SUBDIR>`, например `ms-playwright` |
| Изменение `.vscode/tasks.json`, `launch.json` | ⚠️ Разрешено, известный риск | Граница доверия IDE. См. [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md) для мер защиты |
| Чтение/запись `~/.copilot` (auth, settings) | ✅ Разрешено | Включает `file-map-executable` для `keytar.node`, `pty.node`, `computer.node` |
| Запись `~/.copilot/pkg` (нативные модули) | 🔒 Заблокировано ядром | Предотвращает персистентность через замену нативных модулей |
| Переменные окружения | 🔒 Санитизированы + усилены | Проходит только безопасный allowlist. Lifecycle-скрипты заблокированы. `--pass-env VAR` возвращает одну обратно |
| Чтение `~/.config/gh/hosts.yml` + `config.yml` | ✅ Разрешено (только чтение) | Только эти два файла. Остальная часть `.config/gh` заблокирована |
| Чтение `~/.config/mise` | ✅ Разрешено (только чтение) | Версии инструментов и PATH, без секретов |
| Чтение `~/.gitconfig`, `~/.config/git/config` | ✅ Разрешено (только чтение) | Симлинк dotfiles отслеживается до цели, поэтому stowed `~/.gitconfig` работает |
| Чтение `~/.git-credentials` | 🔒 Заблокировано ядром | `credential.helper = store` хранит здесь токены в открытом виде. Никакой `--allow-read` не открывает его, как и `~/.netrc`. **Linux:** грант на *предка* (сам `$HOME`) всё равно раскрывает его, потому что Landlock не может запретить подпуть внутри разрешённого дерева |
| Чтение глобальных git hooks (`core.hooksPath`) | ✅ Разрешено (только чтение, запись запрещена) | Автоопределяется. Должен находиться под `$HOME` с глубиной ≥3. Запись явно заблокирована |
| Подпись commit/tag (`commit.gpgsign`, `tag.gpgsign`) | 🔒 Отключено | Приватные ключи в `~/.ssh` и `~/.gnupg` заблокированы, поэтому подпись отключена через переопределение переменной окружения |
| Чтение `~/Library/Application Support/Microsoft` | ✅ Разрешено (только чтение) | Device ID для телеметрии |
| Доступ к macOS Keychain | ⚠️ Разрешено (чтение+запись) для агентов, которые хранят там auth | Грант не может быть ограничен одним элементом, поэтому он достигает каждой записи keychain, которую агент может разблокировать. Включите `sandbox.keychain_substitute` (ЭКСПЕРИМЕНТАЛЬНО, по умолчанию выключено), чтобы убрать его в запусках, где агент может аутентифицироваться без него — `CLAUDE_CODE_OAUTH_TOKEN` для Claude Code, существующий файл fallback-токена для Antigravity. См. [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md#keychain-access-is-all-or-nothing) |
| Исходящая сеть (порт 443) | ✅ Разрешено | Все остальные порты заблокированы. Добавляйте дополнительные с помощью `--allow-port` |
| Исходящий localhost | 🔒 Заблокировано ядром (macOS), ⚠️ на основе портов на Linux | Предотвращает доступ к локальным сервисам. Входящий всё ещё работает для прокси. **Linux:** правила Landlock — это только номера портов, и они не могут отличить `localhost:443` от `remote:443`, поэтому локальный сервис на разрешённом порту доступен, и нет запрета, специфичного для localhost. Используйте `--with-proxy` для защиты от SSRF, см. [Ограничения Linux](https://github.com/navikt/cplt/blob/main/docs/security.md#linux) |
| SSH agent (unix socket) | 🔒 Заблокировано ядром (macOS), ⚠️ только env на Linux | Предотвращает подпись git-операций или SSH к хостам. **Linux:** unix socket `connect()` не ограничивается, поэтому удержанный `SSH_AUTH_SOCK` — единственный барьер, и агент, который установит его сам, сможет использовать загруженные ключи. `bwrap` скрывает стандартный сокет OpenSSH под `/tmp`, но не gnome-keyring/gcr или systemd agent под `$XDG_RUNTIME_DIR`. См. [Ограничения Linux](https://github.com/navikt/cplt/blob/main/docs/security.md#linux) |
| Инструменты разработчика (`~/.cargo`, `~/.gradle`, `~/.m2`, `~/.sdkman`, `~/.jenv`, `~/.pyenv`, `~/.konan` и т. д.) | ✅ Разрешено (чтение+запись для кэшей) | Только каталоги, существующие на диске. Уточняется во время выполнения тем, что обнаруживает `cplt doctor` |
| Файлы учётных данных реестров (`~/.m2/settings.xml`, `~/.gradle/gradle.properties`, `~/.cargo/credentials`) | 🔒 Заблокировано ядром на macOS. На Linux родительский каталог инструмента остаётся читаемым | Переопределите с помощью `--allow-read`. См. [Приватные реестры](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#private-registries) |
| Чтение `~/.npmrc` | 🔒 Заблокировано ядром (обе платформы) | Переопределите с помощью `--allow-read`. Ломает yarn 1, см. [yarn 1](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#yarn-1-and-unreadable-home-rc-files) |
| Исходный код Go (`~/go/src`) | 🔒 Заблокировано ядром | Только `~/go/bin` и `~/go/pkg` доступны для чтения |
| Чтение `~/.ssh`, `~/.gnupg`, `~/.aws`, `~/.azure` | 🔒 Заблокировано ядром | |
| Чтение `~/.kube`, `~/.docker`, `~/.nais` | 🔒 Заблокировано ядром | |
| Чтение `~/.password-store`, `~/.terraform.d` | 🔒 Заблокировано ядром | |
| Чтение `~/.config/gcloud`, `~/.config/op` | 🔒 Заблокировано ядром | Отдельные файлы можно переопределить с помощью `--allow-read`. См. [Учётные данные облака](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#cloud-credential-directories) |
| Чтение или запись `~/.config/cplt`, `~/.nav-pilot` | 🔒 Заблокировано ядром | Состояние инструмента, которое определяет, что может делать *следующий* запуск. `~/.config/cplt` не переопределяется как целое поддерево; внутри `~/.nav-pilot` именованный путь остаётся доступным для гранта, чтобы можно было прочитать закреплённую полезную нагрузку agentpakke |
| Чтение `~/.netrc`, `~/.pypirc`, `~/.vault-token` | 🔒 Заблокировано ядром | Не переопределяется на обеих платформах. Указание одного из них в `allow.read` — ошибка запуска |
| Чтение `~/.gem/credentials` | 🔒 Заблокировано ядром | Не переопределяется на обеих платформах. Указание одного из них в `allow.read` — ошибка запуска |
| Деструктивные операции `gh` CLI (merge, delete, release) | 🔒 Ограничено командой (включено по умолчанию) | Отключите с помощью `--no-gh-guard`. См. [gh guard](https://github.com/navikt/cplt/blob/main/docs/gh-guard.md) |
| `git push` в ветку по умолчанию | 🔒 Ограничено командой (включено по умолчанию) | Блокирует push в `main`/`master`; push в feature-ветки всё ещё работает. `protect_default_branch_only = false` блокирует каждый push, `git_guard.mode = "warn"` только предупреждает, `--no-git-guard` отключает |
| Наследование дочерними процессами | ✅ Все ограничения применяются к подпроцессам | |
Эта таблица — сводка. Песочница также разрешает доступ к системным файлам (SSL-сертификаты, `/etc/hosts`), временным каталогам (чтение и запись, без exec) и путям системных инструментов (`/usr/bin`, `/opt/homebrew`). Запустите `cplt --print-profile` для полных правил SBPL.
Для полной модели безопасности, анализа угроз и стратегии тестирования читайте [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md).
## Как cplt сравнивается
### Песочница Codex CLI
| Область | cplt | Песочница Codex CLI |
| --- | --- | --- |
| Контроль исходящей сети | CONNECT-прокси со списками разрешённых/заблокированных доменов | Нет фильтрации на уровне доменов |
| Обработка окружения | Allowlist плюс усиленная инъекция env | Более базовая модель сквозной передачи |
| Защита файлов секретов | Deny-паттерны, такие как `.env*`, `.pem`, `.key` внутри репозитория | Преимущественно доступ, ограниченный каталогом |
| Политика репозитория | [`.cplt.toml`](https://github.com/navikt/cplt/blob/main/docs/configuration.md#per-repo-configuration-cplttoml) с явным потоком доверия/одобрения | Нет файла политики на уровне репозитория |
| Поддержка агентов | Copilot, OpenCode, Gemini CLI, Antigravity CLI, Pi, Claude Code, goose, DeepSeek Harness или shell | Только Codex |
cplt не сильнее везде. Codex CLI уже имеет изоляцию пространств имён Linux, и он уже предоставляет явные режимы песочницы, такие как read-only и workspace-write. У cplt пока нет такой матрицы режимов.
### Песочницы на основе Docker
| Область | cplt | Песочница на основе Docker |
| --- | --- | --- |
| Время запуска | Практически мгновенно для обычного использования CLI | Обычно более медленный запуск контейнера |
| Контроль сети | Фильтрация исходящих запросов через прокси | Обычно сетевой доступ по принципу всё или ничего |
| Контроль файлов | Правила по путям и паттернам | Контроль по монтированиям |
| Требования к хосту | Один бинарник | Требуется демон Docker |
| Пригодность для корпоративного ноутбука | Работает там, где Docker недоступен или ограничен | Часто блокируется локальной политикой |
Docker всё ещё даёт более сильную изоляцию в некоторых средах, особенно если вы хотите полностью отдельную файловую систему и пространство имён процессов. cplt обменивает это на более лёгкую настройку и более тесную интеграцию с машиной, на которой вы уже разрабатываете.
### Разрешения режима агента VS Code
Такие инструменты, как режим агента VS Code, полагаются в основном на разрешения UI. cplt применяет свои ограничения в ядре, поэтому агент не может обойти их с помощью промпта или изменённой инструкции. Это особенно важно для CLI-агентов и раскрытия учётных данных:
- cplt работает вне IDE
- переменные окружения фильтруются до запуска агента
- чувствительные файлы можно блокировать, даже когда они находятся внутри репозитория
- те же ограничения применяются к дочерним процессам
### Песочница Claude Code (Anthropic Sandbox Runtime)
[Anthropic Sandbox Runtime](https://github.com/anthropic-experimental/sandbox-runtime) (`srt`) — это слой песочницы, используемый Claude Code. Тот же высокоуровневый подход, что и у cplt, macOS Seatbelt плюс принудительное применение на уровне ядра Linux плюс HTTP-прокси, но другая реализация.
| Область | cplt | Anthropic srt |
| --- | --- | --- |
| Язык / поставка | Один бинарник на Rust | Node.js + npm-пакет + внешние зависимости |
| Бэкенд Linux | Landlock LSM (без зависимостей, без пространств имён) | bubblewrap (контейнер через пользовательские пространства имён) |
| Фильтрация окружения | Строгий allowlist + deny по суффиксу (`_TOKEN`, `_SECRET`) | Наследует полное родительское окружение (секреты проходят) |
| Защита каталогов учётных данных | 15+ каталогов запрещены по умолчанию | Пользователь должен настроить вручную |
| Защита от DNS rebinding | ✅ IP после DNS проверяется на соответствие приватным диапазонам | ❌ Не реализовано |
| Сетевой прокси | HTTP CONNECT + allow/block доменов | HTTP + SOCKS5 + экспериментальный TLS MITM |
| SSH git | Заблокировано в ядре на macOS (сокет агента запрещён); на Linux удерживается только `SSH_AUTH_SOCK` | Проксируется через SOCKS5 |
| Скрипты менеджеров пакетов | Заблокированы по умолчанию (`npm_config_ignore_scripts`) | Не заблокированы |
| Поддержка агентов | Copilot, OpenCode, Gemini, Antigravity, Pi, Claude Code, goose, DSH, Shell | Claude Code |
| Конфигурация | TOML (глобальная + на репозиторий) | JSON (только глобальная) + живые обновления `--control-fd` |
| Библиотечный API | ❌ Только бинарник | ✅ Встраиваемая библиотека TypeScript |
cplt безопаснее из коробки: фильтрация окружения, защита учётных данных, проверки DNS rebinding, блокировка lifecycle-скриптов. srt гибче: SOCKS5, TLS-инспекция, обратные вызовы на запрос, встраивание библиотеки. Выбор бэкенда Linux имеет значение. bwrap требует обходных путей на Ubuntu 24.04+ из-за ограничений AppArmor на userns, тогда как Landlock требует ядро 5.13 или новее, но не имеет внешних зависимостей.
### Собственная песочница GitHub Copilot CLI
Copilot CLI поставляется с локальной песочницей с июня 2026 года, включённой в
стандартную лицензию. Он запускает shell-команды через Microsoft MXC с ограниченным
доступом к файловой системе, сети и системе, на macOS, Linux и Windows.
`/sandbox enable` включает её.
Если этого вам достаточно, используйте её. Она не стоит ничего дополнительно и работает на Windows,
чего cplt не делает.
Две вещи, которые она не делает.
Политика живёт у администратора, а не у репозитория. Предприятия задают
политику песочницы через Intune или другой MDM. Рядом с кодом ничего не находится,
поэтому правило, важное для одного репозитория, не может следовать за ним к контрибьютору,
в CI или на ноутбук, которым MDM не управляет. В cplt политика — это
`.cplt.toml` в репозитории. Ревьюеры видят изменения в нём в pull
request, и файл может ужесточить собственную конфигурацию разработчика, но никогда не
ослабить её.
Она ограничивает процесс, а не то, что процесс делает с учётными данными, которые он
держит. Вкладки `/sandbox` охватывают файловую систему, сеть и системные
возможности, а внутри Git-репозитория агенту по умолчанию предоставляется чтение и запись
на `.git`. Агент в песочнице всё ещё имеет ваш токен `gh` и ваш
доступ на push. Push ветки, слияние pull request и удаление
репозитория — всё это корректные вызовы API от авторизованного клиента, и
правило файловой системы или сети не имеет о них мнения. cplt вместо этого оборачивает `git` и
`gh`. Агент свободно коммитит, создаёт ветки и делает rebase. `gh pr merge`,
`gh repo delete` и `gh release create` заблокированы по умолчанию. Также
`git push` в `main`/`master`; push в feature-ветки всё ещё работают, потому что
`protect_default_branch_only` включён. Установите его в `false`, чтобы блокировать каждый push, или
`git_guard.mode = "warn"`, чтобы только предупреждать.
Запускать оба разумно. MXC ограничивает процесс. Защиты решают, что
агент может делать с учётными данными, которые он держит.
### Честные пробелы
- macOS сегодня имеет самое сильное принудительное применение на уровне файлов. Покрытие Linux улучшается, но не идентично.
- cplt пока не предлагает простые пресеты политик read-only / workspace-write / full-access.
- Если вы хотите полную изоляцию контейнера, cplt не пытается заменить Docker.
## Установка
### Homebrew (рекомендуется)```bash
brew install navikt/tap/cplt
mise use -g 'github:navikt/cplt@'
mise выбирает подходящий релизный артефакт для вашей платформы и проверяет
аттестацию происхождения сборки.
Зафиксируйте версию. Наши строки версий не являются сопоставимыми semver — они содержат
ведущие нули и два дефиса — поэтому `mise latest` может разрешиться в более старый
релиз, чем самый новый ([navikt/copilot#818](https://github.com/navikt/copilot/issues/818)).
### apt (Debian/Ubuntu, рекомендуется на Linux)
[navikt/apt](https://navikt.github.io/apt/) — это подписанный архив, размещённый через
GitHub Pages, содержащий cplt и nav-pilot для amd64 и arm64:```bash
curl -fsSL https://navikt.github.io/apt/keyring/navikt-archive-keyring.gpg \
| sudo tee /usr/share/keyrings/navikt-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/navikt-archive-keyring.gpg] https://navikt.github.io/apt stable main" \
| sudo tee /etc/apt/sources.list.d/navikt.list
sudo apt update && sudo apt install cplt
Это простой apt-репозиторий, зеркалирующий наши релизы, а не дистрибутивный пакет
с собственным мейнтейнером. Его задача публикации запускается ежечасно и забирает новейший .deb
из последнего релиза каждого инструмента, поэтому релиз, выпущенный минуту назад, становится доступным для установки таким способом только в течение
часа.
Пакет размещает бинарный файл по пути /usr/bin/cplt, и с этого момента обновления происходят
через sudo apt upgrade. cplt update отказывается трогать установку через apt
и вместо этого указывает на sudo apt upgrade: замена бинарного файла в обход dpkg была бы отменена следующим запуском apt.
Без архива тот же .deb является артефактом релиза:```bash
arch=$(dpkg --print-architecture) # amd64 or arm64
gh release download --repo navikt/cplt --pattern "${arch}.deb"
sudo apt install ./cplt_"${arch}".deb
### curl | bash
Для дистрибутивов, не являющихся производными Debian, и для CI:```bash
curl -fsSL https://raw.githubusercontent.com/navikt/cplt/main/install.sh | bash
Параметры:```bash
curl -fsSL ... | bash -s -- --version 2026.05.05-174753-75bae5b
curl -fsSL ... | bash -s -- --dir ~/.local/bin
curl -fsSL ... | bash -s -- --no-brew
### Скачать из релизов
Возьмите последнюю сборку для вашей платформы из [GitHub Releases](https://github.com/navikt/cplt/releases/latest):```bash
# macOS, Apple Silicon (M1/M2/M3/M4)
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-aarch64-apple-darwin.tar.gz | tar xz
sudo mv cplt /usr/local/bin/
# macOS, Intel
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-x86_64-apple-darwin.tar.gz | tar xz
sudo mv cplt /usr/local/bin/
# Linux, x86_64
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv cplt /usr/local/bin/
# Linux, ARM64
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-aarch64-unknown-linux-gnu.tar.gz | tar xz
sudo mv cplt /usr/local/bin/
Каждый релизный бинарник содержит аттестацию происхождения сборки. Проверьте её:```bash gh attestation verify cplt -o navikt
### Сборка из исходного кода```bash
git clone https://github.com/navikt/cplt.git && cd cplt
cargo build --release
sudo cp target/release/cplt /usr/local/bin/
Или с mise:```bash mise run install
`mise run install` и ручная сборка помещают cplt в `/usr/local/bin/cplt`. Если у вас также есть сборка Homebrew в `/opt/homebrew/bin/cplt`, поставьте `/usr/local/bin` первым в `PATH`, чтобы ваша development-сборка имела приоритет:```bash
# Check which cplt is active
which cplt
# If it shows /opt/homebrew/bin/cplt, reorder your PATH:
export PATH="/usr/local/bin:$PATH"
Или просто запустите /usr/local/bin/cplt явно и полностью пропустите разрешение PATH.
У cplt нет бэкенда песочницы для Windows. Принудительное применение — это Apple Seatbelt на macOS и Landlock LSM на Linux, поэтому нативно запускать на Windows нечего. Поддерживаемый путь — WSL2, где cplt — это обычная установка Linux, а песочница обеспечивается на уровне ядра. Каждая ветка ядра Microsoft собирает CONFIG_SECURITY_LANDLOCK=y и указывает landlock первым в CONFIG_LSM (config-wsl), поставляется начиная с ядра 5.15.57.1, и командная строка ядра WSL по умолчанию не задаёт переопределение lsm=.
В PowerShell, один раз:```powershell wsl --install # WSL2 + the default distro (now Ubuntu 26.04 LTS), then reboot wsl --install -d Ubuntu-24.04 # ...or pin an older release wsl --update # keep the Microsoft kernel current, see the ABI note below
Всё ниже выполняется **внутри дистрибутива** (`wsl` или профиля Ubuntu в Windows Terminal), а не в PowerShell:```bash
# 1. Node. Copilot CLI requires Node 22+
# Ubuntu 26.04 ships 22.x, so apt is enough:
sudo apt update && sudo apt install -y nodejs npm
# Ubuntu 24.04 ships Node 18, too old. Use nvm, fnm, or NodeSource there instead.
# 2. GitHub CLI, and log in. Ubuntu's universe package works but lags
# (2.45 on 24.04); add GitHub's apt repo if you want a current gh:
# https://github.com/cli/cli/blob/trunk/docs/install_linux.md
sudo apt install -y gh
gh auth login
# 3. The agent, installed in the distro, never on the Windows side
npm install -g @github/copilot
# 4. cplt, from the apt archive. The default distro is Ubuntu, so this is
# the same route as on any other Debian derivative.
curl -fsSL https://navikt.github.io/apt/keyring/navikt-archive-keyring.gpg \
| sudo tee /usr/share/keyrings/navikt-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/navikt-archive-keyring.gpg] https://navikt.github.io/apt stable main" \
| sudo tee /etc/apt/sources.list.d/navikt.list
sudo apt update && sudo apt install cplt
# 5. Check the result
cplt doctor
Не устанавливайте Copilot CLI на стороне Windows. При включённом interop (по умолчанию) Windows-овый PATH добавляется к PATH дистрибутива, поэтому npm install -g @github/copilot, выполненный на стороне Windows, обнаруживается внутри дистрибутива как /mnt/c/Users/<user>/AppData/Roaming/npm/copilot. Это установка для Windows, доступная через interop. Она не может работать в песочнице Linux, а npm-обёртка запускает node, которого в дистрибутиве не будет, если вы не установили его там же. Раньше симптомом была не связанная с этим ошибка извлечения среды выполнения. Теперь cplt называет причину, когда обнаруживает агента по пути /mnt/<drive>/ и работает под WSL, а cplt doctor сообщает об этом как о проваленной проверке вместо успешной (#188). WSL определяется по состоянию, принадлежащему ядру, — либо /run/WSL, либо по имени ядра в /proc/sys/kernel/osrelease и /proc/version, а не по WSL_DISTRO_NAME, который отсутствует под sudo и в юнитах systemd и который может задать любой процесс. На обычной Linux-машине /mnt/c не трогается. Там это обычная точка монтирования.
У этой проверки есть два ограничения, оба намеренные. Она опирается на корень автомонтирования по умолчанию, поэтому если вы его переместили ([automount] root в /etc/wsl.conf), установка на стороне Windows не распознаётся, и вы получаете прежний, менее полезный сбой с указанием пути в нём. А отключение interop прекращает утечку Windows-ового PATH, но не размонтирует /mnt/c.
Ядро и ABI Landlock. Текущий WSL (2.7.x и новее) поставляется с Linux 6.18, что даёт Landlock ABI 7 — всё, что использует cplt, кроме права connect() для unix-сокетов, для которого нужен ABI 9 (ядро 7.1). Установка, всё ещё работающая на линии ядра 6.6, получает ABI 3: правила файловой системы применяются, но правила TCP-портов (ABI 4), ограничение ioctl (ABI 5) и ограничение области сигналов/абстрактных сокетов (ABI 6) недоступны, а сетевой фильтрации приходится полагаться на прокси CONNECT. wsl --update продвигает вас вперёд. cplt doctor выводит версию ядра и обнаруженный ABI — это та проверка, которая важна на вашей машине.
Не отключайте Landlock в
.wslconfig.[wsl2] kernelCommandLineсо спискомlsm=, в котором отсутствуетlandlock, или собственный[wsl2] kernel=, собранный безCONFIG_SECURITY_LANDLOCK, убирает принудительное применение на уровне ядра, от которого зависит cplt, иcplt doctorсообщит, что Landlock недоступен.
Держите проект в файловой системе Linux. Работайте в ~/src/... внутри дистрибутива, а не в /mnt/c/Users/.... Сама Microsoft указывает, что доступ к файлам между ОС заметно медленнее, а /mnt/c по умолчанию обслуживается через 9p начиная с WSL 2.9.x (virtiofs включается опционально через [wsl2] virtiofs=true). Что важнее, мы не проверяли, как Landlock применяет правила на этой точке монтирования. В ядре не документировано никаких исключений для сетевых файловых систем или файловых систем на базе FUSE — только для каналов (pipes), сокетов и nsfs, — а собственный набор тестов Landlock прогоняет 9p и FUSE, поэтому мы ожидаем, что это работает. Никто здесь этого не подтвердил. Считайте проект в /mnt/c непроверенным, а не поддерживаемым.
Bubblewrap. Ubuntu 23.10+ блокирует непривилегированные пользовательские пространства имён через kernel.apparmor_restrict_unprivileged_userns, что ломает bwrap. Этот sysctl происходит из патча ядра Ubuntu, отсутствующего в ядре Microsoft, поэтому опциональный слой Bubblewrap, как ожидается, будет работать на Ubuntu под WSL2. Это вывод из исходников ядра, а не то, что мы запускали. Если bwrap там падает, пожалуйста, сообщите об этом в #189. Собственный seccomp-фильтр cplt — это обычная BPF-программа PR_SET_SECCOMP, которая наслаивается поверх фильтра, устанавливаемого WSL в каждом процессе.
Пока не проверено на реальной установке WSL2. Проверено по исходникам: Landlock скомпилирован и стоит первым в
CONFIG_LSMв ядре Microsoft; обнаружение/mnt/<drive>/, используемые им сигналы WSL и их текст ошибок; чтоcplt doctorпадает на таком агенте и выводит ядро + ABI Landlock; требования 5.13+/6.7+; и чтоinstall.shустанавливает бинарник релиза для Linux. Всё ещё не проверено никем здесь: как Landlock ведёт себя на/mnt/c, работает ли Bubblewrap под WSL2, какие именно версии пакетов поставляет ваш релиз дистрибутива, и описанная выше последовательность от начала до конца. Если вы это запустите, пожалуйста, сообщите, что реально произошло, в #189.
По умолчанию вы получаете песочницу, набирая cplt. Чтобы обычный copilot тоже запускался в песочнице:```bash
cplt --shell-install
Он определяет вашу оболочку, добавляет алиас в ваш rc-файл и выводит, что именно сделал. Запускайте его сколько угодно раз — дубликаты не появятся.
`--agent` выбирает, какая команда получит алиас, и доступен каждый агент, который может запускать cplt:```bash
cplt --shell-install --agent opencode # 'opencode' runs sandboxed
cplt --shell-install --agent claude # and 'claude', alongside the others
Каждая установка добавляет запись в ваш rc-файл, а не заменяет то, что там уже есть, поэтому вы можете изолировать столько агентов, сколько используете. Без --agent вы получаете copilot, который этот флаг устанавливал всегда.
| Оболочка | Изменяемый файл | Что добавляется (для --agent opencode) |
|---|---|---|
| zsh (по умолчанию в macOS) | ~/.zshrc | eval "$(cplt --shell-setup --agent opencode)" |
| bash | ~/.bashrc | eval "$(cplt --shell-setup --agent opencode)" |
| fish | ~/.config/fish/conf.d/cplt.fish | alias opencode 'cplt --agent opencode' |
--agent antigravity устанавливает алиасы и для antigravity, и для agy, поскольку любое из этих имён запускает один и тот же агент.
Перезапустите оболочку или выполните source для файла, чтобы активировать изменения.
Для --agent shell алиаса нет: нет бинарника shell, который можно было бы перехватить. Введите cplt --agent shell для изолированной оболочки или cplt exec -- <command> для одной команды.
Если вы предпочитаете не использовать --shell-install, добавьте строку самостоятельно:```bash
eval "$(cplt --shell-setup --agent opencode)"
alias opencode 'cplt --agent opencode'
Тот же шаблон, который используют mise, direnv и starship.
</details>
**Почему каждый алиас называет своего агента.** `alias opencode=cplt` не сделал бы того, на что это похоже. Обычный `cplt` выбирает своего агента из `--agent`, затем из файла конфигурации, затем из того, что найдёт в PATH — а определение через PATH предпочитает `copilot`. Ввод `opencode` вместо этого изолировал бы Copilot, и на экране не было бы ничего, что говорило бы об этом. Алиас передаёт `--agent`, поэтому команда, которую вы вводите, — это агент, который вы получаете.
**Почему алиас, а не симлинк?** cplt и Copilot CLI устанавливаются в один и тот же bin-каталог Homebrew (`/opt/homebrew/bin/`), и там может находиться только один файл с именем `copilot`, поэтому симлинк вызвал бы конфликт. Алиас обходит это. Настоящий бинарник `copilot` остаётся в PATH, где cplt может его найти и обернуть, а алиас перенаправляет вашу команду.
> **Примечание:** cplt отказывается вкладываться. Если он обнаружит, что уже работает внутри песочницы (через переменную окружения `__CPLT_WRAPPED`), он не будет запускаться снова. Подкоманды только для чтения, такие как `--print-profile` и `cplt doctor`, всё ещё работают внутри существующей песочницы.
## Использование```
cplt [OPTIONS] [-- <AGENT_ARGS>...]
Всё после -- передаётся напрямую процессу агента (copilot, opencode, gemini, antigravity, pi, claude, goose, dsh или shell).
Пресет задаёт базовый уровень для пяти основных переключателей песочницы одним флагом вместо их списка. Отдельные флаги всё равно имеют приоритет над пресетом, так что --preset permissive --no-allow-tmp-exec делает именно то, что написано. Также задаётся как [sandbox] preset = "..." в конфиге.
Полная матрица пресетов и порядок разрешения: docs/configuration.md.
Каталог проекта — это записываемое рабочее пространство, плюс узкий allowlist, необходимый для аутентификации, среды выполнения и инструментов (см. таблицу выше). Ядро блокирует всё остальное, включая SSH-ключи и облачные учётные данные.
cplt по умолчанию санирует окружение дочернего процесса. Проходят только безопасные переменные, а облачные учётные данные, URL баз данных и токены пакетов удаляются. Он также внедряет переменные укрепления, которые блокируют lifecycle-скрипты npm/yarn/pnpm (хуки postinstall, вектор атак на цепочку поставок номер один), отключают подпись git-коммитов и тегов (поскольку ~/.ssh и ~/.gnupg недоступны внутри песочницы) и отказываются от телеметрии инструментов разработчика (DO_NOT_TRACK=1, NEXT_TELEMETRY_DISABLED=1, TURBO_TELEMETRY_DISABLED=1, CHECKPOINT_DISABLE=1 и другие).
Что проходит:
Allowlist по префиксу с защитой от секретных суффиксов. Переменная, совпадающая с разрешённым префиксом вроде COPILOT_* или YARN_*, всё равно отбрасывается, если она заканчивается суффиксом, несущим секрет: _TOKEN, _AUTH, _SECRET, _SECRET_KEY, _KEY, _PASSWORD или _CREDENTIALS. Так COPILOT_DEBUG проходит, а COPILOT_API_KEY — нет.
Всегда блокируются: AWS_*, AZURE_*, NPM_TOKEN, DATABASE_URL, VAULT_TOKEN, SSH_AUTH_SOCK, переменные Docker, токены CI и всё, чего нет в allowlist.
| Флаг | Что делает |
|---|---|
--pass-env <VAR> | Передать одну переменную окружения агенту. Можно повторять |
--inherit-env | ⚠️ Опасно. Наследовать полное родительское окружение. Удаляются только , , , . Только для отладки |
cplt автоматически обнаруживает установленные инструменты и пишет соответствующие правила песочницы. Обычно правила получают только каталоги, существующие на диске, так что фантомных путей нет. В macOS записываемые каталоги приложений включаются при обнаружении, даже если они ещё не существуют, так что их можно создать при первом использовании. Linux не может разрешить запись в несуществующий путь, поэтому там создание должно происходить вне песочницы.
Запустите cplt doctor, чтобы увидеть, будет ли cplt работать здесь для вашего агента, и cplt doctor --verbose для всего, что он обнаружил на вашей машине.
Они транслируются в собственные флаги сессии агента, так что разделитель -- не нужен.
--continue и --resume также отображаются для OpenCode, Antigravity и Claude Code:
¹ Ни у OpenCode, ни у Antigravity нет интерактивного выбора сессии, так что голый --resume означает «продолжить последнюю сессию». У Claude Code он есть, поэтому отображается напрямую.
--remote и --name только для Copilot. Pi и режим shell не получают никакой трансляции вообще, так что все четыре флага для них отбрасываются. Автовозобновление — отдельный механизм: когда вы вызываете cplt без сквозных аргументов и без флагов сессии, он добавляет --resume за вас, и это применяется только к Copilot.
Комбинируйте их с флагами песочницы и сквозными аргументами --:```bash
cplt --resume=my-task # resume by name
cplt --remote --name my-task -- -p "fix tests" # remote + named + prompt
### Агенты
Выберите один с помощью `--agent <name>` или сделайте его значением по умолчанию с помощью `cplt config set sandbox.agent <name>`. Copilot, OpenCode и Antigravity автоматически определяются из `PATH` в указанном порядке, если вы не назвали агента явно.
| Агент | Значение `--agent` | Автоопределение | Аутентификация |
| --- | --- | --- | --- |
| GitHub Copilot CLI | `copilot` | да, приоритет 1 | Токен GitHub, из Keychain или `gh` |
| [OpenCode](https://opencode.ai/) | `opencode` | да, приоритет 2 | Подписка Copilot через `/connect` или `--pass-env ANTHROPIC_API_KEY` |
| [Antigravity CLI](https://github.com/google-antigravity/antigravity-cli) | `antigravity`, псевдонимы `agy` и `agi` | да, приоритет 3 | Google OAuth в браузере |
| [Pi](https://github.com/earendil-works/pi) | `pi` | нет | `--pass-env ANTHROPIC_API_KEY` и другие |
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `claude`, псевдонимы `cc` и `claude-code` | нет | OAuth подписки в `~/.claude` или Keychain, `CLAUDE_CODE_OAUTH_TOKEN` (отменяет разрешение Keychain) или `--pass-env ANTHROPIC_API_KEY` |
| [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | `dsh`, псевдонимы `deepseek` и `deepseek-harness` | нет | `--pass-env DEEPSEEK_API_KEY` или `$DSH_HOME/.env` (`~/.dsh/.env`) |
| Ваша оболочка | `shell` | нет | нет |
- **Pi, Claude Code, goose и DeepSeek Harness никогда не определяются автоматически.** `pi` и `dsh` — это общие имена бинарных файлов, которые могут конфликтовать с чем-то другим на вашей машине, а Claude Code нужно выбирать осознанно.
- **Сторонние API-ключи передаются только по желанию.** `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN` и переменные маршрутизации Bedrock/Vertex (`CLAUDE_CODE_USE_BEDROCK`, `AWS_BEARER_TOKEN_BEDROCK`, `CLAUDE_CODE_USE_VERTEX`, `ANTHROPIC_VERTEX_PROJECT_ID`, `GOOGLE_CLOUD_PROJECT`) никогда не передаются, если вы не назовёте их с помощью `--pass-env`.
- **Аутентификация по подписке не требует переменной окружения.** Поток устройства `/connect` в OpenCode сохраняет свой токен в `~/.local/share/opencode/auth.json`, а OAuth-токен Claude Code находится в `~/.claude` (`.credentials.json` в Linux) или в macOS Keychain. Оба доступны внутри песочницы, поэтому cplt не будет придираться к отсутствию API-ключа ни для одного из них.
- **Браузерным OAuth-потокам нужен `--allow-browser`**, когда появляется запрос на вход. Это касается Antigravity; все остальные агенты здесь используют поток устройства, который выводит код и URL и не требует браузера. Этот флаг позволяет агенту запускать любое приложение вне песочницы и не может быть ограничен URL-адресами, поэтому включайте его для входа и снова выключайте — см. [таблицу флагов](#sandbox-toggles) и [docs/security.md](https://github.com/navikt/cplt/blob/main/docs/security.md#--allow-browser-is-a-sandbox-escape-and-cannot-be-scoped).
- **Автообновление Claude Code отключено** с помощью `DISABLE_AUTOUPDATER=1`. У Claude Code нет флага `--no-auto-update`, самообновление внутри песочницы является вектором персистентности и в любом случае не сработало бы при путях установки, доступных только для чтения.
- **`CLAUDE_CONFIG_DIR` учитывается.** Когда он задан, cplt предоставляет доступ к этому каталогу вместо `~/.claude` и передаёт переменную дальше, поэтому перемещённый корень конфигурации продолжает работать.
- OpenCode — [официально поддерживаемый клиент Copilot](https://github.blog/changelog/2026-01-16-github-copilot-now-supports-opencode/), поэтому ваша существующая подписка Copilot работает с `/connect` внутри OpenCode.
Каталоги конфигурации для каждого агента, использование Keychain, разрешения на выполнение и изоляция окружения описаны в [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md#supported-agents).
### Поддержка goose
cplt может поместить в песочницу [goose](https://github.com/aaif-goose/goose), открытый AI-агент (бинарный файл `goose`). Проверено на goose 1.48.0.```bash
# Run goose (must be explicit — not auto-detected)
cplt --agent goose
# goose is provider-agnostic — pass your provider's API key
cplt --agent goose --pass-env ANTHROPIC_API_KEY
cplt --agent goose --pass-env OPENAI_API_KEY
# Skip the keyring entirely: keep the key in the environment
GOOSE_DISABLE_KEYRING=1 cplt --agent goose --pass-env OPENAI_API_KEY --pass-env GOOSE_DISABLE_KEYRING
# Set goose as your default agent
cplt config set sandbox.agent goose
Замечания по безопасности для goose:
--agent goose или задайте sandbox.agent = "goose" в конфигурацииANTHROPIC_API_KEY, OPENAI_API_KEY, AZURE_OPENAI_API_KEY, GOOGLE_API_KEY, DATABRICKS_HOST/DATABRICKS_TOKEN, GROQ_API_KEY, OPENROUTER_API_KEY, XAI_API_KEY, AWS_BEARER_TOKEN_BEDROCK) распознаются как подсказки аутентификации и должны передаваться через --pass-env. goose читает , а не . Любой провайдер вне этого подмножества всё равно работает: укажите имя его переменной с помощью cplt может изолировать DeepSeek Harness (бинарник dsh), ориентированный на плагины агентный харнесс от DeepSeek. Upstream поставляет его как предварительную версию для разработчиков, и его собственный SAFETY.md говорит не полагаться на его средства контроля как на единственную границу, — именно для этого и существует cplt.```bash
cplt --agent dsh
cplt --agent dsh --pass-env DEEPSEEK_API_KEY
cplt config set sandbox.agent dsh
**Замечания по безопасности для DSH:**
- **Не обнаруживается автоматически**: выберите его с помощью `--agent dsh` (алиасы `deepseek`, `deepseek-harness`) или установите `sandbox.agent = "dsh"`. `dsh` — это короткое, общее имя команды, которое может принадлежать чему-то другому на вашей машине
- **Отключите собственный sandbox DSH внутри cplt**: DSH оборачивает каждый вызов shell и файловых инструментов в свой собственный процессный sandbox — Seatbelt на macOS, bwrap или Landlock на Linux. Ни один из них не вкладывается в cplt. macOS не поддерживает вложенные вызовы `sandbox-exec` (то же ограничение, из-за которого cplt отключает внутренний sandbox Gradle, см. [Ограничения](#limitations)), а bwrap строит своё пространство имён с помощью `unshare`, который блокируется seccomp-фильтром cplt. В любом случае cplt является принудительной границей, поэтому для сессий в sandbox выбирайте поставляемый с DSH пресет разрешений `danger-full-access`. Оставьте внутренний runner включённым — и вызовы инструментов будут завершаться ошибкой sandbox runner, а не ошибкой задачи
- **Один корень home, и cplt следует за переопределением**: DSH хранит сессии, настройки, кэш и профили в `$DSH_HOME` (`~/.dsh` по умолчанию). `DSH_HOME` находится в списке разрешённых переменных окружения, поэтому дочерний процесс разрешает тот же корень, который предоставляет cplt. Значение, указывающее на системный корень или ваш домашний каталог, отклоняется до запуска — тот же запрет, через который проходит `CLAUDE_CONFIG_DIR`
- **Защита от сохранения на хосте**: `$DSH_HOME/cordis.patch.yml`, оверлей уровня home, который Loader читает при загрузке, запрещён для записи. `$DSH_HOME/profiles/` остаётся доступным для записи, поскольку DSH перезаписывает include-root `cordis.yml` каждого профиля при каждой загрузке, поэтому `cordis.patch.yml` для каждого профиля и установленные плагины являются документированным остаточным риском — вносите изменения в профили и `dsh plugin` вне cplt и всегда запускайте `dsh` через cplt, чтобы всё внедрённое всё равно выполнялось в sandbox
- **Домены по умолчанию**: только `deepseek.com`. Поставляемый адаптер `dsh-llm-deepseek` по умолчанию использует `https://api.deepseek.com`. Направьте `DEEPSEEK_BASE_URL` на шлюз — и вам придётся добавить домен этого шлюза через `allowed_domains`
- **Аутентификация**: передайте ключ с помощью `--pass-env DEEPSEEK_API_KEY` или храните его в `$DSH_HOME/.env`. Ключ, сохранённый через собственный интерфейс моделей DSH, попадает в `$DSH_HOME/.credentials.yaml`, внутрь того же доступного для записи корня. macOS Keychain запрещён, поэтому `git push` по HTTPS требует токена `gh` в `hosts.yml` или `--pass-env GH_TOKEN`
### Режим shell
Запустите обычный shell в sandbox без AI-агента и с теми же ограничениями. Удобно для тестирования инструментов сборки, отладки проблем sandbox или просто аккуратной ручной работы.```bash
# Interactive sandboxed shell (uses $SHELL: fish, zsh, bash)
cplt --agent shell
# Inspect what's allowed without entering the shell
cplt --agent shell --print-profile
Применяются те же правила запрета по умолчанию: изоляция файловой системы, сетевые ограничения, очистка окружения. Каталоги конфигурации оболочки (переменные и история fish, история zsh) остаются доступными для записи.
Для одной команды cplt exec удобнее, чем cplt --agent shell -- -c 'cmd'.
Запуск любой команды внутри песочницы без запуска агента. Без стартового баннера, без запроса подтверждения, поэтому он подходит для скриптов, конвейеров и псевдонимов оболочки.```bash
cplt exec -- npm install cplt exec -- make build cplt exec -- go test ./...
cplt exec -c "npm install && npm test"
cplt exec --allow-lifecycle-scripts -- npm install cplt exec --project-dir /path/to/repo -- make build cplt exec --with-proxy -- curl https://example.com
alias npm="cplt exec -- npm" alias node="cplt exec -- node" alias python="cplt exec -- python"
К каждому флагу верхнего уровня `cplt` применимо: `--project-dir`, `--allow-read`, `--deny-path`, `--with-proxy`, `--pass-env` и остальные. Добавьте `--no-quiet`, чтобы увидеть полную сводку конфигурации песочницы перед запуском команды.
### Примеры```bash
# The common case: Copilot in the sandbox
cplt -- -p "fix the tests"
# Sessions
cplt --resume # pick one interactively
cplt --resume=my-refactor # by name
cplt --continue # most recent in this directory
cplt --remote --name my-task -- -p "fix tests" # named remote session
# Check the environment before the first run
cplt doctor
# Let Copilot read a shared library directory
cplt --allow-read ~/shared-libs -- -p "use shared-libs"
# Block a path you don't want Copilot to see
cplt --deny-path ~/.config/gh -- -p "refactor auth"
# Extra outbound port, e.g. an external API
cplt --allow-port 8443 -- -p "test the API"
# Localhost for MCP servers or dev servers
cplt --allow-localhost 3000 --allow-localhost 8080 -- -p "use the MCP server"
# All of localhost, needed by Next.js/Turbopack and Vite builds
cplt --allow-localhost-any -- -p "fix the build"
# Pass specific env vars through
cplt --pass-env MY_CUSTOM_VAR --pass-env ANOTHER_VAR -- -p "run with custom config"
# Inherit the full environment (dangerous, debugging only)
cplt --inherit-env -- -p "debug the build"
# Network
cplt --no-proxy -- -p "fix the tests" # proxy is on by default
cplt --blocked-domains ./blocked-domains.txt -- -p "refactor"
cplt --allow-private-domain intern.nav.no -- -p "use mcp-onboarding"
# Non-interactive / CI (skip the confirmation prompt)
cplt --yes -- -p "fix the tests"
# Inspect and debug the sandbox itself
cplt --print-profile
cplt --show-denials -- -p "fix the tests"
Конфигурация происходит на двух уровнях: глобальном — для предпочтений разработчика, и на уровне репозитория — для командной политики.```bash
cplt settings
cplt config set sandbox.quiet true cplt config set proxy.blocked_domains "~/.config/cplt/blocked-domains.txt" cplt config set git_guard.mode warn # observe pushes instead of blocking them cplt config set gh_guard.enabled false # opt out of the gh guard entirely
cplt config set --repo sandbox.allow_jvm_attach true cplt config set --repo deny.paths "~/secrets"
cplt config show # effective config (file + defaults) cplt config explain # every key with its description
`cplt settings` — это интерактивный редактор с представлениями Effective, Global и Repository, поиском, поэтапными изменениями и явным подтверждением перед сохранением всего, что связано с безопасностью. `cplt config` остаётся стабильным неинтерактивным интерфейсом для скриптов и CI. Предложения репозитория по-прежнему фиксируются и одобряются отдельно с помощью `cplt trust`. Редактор никогда не фиксирует и не одобряет их автоматически.
Приоритет применяется в порядке: флаги CLI, затем глобальный файл конфигурации `~/.config/cplt/config.toml`, затем встроенные значения по умолчанию. Конфигурация для конкретного репозитория в `.cplt.toml` — это отдельный слой, а не ступень на этой лестнице: `[deny]` ужесточает безусловно, а одобренные разрешения только добавляются, поэтому репозиторий может включить функцию, но никогда не может отключить что-то, заданное флагом CLI или глобальной конфигурацией.
`.cplt.toml` в корне репозитория содержит политику команды:```toml
[deny] # Applied automatically, no opt-in needed
paths = ["~/secrets", "~/.vault-token"]
env = ["VAULT_TOKEN", "DATABASE_URL"]
[propose] # Requires developer approval (cplt trust accept)
gh_guard = true
git_push_prevention = true
allow_jvm_attach = true
allow_docker = true
[propose.allow]
ports = [5432]
localhost = [3000]
socket = ["/var/run/docker.sock"]
cplt читает его из git HEAD, поэтому агент не может изменить свою собственную политику в середине сессии, а одобрения доверия привязаны к содержимому файла. Незакоммиченный .cplt.toml ничего не даёт, пока не будет закоммичен, хотя его ключи [deny] всё равно применяются. В CI и скриптах, где никто не может ответить на запрос, --accept-repo-config одобряет предложения закоммиченного файла для одного запуска, не сохраняя никакого доверия. cplt init создаёт его для вас, определяя инструментарий проекта:```bash
cplt init # preview detected permissions
cplt init --write # write .cplt.toml to disk
cplt init --quiet # output only TOML (pipe-friendly)
cplt init --global # generate a personal ~/.config/cplt/config.toml
Он знает JVM (Gradle/Maven), Node.js, Docker, Python, Rust, Go, Playwright, Spring Boot, Ktor, TestContainers, Next.js, Vite, Flyway, Cypress и секреты окружения из `.env.example`. Опасные разрешения выдаются генератором с прикреплённым предупреждением о риске. `--global` вместо этого смотрит на вещи уровня машины: браузеры Playwright, подпись GPG, учётные данные реестра, альтернативные агенты.
Некоторые ключи являются только глобальными и отклоняются из `.cplt.toml`, поскольку они специфичны для машины или являются локальным предпочтением: `sandbox.agent`, `sandbox.quiet`, `sandbox.yes`, `sandbox.validate`, `sandbox.scratch_dir`, `sandbox.pass_env`, `sandbox.inherit_env`, `sandbox.allow_cache_exec`, `sandbox.allow_cache_exec_any`, `proxy.enabled`, `proxy.port`, `proxy.log_file`, `proxy.log_level`, `proxy.blocked_domains`, `proxy.allowed_domains`, а также все ключи `[gh_guard]` и `[git_guard]`.
Полные сведения, включая модель доверия, правила раскрытия путей и полный справочник по файлу конфигурации: [docs/configuration.md](https://github.com/navikt/cplt/blob/main/docs/configuration.md).
## Архитектура```
┌──────────────────────────────────┐
│ cplt (Rust binary) │
│ ┌───────────┐ ┌─────────────┐ │
│ │ Policy │ │ CONNECT │ │
│ │ Generator │ │ Proxy │ │
│ └─────┬─────┘ │ (optional) │ │
│ │ └─────────────┘ │
│ ▼ │
│ ┌─────────────┬────────────┐ │
│ │ macOS │ Linux │ │
│ │ Seatbelt │ Landlock │ │
│ │ sandbox- │ + seccomp │ │
│ │ exec │ pre_exec │ │
│ └─────────────┴────────────┘ │
│ │ │
│ ▼ │
│ copilot (sandboxed) │
│ ├── All child processes │
│ ├── Cannot read ~/.ssh │
│ ├── Network port-restricted │
│ ├── SSH agent blocked │
│ └── Filesystem = primary ctrl │
└──────────────────────────────────┘
Модель безопасности — это файловая система с запретом по умолчанию и принудительным применением на уровне ядра. В macOS и в Linux с ядром 6.7+ (Landlock ABI v4) сеть по умолчанию ограничена портом 443, а --allow-port добавляет дополнительные. На более старых ядрах Linux эту роль выполняет CONNECT-прокси, поэтому он включён по умолчанию. Доступ к SSH-агенту и исходящие соединения на localhost блокируются на уровне ядра в macOS. В Linux ни то, ни другое не блокируется: правила Landlock на основе портов не отличают localhost от удалённого хоста, а connect() для unix-сокетов не контролируется Landlock до ядра 7.1, поэтому помимо сокетов, которые маскирует bubblewrap, удержанный SSH_AUTH_SOCK — единственное, что стоит между агентом и вашими загруженными ключами. Генератор профиля обнаруживает ваше окружение (cplt doctor --verbose показывает те же результаты проверки) и создаёт правила только для тех каталогов инструментов, которые действительно существуют на диске. Меньше правил — теснее песочница.
sandbox-execpre_exec (ядро 5.13+, фильтрация TCP-портов на 6.7+)Внутреннее устройство и структура модулей: docs/architecture.md. Модель угроз, уровни защиты и честно признанные пробелы: SECURITY.md.
Один бинарник, минимум зависимостей, никаких runtime-сервисов, никакой телеметрии. Три уровня защиты с чёткими границами между ними:
От чего cplt защищает:
.env): блокируется ядром.git/hooks защищён от записи на уровне ядра в macOS. В Linux с Landlock и без Bubblewrap он остаётся доступным для записи, и тогда собственный родительский git в cplt запускается с core.hooksPath=/dev/null, поэтому он никогда не выполняет подложенный хук, хотя git, запущенный вами самостоятельно, всё же выполнитPNPM_HOME, ~/.deno/bin, ~/.bun/bin): запись туда разрешена, чтобы pnpm add -g и подобные команды работали внутри песочницы, поэтому агент может оставить после себя бинарник, который позже подхватит оболочка из вашего PATHОт чего cplt не защищает:
sandbox.keychain_substitute может отказаться от этого разрешения там, где у агента есть другие учётные данныеНаши приоритеты по порядку: корректность (каждое утверждение протестировано, у каждого крайнего случая есть ссылка на CVE или исследование), прозрачность (SECURITY.md ничего не скрывает), простота (один бинарник, конфигурация не требуется, разумные значения по умолчанию) и полезность (не мешать и позволять агенту работать безопасно).
Подробнее: docs/security.md · SECURITY.md
Прокси включён по умолчанию. Весь исходящий трафик от Copilot CLI, gh и curl идёт через локальный CONNECT-прокси посредством HTTP_PROXY/HTTPS_PROXY и NODE_USE_ENV_PROXY=1. Он слушает эфемерный порт, назначенный ОС, поэтому ничего не конфликтует. Вы получаете логирование соединений в реальном времени, блокировку доменов, белый список доменов, постоянный журнал аудита и ту же политику портов, которую применяет песочница (443 плюс всё, что указано в allow.ports).```bash
cplt --proxy-forced -- -p "fix tests" # force all egress through the proxy
cplt --no-proxy -- -p "fix tests" # disable for one run
cplt --blocked-domains blocked-domains.txt -- -p "x" # block known-bad domains
cplt --allowed-domains allowed-domains.txt -- -p "x" # allowlist mode
cplt --default-allowlist -- -p "x" # fail-closed: only the agent's own domains
cplt --observe-domains -- -p "x" # record what the agent contacts, block nothing
cplt --proxy-upstream http://proxy.corp:8080 -- -p "x" # chain through a corporate proxy
`--observe-domains-out <FILE>` записывает наблюдаемый набор по одному домену на строку, а
`--proxy-upstream-no-proxy <HOST>` перечисляет хосты, к которым следует обращаться напрямую, а не через
upstream.```bash
cplt config set proxy.enabled false
cplt config set proxy.blocked_domains "~/.config/cplt/blocked-domains.txt"
cplt config set proxy.allowed_domains "~/.config/cplt/allowed-domains.txt"
cplt config set proxy.log_file "~/.config/cplt/proxy.log"
Принудительный режим прокси включается по желанию. Он ограничивает исходящий трафик ядра портом прокси, так что сокет, открытый напрямую, или env -u HTTPS_PROXY не могут проскользнуть мимо. Принуждение полноценно на macOS, где оно привязывается к localhost:<proxy_port>. На Linux оно блокирует прямой TCP :443, а правило seccomp разрешает только SOCK_STREAM с протоколом 0 или IPPROTO_TCP для AF_INET/AF_INET6, так что UDP, raw, SCTP и DCCP тоже закрыты — ценой всего, что открывает такой сокет, а не только кода, отправляющего UDP. Остаётся остаток на основе порта, evil.com:<proxy_port>, до #114.
Вне принудительного режима прокси Linux не ограничивает UDP. Сетевые права Landlock ограничены только TCP до ABI v10, cplt обрабатывает только AccessNet::ConnectTcp, а правило seccomp выше намеренно не применяется — запрет SOCK_DGRAM там сломал бы getaddrinfo(3), а значит и весь DNS, для каждого непроксируемого инструмента. Исходящий UDP к любому хосту, входящий bind UDP, DNS-туннелирование и QUIC/HTTP-3 поэтому не опосредованы в режиме по умолчанию, а CONNECT-прокси переносит только TCP, так что ничего из этого не появляется в логе прокси. macOS ограничивает UDP в режиме по умолчанию, но тоже не маршрутизирует его: remote ip "*:443" покрывает UDP, так что QUIC/HTTP-3 на 443 уходит, не касаясь прокси, и там тоже. При proxy.forced лог прокси — это полная запись исходящего трафика на macOS. На Linux он полон, за исключением остатка evil.com:<proxy_port> выше, который не проходит через прокси и потому не появляется в его логе.
Оба списка сопоставляются одинаково: example.com покрывает точный домен и все поддомены, сопоставление нечувствительно к регистру, а завершающие точки отбрасываются. Файлы блоклиста и аллоулиста перечитываются каждые пять секунд, так что вы можете редактировать их на лету. Трафик localhost обходит прокси через NO_PROXY и никогда не появляется в журнале аудита. --proxy-timeout <SECONDS> ограничивает чтение запросов и заголовков (по умолчанию 60) и не разрывает установленные CONNECT-туннели, которые могут простаивать до часа.
Каждый флаг прокси, детали фильтрации доменов, цепочка через корпоративный прокси вышестоящего уровня и формат журнала соединений: docs/proxy.md.
Включите их, и cplt перехватывает gh и git через скрипты-обёртки в $PATH:
Это Уровень 3, мягкий барьер. Он останавливает добросовестного агента от случайного совершения разрушительных действий. Для жёсткой границы полагайтесь на песочницу ядра и серверную защиту веток.
С включённой защитой gh cplt также кэширует токен GitHub при запуске и выдаёт его один раз через callback gh auth token, после чего удаляет кэш. Это сокращает случайные утечки и утечки через окружение. Это не граница против враждебного агента, потому что кэш живёт в собственном TMPDIR агента, и агент, который прочитает его до легитимного потребителя, всё равно получит токен. В SECURITY.md есть полное заявление о block_auth_token.
Полное поведение: docs/gh-guard.md · docs/git-guard.md
Песочница намеренно блокирует некоторые рабочие процессы. Распространённые из них и их исправления:
Playwright Chromium требует cplt config set sandbox.allow_cache_exec ms-playwright, и Chromium должен работать без собственной вложенной песочницы. На macOS его вспомогательные процессы не могут инициализировать вторую песочницу Seatbelt внутри cplt (forbidden-sandbox-reinit); на Linux фильтр seccomp в cplt блокирует системные вызовы пространств имён, которые нужны этой песочнице. Playwright как библиотека уже запускается с --no-sandbox, и тот же самый opt-in устанавливает PLAYWRIGHT_MCP_SANDBOX=false для Playwright MCP, который иначе включил бы её обратно. Любому другому лаунчеру Chromium нужен --no-sandbox самостоятельно. cplt остаётся принудительной границей ядра, но скомпрометированный рендерер тогда получает полный профиль Playwright от cplt вместо более узкого дочернего профиля Chromium. См. Cache exec и SECURITY.md.
Git commit работает для любого агента; работает ли git push по HTTPS, зависит от агента. Три предварительных условия: используйте HTTPS-ремоуты вместо SSH (git remote set-url origin https://github.com/org/repo.git, или перепишите глобально с помощью git config --global url."https://github.com/".insteadOf "[email protected]:"), один раз выполните gh auth login вне песочницы и выполните gh auth setup-git, если credential helper ещё не настроен. Тогда push запускает gh auth git-credential, которому нужен токен, доступный gh изнутри песочницы — это различается для каждого агента, см. Git workflow. Push в ветку по умолчанию и все force push по умолчанию отклоняются защитой git; отправляйте feature-ветку. Сокет SSH-агента заблокирован, потому что он разблокирует каждый загруженный ключ и может аутентифицироваться на любом хосте, тогда как credential helper gh ограничен областью GitHub.
JVM учитывает прокси, поэтому внутренний репозиторий Maven на приватном IP теперь нужно разрешать. cplt внедряет http(s).proxyHost/proxyPort в JAVA_TOOL_OPTIONS, так что разрешение зависимостей Gradle и Maven идёт через CONNECT-прокси и появляется в логе прокси вместо обхода его. Затем SSRF-защита прокси отклоняет внутренний Nexus или Artifactory, который разрешается в приватное адресное пространство, точно так же, как она уже делает для curl, npm и pip. Добавьте его DNS-имя в proxy.allow_private_domains. URL репозитория, записанный как голый IP-литерал (https://10.20.30.40/repository/maven-public/), нельзя разрешить никаким ключом — эта проверка выполняется до обращения к списку разрешённых — так что такому репозиторию нужно DNS-имя. Форки плагина WorkerExecutor и демон Gradle, запущенный вне cplt и переиспользованный внутри, не проксируются. См. Internal Maven/Gradle repositories on private IPs.
Gradle 9+ запускает собственную вложенную песочницу, и cplt отключает её. Начиная с Gradle 8.8 демон оборачивает себя в sandbox-exec (управляется GRADLE_MACOS_SANDBOX, ранее свойством org.gradle.daemon.sandbox). macOS не поддерживает вложенные вызовы sandbox-exec, поэтому внутренняя песочница падает с "Operation not permitted" на операциях с сокетами. cplt внедряет GRADLE_MACOS_SANDBOX=off, поскольку он уже обеспечивает песочницу на уровне ядра. Это известная проблема вышестоящего проекта, которая затрагивает любой инструмент, оборачивающий Gradle во внешнюю песочницу. Переопределите с помощью --pass-env GRADLE_MACOS_SANDBOX, если вы действительно хотите собственную песочницу Gradle.
Copilot CLI 1.0.83 запускает собственную вложенную песочницу, и cplt отключает её. На Linux эта песочница строит сетевое пространство имён — slirp4netns, iptables, /dev/net/tun — и фильтр seccomp в cplt запрещает unshare, который она использует. cplt также устанавливает HTTP_PROXY/HTTPS_PROXY, что в 1.0.83 ставит песочницу Linux на путь исходящего трафика через прокси, хотите вы того или нет, так что они конфликтуют при каждом запуске. Симптом: [cplt] Starting Copilot in sandbox... и затем ничего. cplt внедряет собственный opt-out Copilot, COPILOT_CLI_SANDBOX_SUPPORT_OVERRIDE=unsupported; Copilot отступает на сессию, сообщает об этом и оставляет ваш сохранённый sandbox.enabled в покое. cplt — это граница, как и для Gradle и Chromium. Переопределите с помощью --pass-env COPILOT_CLI_SANDBOX_SUPPORT_OVERRIDE. Корпоративная управляемая политика, требующая песочницу, переопределяет всё это — см. Copilot CLI's own command sandbox.
Каждое влияние, с таблицами по инструментам, заметками о демонах JVM и Kotlin, устранением неполадок GPG и различиями платформ для приватных реестров: docs/known-impacts.md.
sandbox-exec устарел. Apple не удалила его, но может в будущей версии macOS.lsopen в SBPL тоже нет фильтра, так что --allow-browser — это либо весь Launch Services, либо ничего из него. С ним агент может запустить любое приложение вне песочницы, и никакая обёртка не может это сузить — см. docs/security.md..env внутри каталога проекта не обеспечивается ядром. Запись в .git/hooks блокируется, когда активен Bubblewrap.--deny-path требует Bubblewrap. Он обеспечивается через маски монтирования, когда bwrap активен. Без него Landlock работает только по аллоулисту, и cplt предупреждает о запрете вместо его применения.Подробнее: docs/security.md
Вклад приветствуется.```bash git clone https://github.com/navikt/cplt.git && cd cplt git config core.hooksPath hack # enables pre-commit fmt + clippy checks mise run check # runs fmt, clippy, and tests
Откройте issue перед началом крупного изменения. Каждый PR должен проходить CI (fmt, clippy, тесты).
## Ссылки
- [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md) — полная модель безопасности, анализ угроз, стратегия тестирования и предшествующие наработки
- [Apple sandbox-exec(1)](https://keith.github.io/xcode-man-pages/sandbox-exec.1.html)
- [Chromium Seatbelt V2 Design](https://chromium.googlesource.com/chromium/src/sandbox/+show/refs/heads/main/mac/seatbelt_sandbox_design.md)
- [Документация Landlock LSM](https://docs.kernel.org/userspace-api/landlock.html)
- [Документация seccomp-BPF](https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html)
- [OWASP SSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html)
- [michaelneale/agent-seatbelt-sandbox](https://github.com/michaelneale/agent-seatbelt-sandbox)
## Лицензия
[MIT](https://github.com/navikt/cplt/blob/main/LICENSE)
| Флаг | Что делает |
|---|
--preset strict | Полная блокировка сети. Все пять переключателей выключены, плюс включены gh_guard, git_guard, proxy.forced (принудительный выход через прокси) и proxy.default_allowlist (allowlist доменов с отказом по умолчанию). Аварийный выход: --allow-all-domains отключает только allowlist |
--preset standard | Текущие значения по умолчанию. Все пять выключены, scratch-каталог остаётся включённым. То же самое, что не передавать пресет |
--preset permissive | Включает allow_localhost_any, allow_tmp_exec и allow_lifecycle_scripts |
--preset full-trust | ⚠️ Опасно. Включает все пять, добавляя allow_env_files и allow_docker |
| Флаг | Что делает |
|---|
-d, --project-dir <DIR> | Каталог, в котором может работать Copilot. По умолчанию — корень текущего git-репозитория |
--allow-read <PATH> | Разрешить Copilot читать файлы вне проекта, только для чтения. Можно повторять |
--allow-write <PATH> | Разрешить Copilot читать и писать вне проекта. Используйте осторожно. Можно повторять. Дерево доступно для записи, но не для выполнения — дерево, обладающее обоими свойствами, это путь для подброса бинарников, поэтому allow.write на ~/.cargo также запрещает запуск ~/.cargo/bin. Используйте --allow-exec на отдельном, непересекающемся дереве, когда нужны оба |
--allow-exec <PATH> | ⚠️ Опасно. Разрешить агенту выполнять бинарники из дерева вне стандартных каталогов инструментов — например, перемещённый Homebrew или префикс тулчейна. Даёт чтение и выполнение, но никогда запись. Можно повторять. Отклоняется для небезопасного корня (/, /tmp, $HOME и его родительские каталоги, системные каталоги платформы) и для любого дерева, пересекающегося с записываемым — каталогом проекта, грантом --allow-write, записываемым каталогом инструментов вроде ~/.cache, записываемым каталогом данных агента (~/.claude, ~/.local/share/opencode, ~/.pi/agent и подобные), реальным .git рабочего дерева или bare-репозитория, или деревом, которое бэкенды делают записываемым вообще без гранта (/tmp и /dev/shm в Linux; /private/tmp и /private/var/folders в macOS): запись плюс выполнение — это путь для подброса бинарников, и ни один бэкенд не может вычесть грант на запись из гранта на выполнение |
--allow-socket <PATH> | ⚠️ Опасно. Разрешить путь к Unix domain socket, например к кастомному демону LSP или сокету базы данных. Можно повторять. То, что находится на другом конце, выполняется вне песочницы, поэтому указание этого на docker.sock или сокет агента эквивалентно --allow-docker, и единственная защита — отклонение пересечений с --deny-path. В Linux не делает ничего ниже ядра 7.1, поскольку подключения к unix-сокетам не контролируются Landlock до ABI v9 (см. Ограничения Linux) |
--deny-path <PATH> | Заблокировать путь, который иначе был бы разрешён. Запрет всегда побеждает. Можно повторять |
--allow-port <PORT> | Разрешить исходящий трафик на дополнительном порту. По умолчанию только 443. Можно повторять. В macOS правило — (remote ip "*:PORT"), которое не зависит от семейства и потому несёт UDP так же, как TCP; Landlock контролирует только TCP connect. При proxy.forced порт вообще не открывает прямой сокет — он достижим через прокси, так что инструменты, осведомлённые о прокси, продолжают работать |
--allow-localhost <PORT> | Разрешить исходящие к localhost на одном порту. Localhost по умолчанию заблокирован. Используйте для MCP-серверов или dev-серверов. Можно повторять |
--allow-localhost-any | Разрешить исходящие к localhost на всех портах. Нужно инструментам сборки вроде Turbopack (Next.js) и Vite, которые используют случайные эфемерные порты для IPC |
| Категория | Примеры | Как |
|---|
| Ядро системы | HOME, USER, PATH, SHELL, TMPDIR, LANG | Явный allowlist |
| Терминал | TERM, COLORTERM, TERM_PROGRAM | Явный allowlist |
| Редактор | EDITOR, VISUAL, PAGER | Явный allowlist |
| Токены аутентификации | GH_TOKEN, GITHUB_TOKEN, COPILOT_GITHUB_TOKEN | Передаются только если вы уже их задали. gh guard вместо этого использует одноразовый файл |
| Конфигурация Copilot | COPILOT_DEBUG, COPILOT_* | Allowlist по префиксу |
| Языковые среды выполнения | NODE_*, GOPATH, CARGO_HOME, JAVA_HOME, VIRTUAL_ENV, PYTHONPATH | Явный allowlist |
| Менеджеры инструментов | NVM_*, FNM_*, PYENV_*, MISE_*, SDKMAN_*, COREPACK_*, YARN_* | Allowlist по префиксу |
| OpenTelemetry | OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTES, OTEL_* | Allowlist по префиксу (OTEL_EXPORTER_OTLP_HEADERS может нести опциональную аутентификацию) |
| Каталоги XDG | XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_STATE_HOME, XDG_CACHE_HOME | Явный allowlist |
NO_COLORFORCE_COLORSSH_AUTH_SOCKSSH_AGENT_PID| Флаг | Что делает |
|---|
--allow-lifecycle-scripts | Разрешить выполнение lifecycle-скриптов npm/yarn/pnpm (хуков postinstall). По умолчанию заблокировано. Используйте, когда npm install их требует |
--allow-gpg-signing | Разрешить подпись GPG-коммитов и тегов внутри песочницы. Даёт доступ только для чтения к публичному кольцу ключей и сокету GPG-агента. Приватные ключи остаются запрещёнными. См. Подпись GPG |
--allow-jvm-attach | Разрешить unix-сокеты JVM Attach API в /tmp. Нужно для inline-мокирования MockK, inline-агентов Mockito, ByteBuddy. См. JVM Attach API |
--allow-msbuild | Разрешить unix-сокеты worker-node MSBuild в /tmp. Нужно для dotnet build. Не включает постоянный MSBuild Server. См. MSBuild worker-node IPC |
--no-scratch-dir | Отключить scratch-каталог для сессии, который включён по умолчанию. TMPDIR не будет перенаправлен |
--scratch-dir | Явно включить scratch-каталог для сессии. Уже значение по умолчанию, так что это для переопределения scratch_dir = false в конфиге |
--brief | 🧪 Экспериментально. Записать обращённый к агенту брифинг песочницы в scratch-каталог (CPLT_BRIEF.md). По умолчанию выключено. Также sandbox.brief = true в конфиге. Нестабильно, поэтому может измениться или быть удалено в будущем релизе |
--no-brief | Отключить брифинг песочницы для этого запуска, переопределяя sandbox.brief = true в конфиге. Также подавляет блок AGENTS.md, который зависит от брифинга |
--agents-md | 🧪 Экспериментально. Вместе с --brief также записать управляемый блок cplt в AGENTS.md проекта. По умолчанию выключено. Также sandbox.agents_md = true в конфиге. Не действует без --brief. Нестабильно, поэтому может измениться или быть удалено в будущем релизе |
--no-agents-md | Отключить блок AGENTS.md для этого запуска, переопределяя sandbox.agents_md = true в конфиге. Не трогает брифинг в scratch-каталоге |
--allow-tmp-exec | ⚠️ Опасно. Разрешить выполнение из системных временных каталогов (/private/tmp, /private/var/folders). Предпочитайте scratch-каталог |
--allow-cache-exec <SUBDIR> | Разрешить выполнение из одного ~/Library/Caches/<SUBDIR>. Можно повторять. Для инструментов, которые кэшируют там скомпилированные бинарники, например Playwright и pnpm dlx |
--allow-cache-exec-any | ⚠️ Опасно. Разрешить выполнение из всего ~/Library/Caches. Предпочитайте --allow-cache-exec <SUBDIR> |
--allow-browser | ⚠️ Опасно. С включённым этим агентом может запустить любое приложение на вашей машине вне песочницы. Грант — это Launch Services, а не браузер: launchd запускает цель вне профиля Seatbelt, так что open -a Terminal /tmp/x.sh выполняется без песочницы. Это невозможно ограничить URL-адресами — lsopen в SBPL не принимает фильтр, и грант достижим через LSOpenCFURLRef() вообще без бинарника open, так что никакая обёртка не может его сузить (#251, и docs/security.md). Включайте только пока на экране действительно виден запрос на вход (OAuth MCP-сервера, повторная аутентификация), затем выключайте обратно. По умолчанию выключено |
--deny-clipboard | Заблокировать агенту чтение или запись в буфер обмена macOS (pbpaste/pbcopy), запрещая Mach-сервис com.apple.pasteboard. Все остальные Mach-сервисы (Keychain, DNS, Security framework) не затронуты. Включено по умолчанию — этот флаг повторяет значение по умолчанию |
--allow-clipboard | Вернуть агенту буфер обмена macOS, который cplt запрещает по умолчанию. Эквивалентно sandbox.deny_clipboard = false |
--use-bubblewrap | Только Linux. Требовать слой пространств имён bubblewrap (PID, mount, IPC, UTS, cgroup, пользовательские пространства имён плюс приватный /tmp) поверх Landlock и seccomp. Завершается с ошибкой, если bwrap отсутствует. Автоопределяется, когда не задан ни один флаг |
--no-bubblewrap | Только Linux. Никогда не использовать bubblewrap, даже когда он установлен. Откатывается к Landlock и seccomp. Используйте, когда bwrap ломает конкретный инструмент |
| Среда выполнения | Домашние каталоги | Переменные окружения / префиксы | Обнаружение |
|---|
| Node.js | .nvm, .local/share/fnm, .local/bin | NODE_*, NPM_*, NVM_*, FNM_* | node |
| Rust | .cargo, .rustup | CARGO_HOME, RUSTUP_HOME | cargo |
| Go | go/bin, go/pkg | GOPATH, GOROOT, GOCACHE и т. д. | go |
| Java/Kotlin (JVM) | .sdkman, .jenv, .gradle, .m2 | JAVA_HOME, JAVA_TOOL_OPTIONS, GRADLE_*, MAVEN_*, SDKMAN_*, JENV_* | java, gradle |
| Kotlin Native | .konan | нет | нет |
| Python | .pyenv | VIRTUAL_ENV, PYTHONPATH, PYENV_ROOT, PYENV_* | python3 |
| Yarn Berry | .yarn | YARN_* (укрепление переопределяет YARN_ENABLE_SCRIPTS) | yarn |
| pnpm | Library/pnpm, .local/share/pnpm | PNPM_HOME | pnpm |
| Corepack | нет | COREPACK_* | нет |
| mise | .local/share/mise, .mise | MISE_* | mise |
| Флаг | Что делает |
|---|
--doctor | Устарело. Используйте подкоманду cplt doctor вместо этого |
--print-profile | Вывести сгенерированный профиль песочницы (SBPL) и выйти |
--show-denials | Потоково выводить логи отказов песочницы macOS в реальном времени |
--no-validate | Пропустить проверку при запуске, которая удостоверяет, что ограничения песочницы активны |
-y, --yes | Пропустить интерактивный запрос подтверждения. Сводка конфигурации всё равно выводится, для аудируемости. Требуется, когда stdin не является TTY, так что CI и скриптам он нужен |
-q, --quiet | Подавить стартовый баннер и несущественные сообщения. Ошибки и предупреждения всё равно выводятся. Также sandbox.quiet = true в конфиге |
--no-quiet | Переопределить sandbox.quiet = true и всё равно показать стартовую сводку |
--no-audit | Пропустить отчёт об изменениях после сессии. cplt обычно сравнивает рабочее дерево с базовым коммитом, зафиксированным перед запуском, и перечисляет то, чего коснулась сессия, помечая чувствительные пути. -q тоже его подавляет |
--init-config | Создать стартовый файл конфигурации в ~/.config/cplt/config.toml и выйти |
| Флаг | Что делает |
|---|
--resume[=SESSION] | Возобновить предыдущую сессию. Голый --resume выбирает интерактивно, --resume=NAME выбирает по имени или ID |
--continue | Возобновить самую недавнюю сессию в текущем каталоге |
--remote | Включить удалённое управление, чтобы можно было наблюдать за сессией и управлять ею с GitHub.com или с мобильного |
--name SESSION | Назвать сессию, чтобы --resume=NAME мог найти её позже |
| Флаг cplt | Copilot | OpenCode | Antigravity (agy) | Claude Code |
|---|
--continue | --continue | --continue | --continue | --continue |
--resume | --resume | --continue¹ | --continue¹ | --resume |
--resume=ID | --resume=ID | --session ID | --conversation ID | --resume ID |
--remote | --remote | игнорируется | игнорируется | игнорируется |
--name NAME | --name NAME | игнорируется | игнорируется | игнорируется |
GOOGLE_API_KEYGEMINI_API_KEY--pass-env--observe-domains, поэтому его встроенный список разрешённых — это только общая база реестра пакетов. Добавьте домен вашего провайдера через allowed_domains перед включением --default-allowlistGOOSE_DISABLE_KEYRING=1 заставляет goose использовать secrets.yaml в его каталоге конфигурации вместо этого, а передача ключа через --pass-env полностью избегает сохранённых секретов. В Linux goose использует D-Bus Secret Service, на который разрешение Keychain не влияет~/.config/goose/config.yaml объявляет записи extensions:, чьи cmd goose запускает при каждом старте сессии, поэтому записываемый каталог конфигурации — это вектор сохранения на хосте. Обычные сессии в него не пишут; изменения /mode и сохранённые разрешения инструментов не сохраняются после запуска в песочнице. Перенастройте с помощью goose configure вне cplt~/.local/share/goose/) и состояния (~/.local/state/goose/) доступны для записи, с запретом на выполнение. goose использует эти пути XDG и в macOS, и учитывает там переопределения XDG_*--continue и голый --resume соответствуют goose session --resume; --resume=ID — goose session --resume --session-id ID; --name X — goose session --name X. Это флаги подкоманды, поэтому cplt внедряет подкоманду session вместе с ними. --remote игнорируется (нет эквивалента в goose)| Уровень | Принудительное применение | Обходится? | Что защищает |
|---|
| 1. Песочница ядра | macOS Seatbelt / Linux Landlock+seccomp | ❌ Нет | Доступ к файлам, exec, сетевые порты |
| 2. Сетевой прокси | CONNECT-прокси, фильтрация доменов | ❌ Нет (внутри песочницы) | Исходящие соединения, эксфильтрация |
| 3. Защита команд | Обёртки-скрипты на основе PATH | ⚠️ Мягкий барьер | Пуши, слияния, релизы, запись через API |
gitbwrapsandbox-execmiseghPATHcplt doctor: его проверки --version запускают каждый найденный в вашем PATH бинарник агента в родительском процессе, поэтому подложенный выполнится именно там — та же подверженность обнаруженному пути, что и при запуске выше, поэтому doctor — это отчёт, а не граница. Его проверка gh разрешается из доверенных каталогов, а чтение версии ядра вообще ничего не порождает| Команда | Действие |
|---|
gh pr merge, gh repo delete, gh release create | 🔒 Заблокировано |
git push origin main, git push --force | 🔒 Заблокировано |
gh api (запись в другие репозитории) | 🔒 Проверка области действия |
gh pr list, gh issue list, git commit | ✅ Разрешено |
git push origin feature-branch | ✅ Разрешено с protect_default_branch_only |
| Влияние | Исправление |
|---|
Файлы .env заблокированы | cplt config set sandbox.allow_env_files true |
| Хуки postinstall npm заблокированы | cplt config set sandbox.allow_lifecycle_scripts true |
go test / mise run заблокированы (временное исполнение) | Каталог scratch включён по умолчанию. Если он всё ещё нужен, cplt config set sandbox.allow_tmp_exec true |
| Соединения с localhost заблокированы | cplt config set allow.localhost 3000, или cplt config set sandbox.allow_localhost_any true |
| Docker заблокирован | cplt config set sandbox.allow_docker true ⚠️ |
| SSH заблокирован | Используйте HTTPS-ремоуты вместо этого |
| Подпись GPG отключена | cplt config set sandbox.allow_gpg_signing true |
| JVM MockK/Mockito не работает | cplt config set sandbox.allow_jvm_attach true |
Рабочие узлы MSBuild для dotnet build заблокированы | cplt config set sandbox.allow_msbuild true |
| Учётные данные приватного реестра заблокированы | cplt config set allow.read "~/.m2/settings.xml" |
| Внутренний репозиторий Maven/Nexus недоступен (Gradle/Maven) | cplt config set proxy.allow_private_domains "intern.example.com". URL репозитория в виде IP-литерала разрешить нельзя — дайте хосту DNS-имя; см. ниже |
| Playwright Chromium не запускается | Разрешите исполнение из кэша, затем отключите вложенную песочницу Chromium; см. ниже |