Перехват и посредничество
Четыре поверхности интеграции доносят решение о применении политики до места, где разработчик или ИИ-агент реально касается чувствительных данных: интерактивная командная оболочка, транспорт 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 с, корректно найдя секрет из более раннего, всё ещё достижимого коммита.
Далее: Механизм обнаружения.