Перейти до вмісту

Бекенди пісочниці

Бекенд Значення Платформа Доступність
Ізольована ВМ microvm macOS, Linux, Windows (гіпервізор мікроВМ) Доступний лише після зондування середовища виконання мікроВМ; застосовується до інтерактивних терміналів — шел виконується всередині rig, а не на хості
Нативний native macOS (Seatbelt), Linux і WSL2 (bubblewrap) Зондується під час завантаження; Linux відмовляє в запуску, який вимагає заборон запису за глобом імені файлу, яких bubblewrap не може забезпечити
Немає none Усі Типове значення розбору, типове значення термінала та запасний варіант, коли жоден бекенд недоступний або задано --sandbox off

SandboxBackend.fromName повертає none для null або нерозпізнаного збереженого значення. Збережене "docker" зіставляється з native.

microvm — єдиний бекенд із межею ядра — робоче навантаження справді не виконується на хості. Він ніколи не буває тихим запасним варіантом у жодному напрямку: явний запит на нього на хості, який не може завантажити ВМ, гучно зривається («я просив ВМ, а отримав ноутбук» — це єдина деградація, яку оболонка не може собі дозволити), і лише незазначене типове значення знижується до native, про що є рядок у журналі. Фактичний бекенд сесії повертається клієнту й позначається бейджем, тож термінал ніколи не може стверджувати, що він ізольований, виконуючись на хості. Життєвий цикл, образи й вихідний трафік самої ВМ описано в довідці про rigs.

У Windows нативної пісочниці немає. NativeSandboxAdapter.probe повертає available: false на кожному хості, який не є macOS або Linux/WSL2. Тож диспетчеризація агентів у Windows використовує none. Бекенд microvm — окремий: він доступний лише після зондування середовища виконання мікроВМ і застосовується до інтерактивних терміналів і rigs, а не до загортання 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 означає «загортати, коли хост пропонує бекенд», а не «вимагати його».

Використовує механізм пісочниці 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 — додаткові інструменти не потрібні

Використовує bubblewrap (bwrap) для створення просторів імен монтування та PID.

  • Файлова система: створює простір імен монтування, у якому видно лише змонтовані шляхи
  • Мережа: працює в неспільному просторі імен мережі; трафік досягає проксі хоста через Unix-сокетні мости socat
  • Процеси: ізоляція простору імен PID

Вимоги:

  • Встановлені bubblewrap і socat (sudo apt-get install bubblewrap socat у Debian/Ubuntu)
  • Підтримка просторів імен ядра (стандартна в сучасному Linux)

Bubblewrap може затіняти наявний шлях, але не може заборонити новий файл .env, *.key чи *.pem усередині придатного для запису bind. Стандартна політика диспетчеризації вимагає цих заборон за глобом імені файлу, тож нативна диспетчеризація агентів наразі зривається із забороною за замовчуванням на Linux/WSL2, навіть коли зонд знаходить bubblewrap. Вона не виконується з тихо послабленою політикою. Щоб відновити нативну диспетчеризацію в Linux, потрібен бекенд із правилами імен файлів на етапі створення. Вимкнення пісочниці — це явна відмова від обмежень, а не рівноцінний обхідний шлях.

Жодної пісочниці. Процес виконується безпосередньо на хості, з доступом хоста до файлової системи, мережі та процесів. ACP та інструмент bash harness усе одно отримують очищення середовища й політику команд; 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 усе одно запускає проксі для сесії, але список дозволених порожній, тож кожне вихідне з’єднання відхиляється. Диспетчеризація задає це значення під час старту запуску за правилом Доступ до мережі: заборона вимикає мережу, дозволити й спочатку запитати залишають її ввімкненою.

Специфікація, яку передають у 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> (типово []) Каталоги хоста, у яких раннер тримає власний стан, доступні для запису в кожному режимі (нині це керований Control Center CLAUDE_CONFIG_DIR)
execGrantRoots List<String> (типово []) Схвалені оператором дерева каталогів, які знову відкривають блокування exec для каталогів із правом запису в macOS. Linux їх ігнорує — у bwrap немає блокування exec для $HOME, яке можна знову відкрити

protectedPaths містить оригінальні зареєстровані робочі копії репозиторіїв, розв’язані на кожну диспетчеризацію з репозиторіїв робочого простору. Агенти працюють виключно у власних worktree з copy-on-write для кожної розмови, тож оригінали ніколи не повинні бути доступними для запису зсередини пісочниці — інакше в macOS загальний дозвіл Seatbelt на запис у $HOME лишав би їх доступними для запису через bash. Вони долучаються до набору заборон на запис для секретів у кожному режимі, включно з chat.

Кожен шлях заборони читання й заборони запису видається і в буквальному написанні, і в розв’язаному через символьні посилання. Ядро зіставляє правило заборони з розв’язаним шляхом, тож правило, написане проти шляху із символьним посиланням, ніколи не спрацьовує — а в macOS це радше звичайний, ніж екзотичний випадок, адже /tmp розв’язується в /private/tmp, а /var/folders/… — у /private/var/folders/…. Записи, що містять * або ?, вважаються глобами й лишаються без змін; шлях, який не розв’язується, зберігається як написано.

Поле Тип Опис
hostPath String Абсолютний шлях на хості
guestPath String Шлях усередині пісочниці (з нативною пісочницею дорівнює hostPath; збережено для симетрії адаптерів)
readOnly bool (типово false) Монтувати лише для читання, коли true

Повертає SandboxPort.launch:

Поле Тип Опис
sessionId String Ідентифікатор сесії
backend SandboxBackend Який бекенд виконується
state SandboxState Стан життєвого циклу
error Object? Встановлюється, коли state дорівнює error
details Map<String, Object?> Внутрішній облік адаптера (робочий каталог, PID, шлях до профілю тощо)
Стан Опис
created Специфікацію створено, але ВМ ще не запущено
warm Виконується й готова приймати команди exec
active Наразі виконує команду
suspended Призупинено / знято контрольну точку на диск, щоб заощадити RAM
destroyed Згорнуто; дескриптор більше не чинний
error Запуск не вдався — див. SandboxHandle.error
Тип події Опис
stdout Стандартний вивід із пісочниці
stderr Стандартна помилка з пісочниці
exit Процес пісочниці завершився (несе exitCode)
starting Пісочниця запускається
ready Пісочниця готова приймати виклики exec
killed Процес убито хостом (OOM, тайм-аут, ручна зупинка)
violation Порушено політику пісочниці (несе SandboxViolation)
Поле Тип Опис
action String Заборонене дієслово (наприклад, file-read*, network-outbound)
target String Шлях або хост, що був ціллю забороненої операції
raw String? Сирий рядок журналу, корисний для зневадження