Бэкенды песочницы
Обзор бэкендов
Заголовок раздела «Обзор бэкендов»| Бэкенд | Значение | Платформа | Доступность |
|---|---|---|---|
| Изолированная VM | microvm |
macOS, Linux, Windows (гипервизор microVM) | Допускается только после проверки среды выполнения microVM; применяется к интерактивным терминалам — оболочка работает внутри rig, а не на хосте |
| Нативная песочница | native |
macOS (Seatbelt), Linux и WSL2 (bubblewrap) | Проверяется при загрузке; Linux отказывает запуску, который требует запретов записи по glob-шаблонам имён файлов, — их bubblewrap обеспечить не может |
| Без изоляции | none |
Все | Значение по умолчанию при разборе, значение по умолчанию терминала и запасной вариант, когда бэкенд недоступен или задан --sandbox off |
SandboxBackend.fromName возвращает none для пустого или нераспознанного сохранённого значения. Сохранённое "docker" отображается на native.
microvm — единственный бэкенд с границей ядра — рабочая нагрузка
действительно не выполняется на хосте. Он никогда не бывает тихим запасным
вариантом ни в одну, ни в другую сторону: явный запрос его на хосте, который не
может загрузить VM, завершается громкой ошибкой («я просил VM, а получил свой
ноутбук» — единственная деградация, которую изолирующая среда не может себе
позволить), и только неуказанное значение по умолчанию опускается до
native, о чём сообщает строка журнала. Фактический бэкенд сессии сообщается
обратно клиенту и помечается значком, поэтому терминал никогда не может
заявить, что он изолирован, работая на хосте. Жизненный цикл, образы и
исходящий трафик самой VM описаны в справочнике по rig.
В Windows нет нативной песочницы. NativeSandboxAdapter.probe возвращает available: false на любом хосте, который не является macOS или Linux/WSL2. Поэтому диспетчеризация агента в Windows использует none. Бэкенд microvm отдельный: он допускается только после проверки среды выполнения microVM и применяется к интерактивным терминалам и rig, а не к обёртке bash на хосте.
Результаты проверки
Заголовок раздела «Результаты проверки»Именно проверка управляет принуждением. Она выполняется один раз, при загрузке сервера.
| Хост | available |
Заметка / подсказка |
|---|---|---|
| macOS | true |
sandbox-exec (Seatbelt) — изоляция пространств имён, без границы ядра |
Linux или WSL2 с bwrap и socat |
true |
bubblewrap — изоляция пространств имён, без границы ядра |
| Linux или WSL2, где нет одного из инструментов | false |
requiresInstall: true, с подсказкой об установке, называющей недостающие пакеты |
| Любая другая платформа | false |
Нативная песочница на этой платформе не предлагается |
Сервер записывает результат в одну строку при запуске: agent sandbox ON плюс заметка, no OS-native agent sandbox on this host плюс подсказка или agent sandbox DISABLED by --sandbox off. GET /healthz не содержит поля песочницы.
--sandbox / CC_SERVER_SANDBOX принимает on (по умолчанию) или off. Это отказ, а не включение: on означает «обернуть, когда хост предлагает бэкенд», а не «требовать его».
Нативный бэкенд
Заголовок раздела «Нативный бэкенд»macOS: Seatbelt
Заголовок раздела «macOS: Seatbelt»Использует механизм песочницы Seatbelt от Apple (ту же систему, что и macOS App Sandbox).
Создаваемый профиль по умолчанию разрешающий ((allow default)) и вырезает из него запреты, потому что полностью запрещающий по умолчанию профиль делает интерактивную оболочку непригодной — вызовов dyld, XPC и Mach слишком много, чтобы их перечислить. Практическое следствие: агент по-прежнему может читать большую часть хоста; ваши зарегистрированные рабочие копии защищены явными запретами записи и переименования, а не невидимостью.
- Чтение файловой системы: запрещено для секретных путей (
~/.ssh,~/.aws,~/.gnupg,~/.config/gh,~/Library/Keychainsи остального набора запрета чтения) - Запись в файловую систему: сбрасывается в запрет, затем следуют явные разрешения для подпутей, а пути с обязательным запретом (файлы rc оболочки,
.git/hooks, конфигурация Claude, защищённые рабочие копии) заблокированы даже внутри записываемого корня.file-write-unlinkзапрещён для каждого запрещённого пути и его предков, поэтому переименование не может обойти запрет записи - Процессы: запреты
process-execдля всегда опасных бинарников плюс блокировка выполнения чего угодно из записываемого каталога - Сеть: ограничена портами внутрипроцессных прокси плюс DNS — loopback не разрешён огульно, а Unix-сокеты не разрешены. Прокси обеспечивают доменный список разрешённых для каждой сессии (см. Исходящий сетевой трафик)
- Конфигурация: профили создаются при каждом запуске из
SandboxSpec
Требования:
sandbox-exec(/usr/bin/sandbox-exec), входит в любую установку macOS — дополнительный инструментарий не нужен
Linux: bubblewrap
Заголовок раздела «Linux: bubblewrap»Использует bubblewrap (bwrap) для создания пространств имён монтирования и PID.
- Файловая система: создаёт пространство имён монтирования, в котором видны только привязанные пути
- Сеть: работает в отдельном пространстве имён сети; трафик достигает хостовых прокси через мосты
socatна Unix-сокетах - Процессы: изоляция пространства имён PID
Требования:
- Установленные
bubblewrapиsocat(sudo apt-get install bubblewrap socatв Debian/Ubuntu) - Поддержка пространств имён ядром (стандартна для современного Linux)
Bubblewrap может заслонить существующий путь, но не может запретить новый файл
.env, *.key или *.pem внутри записываемого bind-монтирования. Стандартная
политика диспетчеризации требует таких запретов по glob-шаблонам имён файлов,
поэтому нативная диспетчеризация агента сейчас завершается ошибкой в
Linux/WSL2, даже когда проверка находит bubblewrap. Она не работает с молча
ослабленной политикой. Чтобы вернуть нативную диспетчеризацию в Linux, нужен
бэкенд с правилами имён файлов на момент создания. Отключение песочницы — это
явный отказ от изоляции, а не равноценный обходной путь.
Бэкенд без изоляции
Заголовок раздела «Бэкенд без изоляции»Никакой изоляции. Процесс выполняется напрямую на хосте с доступом хоста к файловой системе, сети и процессам. ACP и инструмент bash харнесса всё равно получают очистку окружения и политику команд; Claude Code через NoSandboxAdapter наследует окружение хоста. К этому диспетчеризация агента откатывается на хосте без доступного бэкенда или при --sandbox off, и это значение по умолчанию терминала, когда клиент не называет ни одного бэкенда.
Терминал, размещённый на сервере
Заголовок раздела «Терминал, размещённый на сервере»Терминал изолируется по своим собственным правилам, а не по проверке диспетчеризации. defaultBackend у TerminalSessionService равен none, и cc_server его не переопределяет, поэтому сессия терминала запускает оболочку хоста, если клиент явно не запросит native, — а панель терминала настольного приложения этого не делает.
Когда запрошен native, оболочка оборачивается через SandboxManager по фиксированному профилю терминала: $HOME и рабочий каталог сессии доступны для записи, сеть открыта, а ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh и ~/Library/Keychains запрещены для чтения. Токен хоста кода только для чтения и шлюз push не применяются — это забота диспетчеризации. Если обёртка не поддерживается, сессия завершается ошибкой, а не показывает значок нативной песочницы на PTY оболочки хоста.
Исходящий сетевой трафик
Заголовок раздела «Исходящий сетевой трафик»Когда песочница запускается, исходящий сетевой доступ обеспечивается внутрипроцессными прокси, а не правилами межсетевого экрана ядра. На хосте без доступного бэкенда ничего из этого не применяется, и порождённый процесс выходит в сеть точно так же, как это делал бы пользователь сервера.
- Среда выполнения песочницы запускает прокси HTTP/HTTPS и прокси SOCKS5 на
127.0.0.1внутри процессаcc_server, по одной паре на ограниченную сессию (http_proxy.dart,socks_proxy.dart). Параллельные запуски не делят одну пару. - Изолированные процессы получают переменные окружения прокси (
HTTP_PROXY/HTTPS_PROXY→ прокси HTTP,ALL_PROXY→ прокси SOCKS;GIT_SSH_COMMANDнаправляет git-over-SSH через прокси SOCKS). В Linux пространство имён сети отделено, поэтому прокси — единственный выход; в macOS песочница делит с хостом loopback и обращается к ним напрямую. - Целевой хост каждого подключения сверяется с доменным списком разрешённых для сессии; всё остальное отклоняется. Есть две формы шаблонов, в каждой ровно один
*: ведущий*.example.comсовпадает с любым поддоменом (включаяa.b.example.com), но не с самим доменом верхнего уровня;bedrock.*.amazonaws.comсо звёздочкой в середине совпадает ровно с одной меткой (bedrock.us-east-1.amazonaws.com, но неbedrock.evil.attacker.amazonaws.com). - Список разрешённых собирается для каждой сессии из подобранной базовой линии (
kBaselineAllowedDomains: провайдеры LLM, хостинг Git, реестры пакетов), плюс домены GitHub (kGithubDomains), плюсSandboxSpec.egressAllowlist. Путь диспетчеризации никогда не передаёт дополнительные записиegressAllowlist, поэтому на практике каждый запуск получает базовую линию плюс GitHub. - Фиксированный список запрещённых (
kBaselineDeniedDomains: конечные точки метаданных облака, приёмники телеметрии) имеет приоритет над всеми разрешениями. networkEnabled: falseвсё равно запускает прокси для каждой сессии, но список разрешённых пуст, поэтому каждое исходящее подключение отклоняется. Диспетчеризация задаёт это значение при старте запуска по правилу Обращаться к сети: запрет выключает сеть, разрешить и спросить сначала оставляют её включённой.
SandboxSpec
Заголовок раздела «SandboxSpec»Спецификация, передаваемая в SandboxPort.launch:
| Поле | Тип | Описание |
|---|---|---|
sessionId |
String |
Стабильный идентификатор сессии (обычно id пространства) |
workspaceId |
String |
Id владеющего рабочего пространства |
agentId |
String? |
Агент, привязанный к песочнице в данный момент, если есть |
bindMounts |
List<SandboxBindMount> |
Монтирования хост→гость; песочница видит только перечисленные здесь пути хоста |
networkEnabled |
bool (по умолчанию true) |
Задаётся при диспетчеризации по правилу исходящего сетевого трафика (выключено, только когда оно разрешается в запрет). Когда выключено, прокси для каждой сессии всё равно запускаются, но список разрешённых пуст, поэтому каждое исходящее подключение отклоняется |
egressAllowlist |
List<String> (по умолчанию []) |
Дополнительные разрешённые домены исходящего трафика; поддерживаются шаблоны (*.example.com, а также форма со звёздочкой в середине на одну метку). Диспетчеризация никогда его не заполняет, поэтому обёрнутый запуск получает подобранную базовую линию плюс домены GitHub |
guestWorkdir |
String? |
Рабочий каталог по умолчанию внутри песочницы; отдельные вызовы exec могут его переопределить |
mode |
Mode (по умолчанию chat) |
Определяет правила записи в файловую систему: chat оставляет bind-монтирования доступными для записи; review, plan и orchestrate — только для чтения |
protectedPaths |
List<String> (по умолчанию []) |
Пути хоста, которые никогда не должны быть доступны для записи внутри песочницы, ни в каком режиме |
runnerStateDirs |
List<String> (по умолчанию []) |
Каталоги хоста, в которых раннер хранит собственное состояние, доступные для записи в любом режиме (сейчас это CLAUDE_CONFIG_DIR, управляемый Control Center) |
execGrantRoots |
List<String> (по умолчанию []) |
Одобренные оператором деревья каталогов, которые вновь открывают блокировку exec из записываемого каталога в macOS. Linux их игнорирует — у bwrap нет блокировки exec по $HOME, которую можно вновь открыть |
protectedPaths содержит исходные зарегистрированные рабочие копии репозиториев,
определяемые при каждой диспетчеризации из репозиториев рабочего пространства.
Агенты работают исключительно в worktree с копированием при записи для каждого
разговора, поэтому оригиналы никогда не должны быть доступны для записи изнутри
песочницы — иначе в macOS огульное разрешение записи в $HOME у Seatbelt
оставило бы их доступными для записи через bash. Они присоединяются к набору
запрета записи для секретов в любом режиме, включая chat.
Каждый путь запрета чтения и запрета записи выдаётся в двух написаниях —
буквальном и после разрешения символических ссылок. Ядро сопоставляет правило
запрета с разрешённым путём, поэтому правило, написанное для пути через
символическую ссылку, никогда не срабатывает — а в macOS это обычный случай, а не
экзотический, поскольку /tmp разрешается в /private/tmp, а /var/folders/… —
в /private/var/folders/…. Записи, содержащие * или ?, считаются
glob-шаблонами и не трогаются; путь, который не разрешается, сохраняется как
написан.
SandboxBindMount
Заголовок раздела «SandboxBindMount»| Поле | Тип | Описание |
|---|---|---|
hostPath |
String |
Абсолютный путь на хосте |
guestPath |
String |
Путь внутри песочницы (в нативной песочнице совпадает с hostPath; сохранён для единообразия адаптеров) |
readOnly |
bool (по умолчанию false) |
Монтировать только для чтения, когда истинно |
SandboxHandle
Заголовок раздела «SandboxHandle»Возвращается методом SandboxPort.launch:
| Поле | Тип | Описание |
|---|---|---|
sessionId |
String |
Идентификатор сессии |
backend |
SandboxBackend |
Какой бэкенд работает |
state |
SandboxState |
Состояние жизненного цикла |
error |
Object? |
Заполняется, когда state равен error |
details |
Map<String, Object?> |
Служебные данные, приватные для адаптера (рабочий каталог, PID, путь к профилю и т. д.) |
SandboxState
Заголовок раздела «SandboxState»| Состояние | Описание |
|---|---|
created |
Спецификация создана, но VM ещё не запущена |
warm |
Работает и готова выполнять команды |
active |
В данный момент выполняет команду |
suspended |
Приостановлена / сохранена на диск контрольной точкой для экономии ОЗУ |
destroyed |
Свёрнута; дескриптор больше недействителен |
error |
Запуск не удался — см. SandboxHandle.error |
События песочницы
Заголовок раздела «События песочницы»| Тип события | Описание |
|---|---|
stdout |
Стандартный вывод из песочницы |
stderr |
Стандартный вывод ошибок из песочницы |
exit |
Процесс песочницы завершился (несёт exitCode) |
starting |
Песочница запускается |
ready |
Песочница готова принимать вызовы exec |
killed |
Процесс убит хостом (OOM, тайм-аут, ручная остановка) |
violation |
Нарушена политика песочницы (несёт SandboxViolation) |
SandboxViolation
Заголовок раздела «SandboxViolation»| Поле | Тип | Описание |
|---|---|---|
action |
String |
Запрещённый глагол (например, file-read*, network-outbound) |
target |
String |
Путь или хост, бывший целью запрещённой операции |
raw |
String? |
Необработанная строка журнала, полезная для отладки |
См. также
Заголовок раздела «См. также»- Песочница и безопасность
- Настроить политики песочницы
- Ограничения
- CLI cc_server: флаг
--sandbox