Перехват и посредничество

Четыре поверхности интеграции доносят решение о применении политики до места, где разработчик или ИИ-агент реально касается чувствительных данных: интерактивная командная оболочка, транспорт MCP, системный буфер обмена и локальное рабочее дерево/история Git. Каждая из них рассмотрена ниже с описанием того, что фактически реализовано.

Перехват в командной оболочке (PTY)

Защищённая точка входа — функция командной оболочки tcg_shell, создаваемая для zsh, bash, PowerShell 5.1+ и cmd.exe встроенным в агент генератором перехватчиков. Каждое выводимое ею значение правильно экранируется для целевой оболочки, а неподдерживаемая оболочка приводит к явной ошибке.

%%{init: {"theme": "base", "themeVariables": {"fontFamily": "-apple-system, Segoe UI, Helvetica, Arial, sans-serif", "primaryColor": "#eef2f7", "primaryTextColor": "#0b0b0b", "primaryBorderColor": "#5b6b7c", "lineColor": "#5b6b7c", "secondaryColor": "#eef4ff", "tertiaryColor": "#f4f3f0", "clusterBkg": "#f9f9f7", "clusterBorder": "#c3c2b7", "edgeLabelBackground": "#fcfcfb", "actorBkg": "#eef2f7", "actorBorder": "#5b6b7c", "actorTextColor": "#0b0b0b", "actorLineColor": "#5b6b7c", "signalColor": "#52514e", "signalTextColor": "#0b0b0b", "labelBoxBkgColor": "#eef4ff", "labelBoxBorderColor": "#5b6b7c", "labelTextColor": "#0b0b0b", "loopTextColor": "#0b0b0b", "noteBkgColor": "#fdf3d9", "noteBorderColor": "#c98500", "noteTextColor": "#3d2f00", "activationBorderColor": "#5b6b7c", "activationBkgColor": "#eef4ff", "sequenceNumberColor": "#ffffff"}}}%% sequenceDiagram participant Dev as Разработчик / ИИ-агент participant Hook as Перехватчик оболочки (tcg_shell) participant Agent as station-agent (PTY) participant Policy as Механизм применения политик participant Mask as Потоковое маскирование Dev->>Hook: командная строка Hook->>Agent: shell-run-line Agent->>Policy: evaluate(команда, снимок) alt заблокировано Policy-->>Agent: block Agent-->>Dev: код выхода 126, без выполнения Agent->>Agent: событие command_decision else разрешено Policy-->>Agent: allow Agent->>Agent: выполнение в PTY, передача stdin и изменений размера Agent->>Mask: потоковая передача stdout/stderr Mask-->>Dev: маскированный вывод, потоково Agent->>Agent: событие command_decision end

Ключевые свойства:

  • Оценка до выполнения. Заблокированная команда никогда не выполняется — решение принимается до exec. Код завершения 126 сигнализирует именно об отказе политики. Каждое решение, блокировка или разрешение, порождает событие безопасности command_decision, содержащее идентификатор снимка политики и его действующий отпечаток.
  • Потоковая передача вывода. Вывод маскируется через механизм потоковой обработки, описанный в разделе Маскирование и потоковая защита — терминал остаётся отзывчивым, вывод доставляется непрерывно по мере его появления.
  • Защита от рекурсии (маркер окружения) гарантирует, что вложенный опосредованный вызов выполняется один раз.
  • Отдельный, облегчённый перехватчик специально контролирует запуск известных ИИ-агентов для написания кода (claude, codex, qwen, qwen-code, cursor-agent, cursor) — именно он запускает проверку репозитория перед запуском, описанную ниже, и намеренно отделён от более широкого перехватчика алиасов файлов и содержимого, чтобы разрешённый запуск агента сохранял обычный интерактивный TTY без промежуточной обёртки.

Покрытие по платформам:

  • bash/zsh: полное интерактивное посредничество PTY существует как возможность — пересылка stdin, распространение изменения размера терминала и восстановление состояния терминала при выходе (в том числе при ошибке).
  • PowerShell (5.1+): опосредуется через путь shell-run-line для Windows в station-agent (powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command ) — логика решения, маскирования и аудита выполняется в компилируемом агенте, который и является границей доверия; сам процесс PowerShell — лишь средство выполнения уже принятого решения о команде.
  • cmd.exe: посредничество носит рекомендательный характер и ограничено набором макросов через фиксированный список макросов DOSKEY для заданного набора первых слов команд.

Почему перехват командной оболочки Windows устроен именно так: были рассмотрены четыре альтернативы — функции профиля только для PowerShell (вообще не покрывают cmd.exe), полноценная оболочка на основе ConPTY (существенно больший объём работ, не требуется для доказательства модели посредничества), перехват только через ETW/сервис (недостаточно в изоляции) и обёртка стороннего терминала (отклонена сразу как неприемлемая зависимость). Принятая архитектура сохраняет компилируемый агент в роли доверенной границы, рассматривая скрипты для командной оболочки только как средство управления запуском.

Посредник протокола MCP

Посредник MCP находится между ИИ-агентом и локальным MCP-сервером на базе stdio — прозрачно передавая stdin/stdout дочернего процесса и проверяя трафик в обоих направлениях.

%%{init: {"theme": "base", "themeVariables": {"fontFamily": "-apple-system, Segoe UI, Helvetica, Arial, sans-serif", "primaryColor": "#eef2f7", "primaryTextColor": "#0b0b0b", "primaryBorderColor": "#5b6b7c", "lineColor": "#5b6b7c", "secondaryColor": "#eef4ff", "tertiaryColor": "#f4f3f0", "clusterBkg": "#f9f9f7", "clusterBorder": "#c3c2b7", "edgeLabelBackground": "#fcfcfb", "actorBkg": "#eef2f7", "actorBorder": "#5b6b7c", "actorTextColor": "#0b0b0b", "actorLineColor": "#5b6b7c", "signalColor": "#52514e", "signalTextColor": "#0b0b0b", "labelBoxBkgColor": "#eef4ff", "labelBoxBorderColor": "#5b6b7c", "labelTextColor": "#0b0b0b", "loopTextColor": "#0b0b0b", "noteBkgColor": "#fdf3d9", "noteBorderColor": "#c98500", "noteTextColor": "#3d2f00", "activationBorderColor": "#5b6b7c", "activationBkgColor": "#eef4ff", "sequenceNumberColor": "#ffffff"}}}%% flowchart LR Agent["ИИ-агент"] <-->|"JSON-RPC поверх stdio"| Proxy["station-agent\nпосредник MCP"] Proxy <-->|"JSON-RPC поверх stdio"| MCPServer["Локальный MCP-сервер"] Proxy --> Guard1{"Запрос ссылается\nна защищённый ресурс?"} Guard1 -- да --> Block["Блокировать запрос,\nсобытие mcp_request_blocked"] Guard1 -- нет --> Pass1["Переслать запрос"] Proxy --> Guard2{"Ответ содержит\nчувствительное значение?"} Guard2 -- да --> Redact["Маскировать, повторно\nпроверить как JSON-RPC,\nсобытие mcp_response_masked"] Guard2 -- нет --> Pass2["Переслать ответ"]
  • Проверка запросов: проверяется каждая строка в запросе — имя метода и все вложенные параметры. Значения в процентной кодировке декодируются до трёх раундов, а обратные слэши нормализуются в прямые до начала любого сопоставления. Применяются два различных правила сопоставления в зависимости от источника защищаемого значения, и это не одно и то же правило: встроенный минимум (.env, .ssh, id_rsa, id_ed25519) сопоставляет .ssh/.env как целые сегменты пути, а не подстроки, и не может быть переопределён политикой — это жёсткий минимум сверх того, что дополнительно защищает политика. Добавленные политикой protected_resources, напротив, сопоставляются по регистронезависимому равенству базового имени или по подстроке после нормализации — это более свободное правило, чем сопоставление целыми сегментами у встроенного минимума. Для абсолютных локальных путей дополнительно разрешаются символические ссылки перед сопоставлением.
  • Проверка ответов: выполняется тем же набором механизмов обнаружения, что используется в остальной системе, плюс проход декодирования и проверки областей в кодировке base64 (распространённое кодирование для полезной нагрузки вызовов инструментов). Редактирование чувствительных данных, которое повредило бы структуру JSON-RPC, трактуется как ошибка и никогда не отправляется — посредник не станет доставлять повреждённый кадр протокола ради безопасности.
  • События сессии: старт/остановка сессии MCP порождают события mcp_session_status для видимости оператору.

Наблюдение за буфером обмена

Локальный процесс наблюдения опрашивает системный буфер обмена (системные инструменты для каждой платформы — pbpaste/pbcopy на macOS, PowerShell Get-Clipboard/Set-Clipboard на Windows, xclip на Linux — содержимое всегда передаётся через stdio, никогда не собирается в командную строку оболочки). При обнаружении изменения он хэширует содержимое и действует только по этому изменению; хэш собственной маскированной перезаписи запоминается, чтобы монитор не срабатывал повторно на свою же запись.

  • Интервал опроса: 500 мс.
  • Ограничение на проверку: 256 КБ, обрезается по границе UTF-8. Содержимое сверх ограничения порождает событие clipboard_partially_inspected.
  • Маскирование является разрушающим — исходное содержимое буфера обмена не сохраняется после перезаписи.
  • Само событие маскирования фиксирует только хэши и длины, никогда содержимое буфера обмена.

Локальная проверка репозиториев

Механизм с параллельной обработкой проверяет Git-репозитории полностью на рабочей станции — исходное содержимое никогда не покидает машину; сообщаются только типы находок, имена механизмов обнаружения и счётчики. Проверка истории обходит полный граф коммитов (каждый двоичный объект, достижимый из каждой ссылки, с удалением дублей по хешу объекта, ограниченный настраиваемым бюджетом объектов) — поэтому секрет, зафиксированный в одном коммите и удалённый в более позднем коммите, всё ещё находящемся на живой ветке, всё равно будет найден.

Механизм проверки встроен в шлюз запуска ИИ-агента, описанный выше: перед тем как распознанный ИИ-агент для написания кода запускается внутри Git-репозитория, выполняется проверка рабочего дерева и истории (результат сохраняется для того же состояния репозитория и той же политики), и сохраняются только метаданные с удалёнными чувствительными значениями — хэш корня репозитория, команда запущенного агента, состояние проверки и счётчики файлов и находок, но никогда исходное содержимое или найденные значения. Один зафиксированный прогон (2026-08-07, 40 репозиториев, 1 600 файлов, включая полную историю) завершился за 0,339 с, корректно найдя секрет из более раннего, всё ещё достижимого коммита.

Далее: Механизм обнаружения.

results matching ""

    No results matching ""