Перейти к содержанию

RunCommandTool и безопасный режим (Bubblewrap)

В этом документе описаны RunCommandTool (тул агента для выполнения shell-команд) и работа безопасного режима через Bubblewrap (bwrap) в Linux. Режим unsafe использует субпроцесс ОС напрямую и доступен на всех платформах.


1. Что это

RunCommandTool

RunCommandTool выполняет shell-команды (например, ls -la, python script.py). Два режима:

  • Safe (по умолчанию): Команда выполняется в песочнице Bubblewrap (bwrap): минимальный вид файловой системы (только чтение /usr, привязка workspace), пространства имён, без сети по умолчанию. Только Linux; требуется установленный bwrap. Если bwrap не найден, тул возвращает ошибку со ссылкой на инструкцию по установке.
  • Unsafe: Команда выполняется через ОС (asyncio subprocess). Можно задать workspace_path, чтобы процесс использовал эту директорию как текущую, а пути в аргументах не могли выйти за её пределы. Работает в Windows, macOS, Linux.

Итого: safe (по умолчанию) = изоляция bwrap (Linux); unsafe = субпроцесс ОС (все платформы).


2. Как это работает

Поток RunCommandTool

  1. Конфиг: В глобальной секции tools: или у агента: workspace_path (опционально), mode ("safe" или "unsafe"), timeout_seconds, include_paths (опциональный список разрешённых команд/путей), exclude_paths (опциональный список запрещённых команд/путей). Режим по умолчанию - safe. Если RunCommandTool используется где угодно (глобально или у любого агента) и workspace_path не задан для эффективного конфига, сервер создаёт директорию ./workspace рядом с config.yaml и использует её как рабочую.
  2. LLM: Агент передаёт в тул строку commandreasoning).
  3. Проверка: Если заданы include_paths или exclude_paths, тул проверяет, что исполняемый файл команды и пути в аргументах разрешены. Команды сопоставляются по имени (например, "ls") или по полному пути (например, /usr/bin/ls). include_paths имеет приоритет над exclude_paths: если путь есть в обоих списках, он разрешён.
  4. Unsafe: Тул разрешает workspace_path (если задан), проверяет пути в аргументах, затем запускает sh -c "<command>" с cwd=workspace_path и таймаутом. Возвращает форматированные stdout, stderr и код возврата.
  5. Safe: Тул проверяет наличие bwrap (например, which bwrap). Если нет - возвращает ошибку со ссылкой на установку Bubblewrap. Если есть:
  6. Если в конфигурации тула заданы include_paths или exclude_paths, OverlayFS монтируется один раз при старте сервера (не на каждую команду):
    • Сервер проверяет глобальный tools: и список tools каждого агента; если RunCommandTool используется где угодно с mode: "safe" и заданы include_paths/exclude_paths, OverlayFSManager создаёт overlay-файловые системы:
    • Создаёт временные директории для слоёв overlay (lowerdir, upperdir, workdir)
    • Монтирует исходные директории как нижний слой (только чтение)
    • Создаёт whiteout-файлы в верхнем слое для исключённых бинарников
    • Монтирует overlay и сохраняет пути монтирования
    • Эти монтирования переиспользуются для всех выполнений команд в течение жизни сервера
  7. В рантайме тул использует заранее инициализированные монтирования OverlayFS из OverlayFSManager
  8. Это ограничивает доступные в песочнице бинарники на уровне файловой системы, в том числе команды, вызываемые скриптами
  9. Если ни include_paths, ни exclude_paths не заданы, используются монтирования по умолчанию (только чтение /usr и т.д.)
  10. При остановке сервера все монтирования OverlayFS автоматически размонтируются, временные директории удаляются
  11. Запускает команду через bwrap с настроенными монтированиями и таймаутом. Возвращает форматированные stdout, stderr, код возврата.

Безопасный режим: минимальные настройки по умолчанию (bwrap)

Безопасный режим использует минимальную, но достаточную настройку bwrap, чтобы песочница работала из коробки:

  • Файловая система по умолчанию (когда include_paths не задан): Привязка /usr только для чтения; симлинки для /bin, /lib, /lib64; --proc /proc, --dev /dev; записываемая директория workspace, привязанная как /workspace (из workspace_path, если задан, иначе временная или текущая рабочая директория).
  • Ограниченная файловая система (когда заданы include_paths или exclude_paths): Используется OverlayFS для отфильтрованного вида файловой системы:
  • Инициализация: OverlayFS инициализируется один раз при старте сервера, если RunCommandTool используется с mode: "safe" где угодно (глобальный tools: или tools любого агента). Пути (include_paths/exclude_paths) могут быть не заданы; тогда overlay-монтирования не создаются, но менеджер готов. Если пути заданы, создаются overlay-монтирования для этих директорий.
  • Нижний слой: Исходные директории (например, /usr/bin) смонтированы только для чтения
  • Верхний слой: Временная директория с whiteout-файлами для exclude_paths
  • Объединённый слой: OverlayFS-монтирование, объединяющее нижний и верхний слои, скрывая исключённые файлы
  • Например, при include_paths: ["ls", "cat"] и exclude_paths: ["rm"], если все в /usr/bin:
    • Нижний слой: /usr/bin (только чтение, все бинарники)
    • Верхний слой: Содержит whiteout-файл .wh.rm, скрывающий rm
    • Объединённый: overlay /usr/bin показывает ls и cat, но не rm
  • Overlay монтируется в bwrap по исходному пути
  • Системные директории (/lib, /usr/lib, /lib64, /usr/lib64) всегда монтируются для зависимостей (shared libraries)
  • Переиспользование: Одни и те же overlay-монтирования используются для всех выполнений команд (без накладных расходов на команду)
  • Очистка: При остановке сервера все OverlayFS-монтирования размонтируются, временные директории удаляются
  • Это гарантирует, что команды, вызываемые из скриптов (например, bash script.sh, вызывающий rm), тоже ограничены: если rm скрыт whiteout, он недоступен в песочнице
  • Выполнение: Процесс запускается с --chdir /workspace, --unshare-all, --die-with-parent; команда выполняется как /bin/sh -c "<command>".
  • Таймаут: Задаётся тулом (subprocess timeout) после timeout_seconds.

Это даёт изоляцию (пространства имён, ограниченная файловая система) без дополнительной настройки. При использовании include_paths/exclude_paths песочница использует OverlayFS для ограничения бинарников на уровне файловой системы, так что скрипты не могут выполнить запрещённые команды даже при попытке.

Детали реализации OverlayFS

Как работает OverlayFS:

  • Нижний слой (только чтение): Исходная файловая система (например, /usr/bin со всеми бинарниками)
  • Верхний слой (запись): Whiteout-файлы (.wh.<имя_файла>), скрывающие файлы нижнего слоя
  • Рабочая директория: Временная директория для атомарных операций OverlayFS
  • Объединённое монтирование: Общий вид, в котором исключённые файлы скрыты

Whiteout-файлы:

  • Формат: символьное устройство с major/minor 0/0 или обычный файл .wh.<исходное_имя>
  • При встрече whiteout OverlayFS скрывает соответствующий файл из нижнего слоя
  • Это позволяет исключать отдельные файлы из директории, не исключая всю директорию

Управление жизненным циклом:

  • Старт сервера: OverlayFS инициализируется OverlayFSManager в фазе FastAPI lifespan startup
  • Конфигурация: Конфиг RunCommandTool берётся из глобального tools: или из любого агента (выигрывает первый кандидат с mode: "safe"). Если везде mode: "unsafe", overlay не инициализируется. Если хотя бы один конфиг (глобальный или агента) имеет mode: "safe", overlay инициализируется (include_paths/exclude_paths могут быть не заданы; тогда 0 монтирований).
  • Инициализация: При наличии хотя бы одного safe-конфига (глобального или у агента)
  • Рантайм: Заранее инициализированные монтирования переиспользуются для всех выполнений команд
  • Остановка сервера: Все OverlayFS-монтирования размонтируются, временные директории удаляются в фазе FastAPI lifespan shutdown

Преимущества:

  • Нативный механизм ядра (не нужен SUID)
  • Точное исключение файлов внутри директорий
  • Удобная работа с bwrap
  • Эффективность: монтирования создаются один раз при старте, переиспользуются для всех команд
  • Автоматическая очистка при остановке сервера

3. Справочник конфигурации

Все параметры опциональны. Задаются в глобальной секции tools: или у агента.

Параметр Тип По умолчанию Описание
workspace_path str None Директория для cwd (unsafe) или workspace bwrap (safe). В safe-режиме эта директория привязывается как /workspace внутри песочницы. Если при использовании RunCommandTool параметр не задан, сервер создаёт директорию ./workspace рядом с config.yaml и использует её.
mode str "safe" "safe" или "unsafe". Safe использует bwrap (только Linux); unsafe - локальный субпроцесс.
timeout_seconds int 60 Максимальное время выполнения в секундах.
include_paths list[str] None Разрешённые команды/пути. Если задано, выполняться могут только команды из этого списка. Сопоставление по имени (например, "ls") или полному пути (например, "/usr/bin/ls"). Пути в аргументах команды тоже проверяются. Имеет приоритет над exclude_paths (один и тот же путь в обоих - разрешён).
exclude_paths list[str] None Исключённые команды/пути. Если задано, они запрещены, если не указаны также в include_paths.

Параметры тула (от LLM / схемы): reasoning (str), command (str, полная командная строка).

Пример (unsafe):

tools:
  run_command_tool:
    workspace_path: "/tmp/agent_workspace"
    mode: "unsafe"
    timeout_seconds: 120

Пример (safe, Linux с установленным bwrap):

tools:
  run_command_tool:
    workspace_path: "/tmp/agent_workspace"
    mode: "safe"
    timeout_seconds: 60

Пример (с include_paths/exclude_paths - ограничение разрешённых команд):

tools:
  run_command_tool:
    workspace_path: "/tmp/agent_workspace"
    mode: "unsafe"
    timeout_seconds: 60
    include_paths:
      - "ls"
      - "cat"
      - "/usr/bin/python3"
      - "/tmp/agent_workspace"  # Доступ к директории workspace
    exclude_paths:
      - "rm"
      - "/usr/bin/rm"

Установка Bubblewrap (для безопасного режима)

Безопасный режим требует наличия bwrap в системе. Если он не установлен, тул возвращает сообщение об ошибке со ссылкой на инструкцию по установке.

  • Установка: См. Bubblewrap - Installation. В Debian/Ubuntu: apt install bubblewrap. В Fedora: dnf install bubblewrap. В Arch: pacman -S bubblewrap.
  • Docker: В Docker-образе проекта bubblewrap ставится через apt, поэтому безопасный режим работает без дополнительных шагов.

4. Аналоги и альтернативы

Режим Unsafe (ОС)

Unsafe использует субпроцесс ОС и опционально workspace_path; работает на всех платформах. Используйте, когда нужна только граница по директории или когда bwrap недоступен (например, Windows, macOS).

Bubblewrap + OverlayFS (безопасный режим)

bubblewrap - лёгкая непривилегированная песочница на базе пространств имён Linux и bind-монтирований. Используется в Flatpak и др. Безопасный режим сочетает bwrap с OverlayFS для точного управления файловой системой:

  • bwrap даёт изоляцию пространств имён (PID, UTS, IPC, NET, MNT, USER, CGROUP, TIME)
  • OverlayFS даёт исключение на уровне файлов через whiteout-файлы
  • Вместе это позволяет монтировать директории, исключая отдельные файлы, без SUID-бинарников

Безопасный режим строит минимальное окружение, в котором команды выполняются изолированно с одной записываемой директорией workspace и отфильтрованным доступом к бинарникам.


5. Замечания по безопасности

  • Unsafe: Выполняется от того же пользователя, что и агент. Проверка путей ограничивает доступ к workspace_path; используйте таймаут, чтобы избежать зависаний.
  • Safe: Использует bwrap для изоляции пространств имён и файловой системы. Песочница не является полной границей безопасности; используйте как слой снижения рисков. Убедитесь, что workspace_path указывает на выделенную рабочую директорию, а не на чувствительную.

6. Кратко

Элемент Описание
RunCommandTool Выполняет shell-команды; unsafe = субпроцесс ОС (все платформы); safe = песочница bwrap (Linux, требуется bwrap).
bwrap Должен быть установлен для безопасного режима. Установка: Bubblewrap - Installation.
Минимальные умолчания Безопасный режим использует минимальную настройку bwrap: ro-bind /usr, workspace как /workspace, unshare-all, таймаут.
OverlayFS При заданных include_paths/exclude_paths использует OverlayFS с whiteout-файлами для исключения отдельных бинарников из директорий.