fix(skills): исправлена настройка песочницы Codex через AppArmor

- Зачем:
  - Профили на пути установки Codex ломались после переустановки, а прежние проверки могли давать ложный успех.
- Что:
  - Штатный профиль системного bwrap выбран основным способом настройки; исторические обходы ограничены подтверждёнными случаями.
  - Уточнены диагностика, переход со старых профилей и проверки режимов и границ записи.
  - Обновлены связанные инструкции и записан результат применения на Ubuntu 24.04.4 с Codex 0.154.0.
- Проверка:
  - Пройдены quick_validate, проверка ссылок, синтаксиса Bash и git diff --check.
  - Штатный профиль применён; старые профили выгружены. Оба режима и запреты записи проверены из процесса unconfined; подтверждены метки AppArmor у bwrap и дочерней команды.
This commit is contained in:
Dmitry Dementiev committed 2026-09-10 14:56:36 +03:00
1 parent 67aa5e67d5
commit 26fdb7584c
3 files changed
+162 -127

No files matched your search

@@ -15,10 +15,10 @@ WSL2 Ubuntu: exec/resume/`-o`/фоновый Bash — весь конвейер)
## Сквозные правила (любая ветка)
- **Предполёт — один раз на новой машине или в новом харнессе.** Две
проверки. Песочница: диагностика из
[codex-sandbox-apparmor.md](codex-sandbox-apparmor.md) (сигнатура поломки
и лечение — там же). Вывод доходит до файла: `codex --version > f;
- **Предполёт — на новой машине, в новом харнессе и после обновления или
переустановки Codex.** Две проверки. На Linux/WSL песочница: оба режима
и границы записи по [codex-sandbox-apparmor.md](codex-sandbox-apparmor.md).
Вывод доходит до файла: `codex --version > f;
wc -c f` — непусто значит, что рецепты ниже работают как написаны. Пусто:
среда теряет унаследованный файловый дескриптор, и на входе, и на выходе
(известный случай — T3 Code, [lessons.md](lessons.md) 2026-08-06); тогда
@@ -118,14 +118,12 @@ WSL2 Ubuntu: exec/resume/`-o`/фоновый Bash — весь конвейер)
`jq`, редиректы под Windows работают). `$SCRATCH` задавай
forward-slash-путём (`/c/Users/...`), не `C:\...`; пути в аргументах
кавычь; в выводах под Windows возможны `\r`.
- **Linux: sandbox может молча сломаться обновлением Codex.** Сигнатура:
web_search работает, а `pwd` внутри песочницы — нет
(`bwrap: loopback: Failed RTM_NEWADDR`). Обход без sudo
`use_legacy_landlock=true` чинит только read-only, write-режим с ним
паникует; полный фикс — AppArmor-профиль, и он под sudo: сам не применяй,
дай пользователю готовые команды из
[codex-sandbox-apparmor.md](codex-sandbox-apparmor.md) (`!`-префикс в чат),
после применения профиля напомни убрать `use_legacy_landlock`.
- **Linux: shell-команды падают до запуска, хотя web_search работает.**
При ошибке bwrap, в том числе `Failed RTM_NEWADDR`, сначала установи
причину и фактический способ запуска по
[codex-sandbox-apparmor.md](codex-sandbox-apparmor.md). Там же — штатная
настройка, переход со старого обхода и критерий готовности. При провале
предполёта сначала восстанови среду, затем запускай рабочие задачи.
- **Блок классификатора — сначала сузь песочницу, потом зови пользователя.**
Первая проверка: нет ли в команде `-s danger-full-access` — классификатор
его блокирует, и он не нужен (почему — в ветке исполнителя). Если блок не
@@ -1,120 +1,157 @@
# Sandbox Codex на Linux: диагностика и починка (bwrap/AppArmor)
# Песочница Codex на Linux: проверка и настройка AppArmor
Справочник: симптомы, корень и рецепты фикса поломки песочницы Codex CLI
на Linux с AppArmor (эмпирика Ubuntu 24.04, 2026-07-10). Самодостаточен.
Читай при первом запуске на Linux/WSL, после смены версии или установки
Codex и при отказе команд внутри песочницы. Основной путь — системный
`bwrap` со штатным профилем AppArmor. Способ запуска проверяй по фактам:
номер версии сам по себе не доказывает выбор встроенного или системного bwrap.
## Симптом
## 1. Проверь запуск в нужной среде
Любая команда внутри sandbox Codex падает **до запуска процесса**, даже `pwd`:
```
bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted
```
Проявляется и в read-only, и в workspace-write. Codex не может ни читать файлы через shell, ни выполнять команды — задачи либо виснут, либо честно завершаются отказом.
## Корневая причина (подтверждена kernel audit log)
**Codex CLI 0.144.1 (npm) сменил Linux-sandbox backend**: раньше был Landlock/seccomp без user namespaces, теперь — vendored bubblewrap (`…/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/codex-resources/bwrap`), который создаёт unprivileged user namespace + network namespace.
Ubuntu 24.04 с `kernel.apparmor_restrict_unprivileged_userns = 1` загоняет такой userns в запретительный AppArmor-профиль `unprivileged_userns`, который блокирует два шага, нужных bwrap: запись `/proc/PID/uid_map` и `RTM_NEWADDR` (поднятие loopback). Доказательство из audit log:
```
apparmor="AUDIT" operation="userns_create" comm="bwrap" profile="unconfined" target="unprivileged_userns"
apparmor="DENIED" operation="open" name="proc/…/uid_map" profile="unprivileged_userns" denied_mask="wr"
```
Важные отрицательные результаты (экономят время диагностики):
- **Плагин openai-codex (1.0.5 → 1.0.6) ни при чём** — он лишь передаёт режимы sandbox бинарю codex; даунгрейд плагина не помогает.
- Системный `/usr/bin/bwrap` падает так же — это не баг vendored-сборки.
- Система не менялась (машина без ребута 14 недель, политика AppArmor старая) — это дрейф самого Codex CLI, прилетевший с обновлением npm-пакета.
## Применённый фикс без sudo (обратимый)
В `~/.codex/config.toml` добавлено:
```toml
[features]
use_legacy_landlock = true
```
Backup рядом: `~/.codex/config.toml.bak-20260710`. Откат — восстановить backup или удалить две строки.
## Проверка (сквозная, через codex-companion)
- Read-only задача `task --wait --fresh` («pwd + первая строка /etc/os-release») — команды выполняются, вернула корректные значения.
- **web_search работает**: задача сходила на github.com/openai/codex/releases. Нюанс: сетевой доступ из *shell-команд внутри sandbox* по-прежнему закрыт (`npm view` виснет) — это корректный read-only режим; инструмент web_search исполняется вне sandbox и не страдает.
- Изоляция сохранена: запись вне workspace запрещена.
## Известное ограничение фикса
`use_legacy_landlock` чинит **только read-only**. Режим `--write`/workspace-write с этим флагом **паникует**:
```
permission profiles requiring direct runtime enforcement are incompatible with --use-legacy-landlock
```
— workspace-write требует именно bwrap-backend. Полный фикс — ниже, нужен sudo.
## Полный фикс (sudo; применён и проверен 2026-07-10)
**Ловушка, съевшая первую попытку**: профиль на путь vendored bwrap
(`**/codex-resources/bwrap`) НЕ работает — Codex ≥0.144 исполняет
**встроенный** bwrap из memfd (`linux-sandbox/src/bundled_bwrap.rs`,
`memfd_create` в бинаре), и путевой attachment не цепляется никогда: в audit
виден `profile="unconfined" comm="bwrap"` → transition в
`unprivileged_userns`. Прямой запуск vendored bwrap с диска при этом
проходит — ложное подтверждение, не верь ему.
**Рабочий вариант**: вешать профиль на **сам бинарь codex** (родителя) —
memfd-exec'нутый ребёнок наследует метку через exec, и правило `userns,`
разрешает namespace. Стандартный приём Ubuntu для браузеров/Electron.
`/etc/apparmor.d/codex-bwrap`:
```
abi <abi/4.0>,
include <tunables/global>
profile codex-cli /home/dmitry/.npm-global/lib/node_modules/@openai/codex/**/bin/codex flags=(unconfined) {
userns,
include if exists <local/codex-cli>
}
profile codex-bwrap /home/dmitry/.npm-global/lib/node_modules/@openai/codex/**/codex-resources/bwrap flags=(unconfined) {
userns,
include if exists <local/codex-bwrap>
}
```
Загрузить: `sudo apparmor_parser -r /etc/apparmor.d/codex-bwrap`. После этого **убрать** `use_legacy_landlock` из config.toml и проверить оба режима:
```
codex sandbox -c 'sandbox_mode="workspace-write"' -- sh -c 'touch ./__p && rm ./__p && echo OK'
codex sandbox -- sh -c 'touch ./__p 2>/dev/null && echo BROKEN || echo RO_OK'
```
Проверено 2026-07-10: WRITE_OK, read-only блокирует запись, workspace-write
не пускает в `/etc` — изоляция сохранена.
Переносимость: путь в профиле — под конкретную машину (`~/.npm-global/...`); glob `**` переживает обновления версий Codex, но если npm-global живёт в другом месте — путь поправить. Перезагружать профиль нужно только при смене самого расположения.
**Вариант B — грубый, не рекомендуется**: `sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0` (+ файл в `/etc/sysctl.d/`). Ослабляет защиту всей машины.
## Диагностические команды для другой машины
Из рабочего каталога проекта выполни оба вызова тем же способом, которым
будет запущен исполнитель или ревьюер:
```bash
codex --version # 0.144.1+ → bwrap-backend
sysctl kernel.apparmor_restrict_unprivileged_userns # 1 → будет блокировка
bwrap --ro-bind / / --unshare-net --dev /dev --proc /proc true && echo BWRAP_OK
sudo dmesg | grep -iE 'apparmor.*(userns|bwrap)' | tail # AUDIT/DENIED — подтверждение
codex sandbox -c 'sandbox_mode="read-only"' -- sh -c 'pwd && echo READ_OK'
codex sandbox -c 'sandbox_mode="workspace-write"' -- sh -c \
'set -eu; probe=$(mktemp ./.codex-sandbox-check.XXXXXX); rm -- "$probe"; echo WRITE_OK'
```
## Связанные записи
Успех — нулевой код выхода и соответствующий маркер от каждой команды.
Это проверка запуска; проверка запретов записи — в разделе 4.
Работающий `web_search` ничего не говорит о выполнении shell-команд.
Принесено 2026-07-10 из ветки `codex-sandbox-fix-20260710` (исходная машина —
Ubuntu 24.04; там сжатая версия жила в codex-companion.md, который в основной
линии уже поглощён codex-exec.md). Сжатая версия урока здесь — в
[codex-exec.md](codex-exec.md), сквозное правило «Linux: sandbox может молча
сломаться обновлением Codex»; датированная запись — в
[lessons-archive.md](lessons-archive.md).
Если в конфигурации остался `use_legacy_landlock=true`, для проверочных
вызовов добавь `-c 'features.use_legacy_landlock=false'`: проверяем штатную
песочницу, а не старый обход.
## 2. Установи причину отказа
`bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted` — повод
проверить AppArmor, но не достаточный диагноз. Собери:
```bash
codex --version
cat /etc/os-release
type -a codex bwrap
sysctl kernel.apparmor_restrict_unprivileged_userns
cat /proc/self/attr/current
```
Проверь журнал ядра за время неудачного вызова: записи `apparmor="DENIED"`
для `userns_create`, `uid_map` или настройки сети подтверждают ограничение
AppArmor. Отсутствие доступа к журналу — пробел в диагностике, а не
доказательство причины. При отказе доступа к
`codex-bwrap-synthetic-mount-targets` сравни минимальный вызов из среды
агента и из обычного терминала хоста. Если на хосте он работает, исследуй
ограничения внешней песочницы и способ запуска агента; профиль AppArmor
пока не считай причиной. Если вызов падает и на хосте, а причина по
доступным данным не установлена, сохрани точную ошибку и результаты обоих
запусков; запроси недостающие записи журнала за это время. До подтверждения
причины рецепт AppArmor не применяй.
По [документации OpenAI](https://learn.chatgpt.com/docs/sandboxing#prerequisites)
Codex выбирает первый `bwrap` из `PATH`, а при его отсутствии использует
встроенный. Проверяй `PATH` именно запускающего процесса: оболочка,
редактор и агент могут видеть разные установки. При расхождении с этим
поведением установи фактический исполняемый файл дочернего bwrap через
`/proc/<pid>/exe` или трассировку `execve`/`execveat`; одного `command -v`
для этого недостаточно.
## 3. Настрой системный bwrap
Если подтверждена блокировка AppArmor, используй пакет `bubblewrap` и
профиль `bwrap-userns-restrict` из дистрибутива. Путь в профиле должен
соответствовать фактически запускаемому bwrap. При другой копии в `PATH`
сначала приведи запуск к системной установке.
Для Ubuntu 24.04 официальный рецепт использует пакеты:
```bash
sudo apt update
sudo apt install bubblewrap apparmor-profiles apparmor-utils
```
Если `/etc/apparmor.d/bwrap-userns-restrict` уже существует, изучи его;
локальные изменения сохрани. Если файла нет, проверь наличие штатного
образца и установи его:
```bash
test -f /usr/share/apparmor/extra-profiles/bwrap-userns-restrict && \
sudo install -m 0644 /usr/share/apparmor/extra-profiles/bwrap-userns-restrict \
/etc/apparmor.d/bwrap-userns-restrict
```
Загрузи профиль без перезагрузки машины:
```bash
sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict
```
В Ubuntu 25.04 профиль поставляется пакетом `apparmor`; на других выпусках
проверь состав пакетов. Если образца нет или загрузка не удалась, останови
этот рецепт и выясни совместимость пакетов и AppArmor по документации
дистрибутива. Отсутствующий профиль не заменяй расширением разрешений всей
машины или отключением песочницы.
Установка пакетов и изменение профилей — настройка машины. Выполняй её в
пределах уже разрешённой задачи; если настройка среды не разрешена, сначала
подготовь конкретные команды по результатам диагностики и запроси согласие.
## 4. Проверь результат и убери старый обход
Повтори оба вызова из раздела 1. Затем проверь границы записи, явно задавая
режим каждому вызову:
- `read-only`: чтение работает, создание временного файла внутри проекта
запрещено.
- `workspace-write`: создание и удаление временного файла внутри проекта
работает; запись за пределами разрешённых каталогов запрещена.
Для проверки запрета используй отдельный временный каталог, в который тот
же пользователь может записать вне проверяемой песочницы. Отказ засчитывай
только после успешного запуска команды и как запрет доступа, а не любую
ошибку. `/etc` не подходит: запись туда обычно запрещена уже правами Unix;
`/tmp` не подходит для проверки внешнего запрета, если разрешён политикой.
Удали только созданные проверкой файлы и каталоги.
Если раньше был установлен профиль на бинарь Codex (например,
`codex-bwrap` с секциями `codex-cli*`), одного успешного прогона недостаточно:
дочерние процессы могут наследовать его разрешения. При переходе сохрани
старый профиль для отката, выведи его из автозагрузки и выгрузи его секции
из ядра. Запусти проверку из новой оболочки, не унаследовавшей старую метку
AppArmor, и новым процессом Codex. Продолжение прежней сессии не доказывает
независимость от обхода. При неудаче восстанови старую настройку и сохрани
диагноз; переход не завершён.
Готово, когда оба режима и запреты записи проверены, а при переходе со
старого профиля — ещё и подтверждена независимость от него. После этого
убери оставшийся `use_legacy_landlock` из конфигурации. Если системная
настройка не выполнялась, различай «инструкция подготовлена» и
«песочница на этой машине исправлена».
## Исторические обходы и границы применимости
- **2026-07-10, Codex 0.144.1, Ubuntu 24.04.** Наблюдался запуск встроенного
bwrap через `memfd`: профиль на дисковый файл bwrap не применялся.
Профиль на сам бинарь Codex с разрешением `userns` помог. Это запасной
вариант для подтверждённого встроенного запуска, если перейти на
поддерживаемый системный bwrap нельзя; путь определяют на конкретной
машине, ограничивая его текущей установкой.
- **Тогда же:** `use_legacy_landlock=true` помогал read-only, но
workspace-write завершался ошибкой несовместимости. Для конвейера,
которому нужна запись, это не решение.
- **2026-09-10, Codex 0.154.0.** Смена npm-установки на standalone вывела
бинарь из-под старого профиля; добавление второго пути устранило симптом.
Затем этот рецепт применён на Ubuntu 24.04.4: штатный профиль из
`apparmor-profiles` 4.0.1really4.0.1-0ubuntu0.24.04.7 установлен без
изменений, старые профили Codex выгружены и убраны из автозагрузки.
Из процесса `unconfined` проверены чтение, запрет записи в read-only,
запись внутри workspace-write и запрет снаружи; перед проверкой обычная
пользовательская запись в оба временных каталога проходила.
Через `/proc` подтверждены `/usr/bin/bwrap` с меткой `bwrap (enforce)`
и дочерняя команда с `bwrap//&unpriv_bwrap (enforce)`.
`apparmor_restrict_unprivileged_userns=1` сохранён, legacy-обход отсутствует.
Наблюдения относятся к указанным установкам, а не ко всем версиям Codex.
Штатный рецепт и состав пакетов сверены с документацией OpenAI 2026-09-10.
Связанная запись: [lessons-archive.md](lessons-archive.md).
@@ -55,9 +55,9 @@
- Ревьюер Codex без read-only: мандат промптом надёжен, песочница не режется.
Поглощено: codex-exec (ветка ревьюера).
- Sandbox-инцидент CLI 0.144.1 (bwrap+userns vs AppArmor) и ловушка memfd
(профиль на путь bwrap не цепляется — вешать на бинарь codex). Поглощено:
codex-exec + codex-sandbox-apparmor.md.
- Sandbox-инцидент CLI 0.144.1 (bwrap+userns vs AppArmor): при наблюдавшемся
запуске через memfd помог профиль на бинарь Codex. Актуальная настройка
и границы этого обхода — в [codex-sandbox-apparmor.md](codex-sandbox-apparmor.md).
- Постановка через `/to-tickets` ложится в конвейер без трения; двойное
слепое ревью постановки окупилось (Клод — механика кода, Codex — уровень
требований; пересечение 2 из ~15). Поглощено: SKILL.md этапы 1–2.