Песочница отвечает на вопрос, принципиально иной, чем режим работы. Режим решает, нужно ли спрашивать вас перед действием. Песочница решает, что процесс физически может прочитать, куда записать и куда подключиться. Это два независимых слоя: команду можно разрешить без вопросов и одновременно жёстко ограничить в том, к чему у неё есть доступ. Путать их - значит ждать от одного механизма того, что даёт другой, и обнаруживать нехватку в самый неудачный момент.
Конфигурация живёт в двух файлах: пользовательском и проектном, причём проектный имеет более высокий приоритет. Поверх них действуют административные и встроенные ограничения, которые нижний слой ослабить не может. Такая асимметрия намеренная: организация задаёт обязательный минимум, а проект уточняет его под свою специфику, но не может открыть то, что закрыто сверху. Практическое следствие - разбирая непонятный отказ, смотреть надо снизу вверх: сначала проектный файл, затем пользовательский, затем то, что задано администратором и не редактируется вовсе.
Полезно один раз увидеть цельную конфигурацию. Ниже - режим доступа к рабочей области, дополнительные пути на чтение, запрет записи во временный каталог и сетевая политика с явным списком разрешённых адресов. Читается она как описание границ: что можно трогать, куда можно писать и с кем можно разговаривать. Каждая строка здесь - это решение, а не украшение конфигурации.
Поля стоит понимать по смыслу, а не по названию. Тип задаёт базовый режим: запись в рабочую область, только чтение или отсутствие изоляции. Дополнительные пути расширяют доступ точечно - например, к соседнему пакету со схемами, который нужен для сборки. Запрет записи во временный каталог закрывает популярный обходной путь. А сетевая политика работает по принципу запрещено по умолчанию с явными исключениями - это единственная форма, которую можно объяснить в ревью.
| Поле | Что задаёт |
|---|---|
| type | Базовый режим: запись в рабочую область, только чтение или без изоляции |
| additionalReadwritePaths | Дополнительные пути на чтение и запись; действуют только при типе с правом записи |
| additionalReadonlyPaths | Дополнительные пути, доступные на чтение |
| disableTmpWrite | Запрет записи во временный каталог |
|---|
| enableSharedBuildCache | Разрешение на общий кэш сборки |
|---|
| networkPolicy | Поведение по умолчанию плюс списки разрешённого и запрещённого |
|---|
Разница между чтением и записью в дополнительных путях важнее, чем кажется, и хорошо видна на обычном сценарии. Сборке нужны схемы из соседнего каталога: их достаточно читать, поэтому путь добавляют в список только для чтения, и агент не сможет их изменить, даже если решит, что так задача решается проще. Ошибка в эту сторону дешёвая, а вот пропущенный путь узнаётся не сразу: отказ песочницы приходит в приложение как обычная ошибка среды - файл не найден, доступ запрещён, соединение не установлено. Выглядит как поломка проекта, а на деле это работающая политика, и первое, что стоит проверять при таких симптомах после её изменения, - сама политика.
Самое важное и самое пропускаемое - платформенные различия. На macOS изоляция строится одними средствами операционной системы, на Linux другими, и уровень поддержки зависит от ядра и настроек. При недостаточной поддержке часть действий может потребовать подтверждения или дополнительной настройки на уровне системы. Отсюда правило: политику проверяют на каждой операционной системе фактическим поведением, а не переносят по названию режима.
Проверять нужно негативным тестом, и это стоит сделать привычкой. После изменения политики попросите выполнить заведомо запрещённое безопасное действие: прочитать тестовый закрытый файл, обратиться к неразрешённому домену, записать туда, куда записывать не должно. Политика доказана только тогда, когда отказ наблюдается. Файл конфигурации, который выглядит строгим, но не проверен, - это предположение о безопасности, а не безопасность.
У песочницы есть граница применимости, и её лучше проговорить прямо. Она защищает машину от процесса, а не проект от агента. Внутри рабочей области с правом записи агент может переписать почти что угодно: удалить нужный файл, испортить миграцию, закоммитить полуготовое; неприкосновенным остаётся лишь узкий набор служебных файлов: конфигурация самого инструмента и редактора, файл исключений и служебные файлы репозитория вроде настроек и хуков системы контроля версий. Изоляция при этом отработает безупречно - именно это ей и разрешили. Значит, от неверных правок защищает другой слой: узкая задача, просмотр diff, тесты и система контроля версий, из которой изменение можно откатить. Ждать от песочницы качества кода - та же подмена, что ждать от подтверждений безопасности файловой системы.
Инженерный вывод простой: сначала узкая граница, потом удобство. Расширять доступ дешевле, чем сужать после инцидента, и каждое расширение стоит делать точечным - конкретный путь, конкретный домен. Соблазн выключить изоляцию целиком, чтобы не мешала, понятен, но он превращает управляемую границу в её отсутствие.
Типичные провалы предсказуемы. Спутать песочницу с подтверждениями и ждать от одной того, что даёт другое. Перенести политику с macOS на Linux по названию и не проверить фактическое поведение. Оставить открытую запись во временный каталог как обходной путь. Принять отказ политики за поломку проекта и чинить не то. И не выполнить негативный тест, приняв текст конфигурации за доказательство.
// .cursor/sandbox.json - проектный файл важнее пользовательского
{
"type": "workspace_readwrite",
"additionalReadonlyPaths": ["../shared-schemas"],
"additionalReadwritePaths": [],
"disableTmpWrite": false,
"networkPolicy": {
"default": "deny",
"allow": ["registry.npmjs.org", "*.github.com"],
"deny": []
}
}