Читать 7 мин

Средства одобрения действий ИИ-агентов: правила и понятные решения

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

Средства одобрения действий ИИ-агентов: правила и понятные решения

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

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

Механизм правил превращает авторизацию в постоянную поддержку программного обеспечения

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

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

Рассмотрим знакомое правило:

allow if
  agent.project == "payments"
  and request.host ends_with ".internal.example"
  and request.method in ["GET", "POST"]
  and time.weekday in ["Mon", "Tue", "Wed", "Thu", "Fri"]

Оно выглядит разумно, пока не приходится отвечать на операционные вопросы. Кто назначает agent.project? Может ли агент на него влиять? Принимает ли ends_with значение not-internal.example? Что разрешает POST на конечной точке, которая умеет создавать, возвращать, удалять или запускать перевод? Что произойдет при инциденте в субботу? Перекрывает ли более поздний запрет более раннее разрешение?

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

Документация Open Policy Agent справедливо описывает политики как код и рекомендует их тестировать. Это не рекламный лозунг о гибкости. Это признание операционного обязательства: если политика управляет значимым доступом, команда должна относиться к ее изменению как к изменению кода. Проверяющим нужны тестовые наборы. CI нужны ожидаемые решения. Дежурному инженеру нужен способ понять, какая версия политики разрешила запрос.

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

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

Ясность решения важна, когда вызов имеет последствия

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

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

Полезный экран авторизации отвечает на конкретные вопросы:

  • Какой исполняемый файл запросил действие и кто его подписал?
  • Это новый процесс или процесс, уже одобренный для этой сессии?
  • Какие учетные данные будут использованы?
  • Куда уйдет запрос или с каким хостом свяжется SSH?
  • Одобрение относится к одному запуску или к одному чувствительному использованию?

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

NIST Special Publication 800-207 строит модель нулевого доверия на явной проверке и постоянной оценке, а не на унаследованном доверии к сети. Практический вывод для локальных действий агента проще, чем многие реализации: оценивайте исполнителя и запрос в момент действия. Не передавайте токен агенту в надежде, что граница останется значимой после того, как токен выйдет из-под вашего контроля.

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

Идентичность, полномочия и использование секретов, это разные вопросы

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

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

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

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

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

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

Это отличается от обычной «маскировки секрета». Скрытие вывода после того, как токен попал к агенту, не убирает его из памяти, истории запросов, окружения оболочки или дочернего процесса. Если не передавать токен агенту, исчезает целый класс случаев случайного повторного использования.

Трех явных средств контроля достаточно для обычного случая с агентом

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

Во-первых, используйте абсолютную блокировку хранилища. Пока хранилище заблокировано, любое действие завершается отказом. Это дает оператору физическую и понятную точку остановки. Решение не должно зависеть от вычисления правила, сохраненной сессии или проверки сети. На Mac разблокировка через Secure Enclave и Touch ID, привязанная к оборудованию, может сделать выбор особенно ясным: оператор открыл хранилище или нет.

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

В-третьих, помечайте отдельные учетные данные для одобрения при каждом использовании. Делайте это выборочно и осознанно. Учетные данные для развертывания, способные менять инфраструктуру production, SSH-идентификатор с широким доступом к хостам или токен, с которого можно перевести деньги, могут требовать немедленного решения для каждого вызова. Повторно используемому токену только для чтения в среде разработки это обычно не нужно.

Итоговую схему легко понять:

if vault is locked:
    deny action
else if this agent process has no current session approval:
    ask for session approval
else if the selected credential requires approval per use:
    ask for credential approval
else:
    execute the action

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

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

Механизм политик оправдывает затраты, когда меняется владение ресурсами

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

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

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

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

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

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

Усталость от одобрений означает, что масштаб выбран неправильно

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

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

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

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

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

Безобидное правило может разрешить опасный запрос

Одобряйте процесс, а не ярлыки
Одобрите новый процесс агента один раз, и он сможет работать до завершения.

Типичная проблема начинается с команды, которая хочет разрешить агенту обновлять сервис в staging. Она настраивает правило, разрешающее POST-запросы к api.example.internal, если агент заявляет проект staging. Агент получает токен в окружение, потому что шлюз не умеет подставлять его напрямую.

Во время отладки агент выполняет скопированную команду с тем же именем хоста, но с адресом управления. Конечная точка принимает POST и поддерживает операцию, которая переносит конфигурацию в production. Политика видит разрешенный метод, разрешенный хост и разрешенную метку проекта. Она возвращает разрешение.

Команда может назвать это ошибкой политики, но на самом деле проблем несколько:

  1. Метод был слишком широким, чтобы описывать намерение.
  2. Атрибут проекта, которым управлял агент, не подтверждал владение.
  3. На хосте были конечные точки с совершенно разными последствиями.
  4. Токен существовал за пределами точки контроля и мог использоваться повторно после запроса.
  5. Оператор не увидел решения, отличающего обновление staging от переноса в production.

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

Лучше разделить учетные данные для staging и production. Обычная сессия может использовать staging-учетные данные через шлюз. Для production-учетных данных требуется одобрение каждого использования, а в запросе должны быть указаны цель и действие. Шлюз подставляет учетные данные и возвращает результат, при этом агент никогда не получает их значение.

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

Проверяйте пути отказа до того, как агент проверит их за вас

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

Для фиксированной схемы решений составьте таблицу ожидаемых результатов и храните ее рядом с реализацией:

Состояние хранилищаОдобрение сессииНастройка учетных данныхОжидаемый результат
заблокированоестьобычныеотказ
разблокированонетобычныезапросить одобрение сессии
разблокированоестьобычныевыполнить действие
разблокированоестьдля каждого вызовазапросить одобрение учетных данных
разблокированоотозванообычныеотказать или запросить новое одобрение сессии

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

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

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

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

Журнал аудита должен отвечать на другой вопрос, чем запрос на одобрение

Видите, кто отправляет запрос
Sallyport показывает кодовую подпись процесса при одобрении сессии.

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

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

Формулировать защиту от подделки нужно аккуратно. Хеш-цепочка может сделать последующее изменение или удаление обнаружимым, если проверяющий располагает ожидаемыми данными цепочки. Но она не доказывает, что скомпрометированная система изначально записала каждое событие. Она также не решает, было ли одобрение разумным. Журнал дает свидетельство о записанной истории, а не машину времени.

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

Sallyport записывает запуски агентов в журнал Sessions, а отдельные действия, в журнал Activity. Оба журнала строятся из зашифрованного аудита с хеш-цепочкой. Команда sp audit verify проверяет цепочку офлайн по шифротексту, и это правильный подход для журнала, который может понадобиться после того, как компьютер окажется под подозрением.

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

Выбирайте минимальную модель решений, которой сможете управлять

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

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

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

Вопросы и ответы

Чем механизм политик отличается от средств одобрения для ИИ-агентов?

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

Нужен ли ИИ-агентам механизм политик?

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

Одобрять сессию агента один раз или каждый API-вызов?

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

Почему доступ к хранилищу и авторизацию агента нужно разделять?

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

Может ли одобрение сессии быть небезопасным для автономных агентов разработки?

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

Для каких учетных данных нужно одобрение каждого вызова?

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

Что должен записывать журнал аудита действий ИИ-агента?

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

Как понять, нужны ли команде правила или фиксированные средства контроля?

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

Почему политики авторизации становится трудно поддерживать?

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

Может ли защищенный от подделки журнал аудита заменить запросы на одобрение?

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

Sallyport

Sallyport выполняет API-вызовы и SSH-команды за вашего ИИ-агента. Ключи остаются в локальном хранилище на вашем Mac; вы подтверждаете каждый запуск, и каждое действие попадает в запечатанный журнал.

© 2026 Sallyport · Открытый код по лицензии Apache-2.0 · Oleg Sotnikov