# Как расследовать заблокированные вызовы AI-агентов, не ослабляя контроль

Заблокированные вызовы AI-агента не нужно считать помехой, от которой следует избавиться. Это часть вашей системы контроля. Она показывает, где инструкции агента, интерфейс инструмента, настройка доступа или поведение перестали соответствовать реальности. Если воспринимать каждый отказ как просьбу выдать дополнительные права, рано или поздно агент получит самые широкие полномочия именно в тот момент, когда у вас меньше всего оснований доверять его следующему шагу.

Я видел, как команды превращали полезный отказ в постоянное исключение, потому что сроки поджимали, а данные были разбросаны. Первое одобрение кажется безобидным. Второе становится привычным. Вскоре агент получает доступ к production с учетными данными, которые ему не нужно было видеть, через инструмент, назначение которого никто не может толком объяснить. Это не рост эффективности. Это расследование, которое вы решили не проводить.

Расследование заблокированных вызовов AI-агента сводится к нескольким вопросам, на которые нужно отвечать по порядку: что именно запросил процесс, какой контроль отклонил запрос, оправдывала ли задача это действие и какое минимальное исправление позволит продолжить законную работу? Порядок важен. Если начать с расширения доступа, все последующие записи будет сложнее интерпретировать.

## Запись об отказе - это свидетельство, а не сообщение об ошибке

Заблокированный запрос фиксирует разногласие между попыткой агента выполнить действие и полномочиями, которые вы намеревались ему выдать. Сохраните это разногласие, пока не поймете его причину. Отказ может выявить отсутствующие учетные данные, неразрешенный процесс, слишком расплывчатый инструмент, неверное окружение или запрос, которого вообще не должно было быть.

Термин «заблокирован» смешивает два разных события, с которыми команды часто обращаются неправильно. Действие может завершиться неудачей, потому что шлюз не разрешил его, либо оно может дойти до внешнего сервиса, который сам его отклонил. В первом случае контроль остановил запрос. Во втором вы позволили запросу выйти наружу, а адресат его отверг. Сначала расследуйте первый вариант, пока он не превратился во второй.

Полезная запись отвечает на вопросы, на которые консольная расшифровка обычно ответить не может:

- Какой процесс агента сделал запрос и как этот процесс был идентифицирован?
- Какую точную HTTP-операцию или SSH-команду он запросил?
- Какой адресат и ссылка на учетные данные были выбраны?
- Какой шлюз или условие одобрения отклонили запрос?
- Какая инструкция задачи или информация из репозитория привела к этому запросу?

Не принимайте фразу «агенту нужен доступ к развертыванию» в качестве ответа на любой из этих вопросов. Доступ к развертыванию - это категория. Для расследования нужны операция, цель и ожидаемый результат. «Прочитать текущий статус релиза из staging API» - утверждение, которое можно проверить. «Доступ к развертыванию» - приглашение одобрить все, что появится дальше.

В документе NIST Special Publication 800-92, Guide to Computer Security Log Management, содержится не самая эффектная, но важная мысль: журналы помогают при реагировании на инциденты и устранении операционных проблем. Команды часто пропускают часть о сохранности данных: в журнале должно оставаться достаточно контекста, чтобы отличить обычную ошибку от необычного запроса. Одного всплывающего окна с одобрением недостаточно. Скопированной строки из терминала тоже недостаточно. Сохраните весь запуск и отдельный вызов до того, как кто-либо изменит настройку.

У отказов есть еще одно преимущество: они заставляют оператора сформулировать, какие полномочия действительно предполагались. Эта формулировка станет проверкой для следующего запуска агента. Если никто не может описать полномочия без широких слов вроде «администратор», «production» или «доступ к репозиторию», задача еще не готова к автономному выполнению.

## Назовите запрошенное действие до изменения доступа

Нельзя расследовать заблокированный вызов, пока вы не сведете его к предложению, которое другой инженер сможет воспроизвести. В нем нужно назвать инициатора, действие, адресат, ссылку на аутентификацию и ожидаемый результат. Если в записи отсутствует хотя бы один из этих элементов, перестаньте считать ее обычным запросом разрешения.

Для HTTP сохраните метод, путь, имя хоста и укажите, читает ли вызов данные или изменяет состояние. `GET /releases/current` и `POST /releases` могут использовать один сервис и одни учетные данные, но создают совершенно разные риски. Bearer-токен, который позволяет читать конечную точку со статусом, может также запускать развертывание. Не делайте вывод о безопасной области доступа по дружелюбному названию учетных данных.

Для SSH запишите псевдоним хоста, запрошенную команду, рабочий каталог, если инструмент его раскрывает, и ожидаемый результат. Фраза «запустить тесты на сервере сборки» все еще слишком расплывчата. «Выполнить `git status --short` в клонированном репозитории» дает проверяющему конкретный ориентир для сравнения с задачей. Команды с перенаправлением оболочки, подстановкой команд, установкой пакетов, удалением или передачей данных по сети требуют особого внимания: видимый глагол может скрывать главное последствие.

Пока запуск еще доступен, используйте эту короткую заметку расследования:

```text
Идентификатор запуска:
Инструкция задачи:
Запрошенная операция:
Целевой хост или путь API:
Ссылка на учетные данные:
Контроль, отклонивший запрос:
Ожидаемый результат:
Почему запрос относится к задаче:
Минимальное безопасное исправление:
```

Эта заметка предотвращает знакомую проблему при передаче работы: один человек видит промпт, другой - карточку одобрения, а третий - сообщение об ошибке от адресата. У каждого есть правдоподобный фрагмент, поэтому кто-то одобряет запрос вслепую.

Авторизация сессий в Sallyport начинается с полномочий подписи кода процесса. Именно это стоит проверить до одобрения нового запуска. Идентификатор процесса не доказывает, что запрос разумен, но не позволяет считать все локальные процессы взаимозаменяемыми. Терминал, запущенный ожидаемым подписанным приложением, и неизвестный исполняемый файл, запрашивающий то же действие, - разные случаи.

Не используйте свободное описание задачи как доказательство. Агент может неправильно его понять, унаследованные инструкции могут конфликтовать, а вредоносный репозиторий способен добавить указания, похожие на обычные рекомендации по проекту. Сопоставляйте запрошенное действие с источником задачи, которым вы управляете, например с проверенной заявкой или явной инструкцией оператора. Текст репозитория - это входные данные, а не полномочия.

## Источник отказа меняет ход расследования

Разные элементы контроля отклоняют запросы по разным причинам, и для каждой причины нужно свое исправление. Если складывать все отказы в одну категорию «доступ запрещен», вы получите плохие исправления, потому что не будете видеть, где именно было принято решение.

Отказ заблокированного хранилища означает, что действие не должно выполняться. Не переносите учетные данные в переменную окружения, не копируйте их в промпт и не создавайте обходной путь. Такие действия обходят именно ту защиту, которая обнаружила проблему. Убедитесь, что человек за Mac намерен разблокировать доступ для этой задачи, и продолжайте только после того, как он проверит контекст запуска.

Отказ нового сеанса означает, что процесс агента еще не получил полномочий для текущего запуска. Проверьте идентификатор процесса и границы задачи. Если они соответствуют начатой вами работе, одобрение для конкретной сессии уместно: оно действует ограниченное время, а после завершения запуска прекращаются и эти полномочия. Если процесс оказался неожиданным, не одобряйте его лишь потому, что первый вызов выглядит безобидным. Незнакомый процесс может начать с безвредного действия, чтобы постепенно сформировать доверие.

Требование одобрения каждого вызова означает, что владелец учетных данных намеренно оставил каждое использование на решение человека. Не убирайте это условие только потому, что агент делает несколько похожих запросов. Возможно, задача плохо сформулирована. Пакетная операция может требовать отдельного продуманного процесса, а не серии одобрений, после которых проверяющий перестает читать.

Отсутствующие или несовпадающие учетные данные - отдельный случай. Агент может запрашивать именованную операцию, которая относится к задаче, но в хранилище нет учетных данных для этого адресата или у них отсутствуют нужные права во внешнем сервисе. Сначала подтвердите, что адресат выбран намеренно. Затем добавьте или исправьте узкое сопоставление учетных данных. Никогда не передавайте секрет агенту для диагностики. Шлюз может выполнить аутентификацию, а агент увидит только результат.

Ошибка внешней авторизации требует другого ответа. Вызов мог корректно пройти через шлюз, но сервис отклонил его с ответом вроде `401`, `403` или специфичной для домена ошибкой. Сохраните форму запроса и полученный результат. Исправляйте права сервисной учетной записи только после того, как подтвердите, что операция относится к задаче. Изменение роли сервиса до этой проверки превращает обычную проблему настройки в широкие постоянные права.

Различие имеет практическое значение: отказ шлюза защищает установленную вами границу, а внешний отказ показывает, что граница уже позволила попытку. Не называйте оба события «блокировкой» в заметках об инциденте. Используйте разные метки. Позже вам нужно будет знать, остановили ли запрос локально или он просто завершился ошибкой дальше по цепочке.

## Восстанавливайте намерение по задаче, а не по объяснению агента

Агент может объяснить, почему он сделал запрос, но его объяснение - это свидетельство о ходе рассуждений, а не основание для выдачи доступа. Решение о том, относится ли действие к задаче, принимает ее владелец. Это кажется очевидным, пока уставший оператор не слышит от агента, что широкая команда нужна «для проверки окружения», и не перестает ее блокировать.

Начните с ожидаемого результата. Если задача заключается в исправлении неработающего теста, HTTP-вызов для чтения статуса сборки может быть уместен. Вызов для смены учетных данных развертывания не подходит, если задача прямо не связана с учетными данными. Если задача требует обновить документацию, SSH-запрос для установки пакетов на общем хосте нуждается в гораздо более убедительном объяснении, чем «это нужно сборке».

Затем изучите самый короткий путь к результату. Агенты часто выбирают широкое действие, потому что его проще описать. Инструмент, принимающий произвольный текст оболочки, подталкивает агента к командам обнаружения, проверке окружения и составным сценариям там, где хватило бы именованной операции. Инструмент, принимающий произвольный URL API, приглашает исследовать конечные точки за пределами задачи.

Я использую простой тест: можете ли вы заранее записать узкое утверждение об ожидаемом действии? Если вы можете сказать «прочитать текущие метки задачи», но не можете сказать «изменить метки», запрос на запись не является неоднозначным. Он находится за пределами области задачи. Отклоните его и изучите путь инструкций, который к нему привел.

Здесь команды часто дают популярный, но плохой совет: выдать агенту широкий доступ на чтение, потому что чтение безопасно. Доступ на чтение может раскрыть данные клиентов, внутреннюю топологию, детали развертывания, схемы доступа и случайно сохраненные в сервисе секреты. Он может быть менее разрушительным, чем запись, но это все равно полномочия. Ограничивайте чтение сервисом, классом ресурсов и окружением, которые нужны задаче.

Инструкции в промптах тоже являются слабым доказательством, потому что содержимое репозитория может направлять агента. В комментарии к скрипту установки зависимостей может содержаться указание проверить локальный каталог с учетными данными. Документ по настройке может предлагать выполнить curl-команду для незнакомого хоста. Агент может послушно выполнить этот текст, хотя вы не разрешали действие. Если непроверенные инструкции репозитория приводят к новому внешнему действию, относитесь к ним как к данным, требующим проверки.

Запишите несоответствие простыми словами. «Задача требовала прочитать статус релиза, а агент запросил создание релиза». «В задаче было указано staging, а запрос направился в production». «В описании инструмента упоминался известный хост, а запрос содержал новое имя хоста». Такие формулировки помогают инженеру исправить причину. Фраза «отклонено службой безопасности» не помогает.

## Повторные отказы обычно показывают дефект контракта инструмента

Интерфейс инструмента создает проблемы, когда передает модели решения по безопасности в виде открытых параметров. Агент начинает угадывать хост, ветку, путь, учетные данные или команду оболочки. Каждый отказ выглядит как проблема доступа, хотя настоящая причина может заключаться в том, что инструмент никогда не определял разрешенное действие.

Представьте, что агенту поручили проверить завершение релиза. Расплывчатый HTTP-инструмент может разрешать любой метод, любой URL, произвольные заголовки и выбор учетных данных. Агент формирует запрос к конечной точке, найденной в тексте репозитория. Запрос отклоняется. Кто-то одобряет адресат, после чего агент выбирает другую конечную точку для следующего шага. Оператор видит серию по отдельности правдоподобных вызовов и постепенно собирает через решения об одобрении непроверенный API-клиент.

Лучший инструмент предоставляет именно поддерживаемую операцию: прочитать статус релиза для указанного окружения. Владелец инструмента фиксирует базовый адрес и HTTP-метод. Агент передает небольшой параметр, например идентификатор релиза. Шлюз добавляет учетные данные только для предусмотренного вызова. Теперь отказ имеет ясный смысл: окружение, идентификатор, процесс или сопоставление учетных данных не соответствуют контракту.

То же правило действует для SSH. Не выдавайте агенту для программирования общий удаленный shell, если работе нужны две операции обслуживания. Представьте эти операции как скрипты с известными аргументами или используйте оболочку, которая проверяет узкую форму команды. Ограничительный интерфейс может казаться неудобным при проектировании. Но он быстро начинает казаться разумным, когда агент впервые просит выполнить составную команду не на том хосте.

Ищите такие признаки в группе отказов:

- Агент снова и снова придумывает названия адресатов или пути API.
- Запросы чередуют операции чтения и записи, хотя задача не менялась.
- Для одной задачи требуется много несвязанных учетных данных.
- Проверяющему приходится по длинной строке команды угадывать последствия ее выполнения.
- Описание инструмента обещает результат, но оставляет важные параметры открытыми.

Не исправляйте каждый случай новым исключением. Измените контракт инструмента. Узкие инструменты также повышают надежность агента, потому что убирают решения, с которыми языковые модели справляются плохо. Агент должен выбирать из поддерживаемых операций, а не собирать собственную границу безопасности из строк.

Sallyport хранит секреты в зашифрованном хранилище и выполняет HTTP- или SSH-действия, не передавая учетные данные агенту. Это разделение полезно только тогда, когда интерфейс действия достаточно конкретен для человеческой проверки. Изоляция учетных данных предотвращает утечку секретов, но не делает широкий запрос приемлемым.

## Проследите один неудачный запуск от начала до конца

При расследовании отказа нужно сохранить последовательность: первый необычный вызов часто объясняет все последующие запросы. Если смотреть только на последнее заблокированное действие, возникает ложная история, будто агент внезапно стал подозрительным.

Рассмотрим реалистичный пример. Агент получает задачу обновить заметки о релизе сервиса после успешной сборки в staging. Сначала он читает файлы в репозитории. Затем запрашивает HTTP-вызов для получения статуса сборки в staging. Вызов соответствует задаче и выполняется после ожидаемого одобрения запуска. Далее агент запрашивает SSH-доступ к серверу сборки, чтобы проверить созданный артефакт. Это может быть оправдано, но новый канал требует отдельного сравнения с задачей.

Сервер возвращает ошибку: ожидаемого артефакта нет. Агент читает скрипт репозитория, в котором сказано, что оператор может пересобрать артефакты удаленной командой. Затем он просит выполнить команду, которая очищает каталог результатов, устанавливает зависимости и запускает сборку. Запрос отклоняется при проверке каждого вызова.

Не одобряйте эту команду только потому, что первый HTTP-запрос был законным. В исходной задаче не было указано пересобирать артефакт, изменять общий хост или устанавливать зависимости. Путь инструмента изменился: вместо проверки статуса агент перешел к удаленной модификации. Правильное расследование задает вопросы:

1. Человек разрешил пересборку артефакта или агент вывел ее из текста репозитория?
2. Предназначен ли сервер сборки для автономных изменений или агент должен сообщить об отсутствии артефакта?
3. Может ли отдельная операция сборки заменить составную команду удаленной оболочки?
4. Относится ли каталог результатов к этой задаче или его очистка может повлиять на другой запуск?
5. Нужен ли другой процесс, потому что сборка в staging завершилась неуспешно?

Исправление может заключаться в том, чтобы остановиться и сообщить об отсутствующем артефакте. Можно добавить проверенное действие сборки с изолированным рабочим каталогом. Возможно, нужно исправить конвейер, который должен был создать артефакт. Выдача общего SSH-доступа - худшее исправление: она скрывает все три варианта под одним широким разрешением.

Эта последовательность также объясняет, почему усталость от одобрений - дефект дизайна. Человек видит один обычный вызов, затем несколько технических запросов и начинает одобрять их по инерции. Контроль формально продолжает работать, но качество проверки падает. Размещайте решения на важных границах: при появлении нового процесса, учетных данных с серьезными последствиями или изменении области доступа. Не заставляйте человека каждые несколько секунд разбирать новую программу оболочки.

## Доверяйте журналу аудита только после проверки его целостности

Журналы полезны лишь тогда, когда можно понять, изменял ли кто-то их после события. Само по себе утверждение о добавлении данных только в конец журнала ничего не решает, если компьютер с агентом взломан или оператору хочется убрать неудобную запись.

Журнал аудита с хеш-связями связывает каждую запись с предыдущей. Изменение более раннего зашифрованного содержимого меняет последующую связь в цепочке. Благодаря этому вмешательство обнаруживается при проверке. Но такая цепочка не делает исходное событие правильным и не мешает злоумышленнику причинить вред до записи события. Используйте ее по назначению: для уверенности, что сохраненная последовательность не была незаметно изменена.

Запустите проверку до начала долгого анализа и повторите ее, если экспортируете записи для расследования. Sallyport умеет проверять зашифрованную цепочку аудита офлайн с помощью этой команды:

```text
sp audit verify
```

Для проверки не нужен ключ хранилища. Сохраните результат вместе с заметкой расследования, укажите время проверки и набор изученных записей. Если проверка завершилась ошибкой, не считайте затронутую последовательность полной историей. Сохраните исходные файлы, ограничьте доступ к компьютеру и сопоставьте данные с независимыми источниками, например журналами целевого сервиса, историей репозитория и системой задач.

Не переоценивайте пользу независимых журналов. Сервис-адресат может записать, что получил запрос, но не знать, какой локальный процесс агента его инициировал. Система контроля версий может показать коммит, но не объяснит, почему агент выбрал именно это изменение. Корреляция работает, когда идентификаторы и порядок времени сохраняются во всех источниках, а не когда скриншоты собирают постфактум.

Разделяйте в заметках два вопроса. Первый: «Запросил ли этот запуск агента такое действие?» Второй: «Было ли это действие уместно?» Целостность аудита помогает ответить на первый. Область задачи и человеческое решение определяют второй. Команды смешивают эти вопросы, потому что целый журнал выглядит авторитетным. Целый журнал может доказать, что плохой запрос действительно был. Он не превращает этот запрос в хороший.

## Исправьте узкую причину и подтвердите результат

Правильное исправление позволяет выполнить нужную задачу, сохраняя причину, по которой контроль отклонил исходный запрос. Любое исправление, которое лишь убирает всплывающее окно, вызывает подозрения.

Если не хватает доступа, добавьте ссылку на учетные данные, связанную с нужным сервисом, и убедитесь, что внешняя область этих учетных данных включает только необходимую операцию. Повторно выполните тот же узкий запрос. Не проверяйте исправление широкой операцией «просто чтобы убедиться». Тест должен показать, что конкретный неработавший случай теперь выполняется, а несвязанные запросы по-прежнему отклоняются.

Если процесс оказался неожиданным, снова запустите известную точку входа агента и сравните его идентификатор с отклоненным процессом. Если ожидаемый процесс изменился из-за обновления или оболочки, зафиксируйте это изменение и выясните причину расхождения. Если объяснения нет, не маскируйте проблему постоянным одобрением. Инструменты агента часто запускают дочерние процессы, но это не означает, что каждый дочерний процесс заслуживает полномочий родительского.

Если проблема в инструменте, измените интерфейс до следующего автономного запуска. По возможности замените произвольные адресаты фиксированным. Произвольный текст команды замените именованной операцией. Уберите чувствительный параметр из-под контроля агента. Затем проверьте обе стороны границы:

- Поддерживаемый запрос выполняется с нужным процессом и в рамках задачи.
- Другой адресат, команда или операция записи отклоняются.
- В записи активности достаточно ясно указано, что произошло.
- Запись сессии позволяет отозвать запуск, если его поведение изменится.

Если запрос подозрителен, не продолжайте запуск, пока обсуждаете область доступа. Отзовите его полномочия, сохраните записи сессии и вызовов и изучите источники инструкций, которые предшествовали запросу. Обычная задача может стать небезопасной после чтения непроверенного содержимого. То, что процесс начинался как одобренный запуск, не дает ему безусловного права на последующие действия.

Sallyport собирает журналы запусков и вызовов в одном зашифрованном журнале аудита с защитой от записи и хеш-связями, а также поддерживает немедленный отзыв запуска через журнал Sessions. Используйте отзыв, когда последовательность запросов перестает иметь смысл. Это мера сдерживания, а не вывод о виновности разработчика, который начал запуск.

Завершите расследование одним предложением, которое сможет направить следующего оператора: «Агенту не хватало учетных данных для чтения статуса staging, и мы добавили их для одобренной операции чтения» или «Агент попытался выполнить неразрешенную удаленную пересборку после чтения текста репозитория, поэтому мы остановили запуск и добавим проверенное действие сборки». Если вы не можете написать такое предложение, причина еще не найдена.

## Понимать отказы должно быть проще, чем обходить их

Люди обходят контроль, когда расследование кажется дороже самой задачи. Ответом не должны быть более слабые ограничения. Нужны записи и интерфейсы инструментов, которые делают законный путь очевидным, а необычный - заметным.

Ограничивайте инструкции задачи. Укажите окружение, предполагаемое внешнее действие и условие остановки. Фраза «изучи неудачное развертывание в staging и сообщи причину» оставляет место для отчета. Фраза «сделай production таким же, как staging» незаметно приглашает к изменениям, выдаче учетных данных и системным действиям, которые никто не проверял.

Давайте проверяющим достаточно контекста для одного обоснованного решения. В одобрении сессии нужно показать, кто запустил процесс и к какому запуску он относится. В одобрении чувствительного действия нужно описать операцию и адресат понятными человеку словами. Если проверяющему приходится расшифровывать название учетных данных, прослеживать непрозрачный URL и мысленно выполнять конвейер оболочки, вы перенесли работу по безопасности в поспешный клик.

Измеряйте повторные отказы по причинам, а не по количеству. Десять запросов, заблокированных из-за неподдерживаемой конечной точки, указывают на проблему инструмента. Десять запросов, заблокированных из-за появления нового процесса при каждом запуске, указывают на проблему идентификации или запуска. Десять запросов, заблокированных из-за постоянного расширения задачи, указывают на проблему планирования. Само число мало что говорит.

Не пытайтесь сделать автономных агентов похожими на обычные скрипты. Скрипты обычно получают полномочия, потому что человек написал и проверил их точное поведение. Агент выбирает поведение во время работы и может учитывать новое содержимое репозитория, вывод инструментов и ошибки. Поэтому шлюзу действий нужны путь для решения человеком и запись, которая сохраняется после завершения операции.

Следующий отклоненный вызов должен привести к более ясной задаче или лучшему инструменту, а не к более широкому исключению. Если команда примет это правило, отказы станут реже по правильной причине: агент будет получать понятные и узкие полномочия, а оставшиеся блокировки будут указывать на поведение, которое действительно стоит остановить.
