Зачем AI-ассистенту отдельный механизм доступа
В работе с несколькими проектами быстро накапливаются токены GitLab, пароли баз данных и доступы к серверам. Ассистент помогает запускать проверки и разбирать ошибки, но передавать ему каждый секрет сообщением неудобно: значение оказывается в истории задачи, а потом может попасть в команду, лог или скопированный пример.
В моей рабочей схеме значения хранятся в macOS Keychain, а отдельно лежит реестр проектов и окружений. Ассистент выбирает нужный ресурс по имени, локальный инструмент получает доступ и выполняет операцию. В задачу возвращается результат проверки. Ниже — упрощённая версия этого подхода, которую можно собрать у себя без копирования чужой инфраструктуры.
Для повторения нужны Mac, Python 3.9 или новее и AI-ассистент с разрешённым локальным запуском команд. Обычный чат в браузере и облачный контейнер не получают доступ к связке ключей вашего Mac автоматически. Пример рассчитан на локальную сессию пользователя; он не устанавливает хранилище секретов для удалённых CI-воркеров.
Три части: Keychain, реестр и локальный помощник
| Часть | Содержимое | Назначение |
|---|---|---|
| macOS Keychain | Значение токена или пароля | Хранение секрета средствами системы. |
| Реестр доступов | Проект, окружение, ресурс, адрес и ссылка на запись Keychain | Однозначный выбор цели без хранения самого секрета. |
| Локальный помощник | Код одной разрешённой операции | Проверить цель, прочитать секрет, обратиться к сервису и отфильтровать результат. |
| Skill | Когда и как вызвать помощник | Сделать процедуру понятной ассистенту. |
Полезный идентификатор доступа — проект / окружение / ресурс. Например, demo-web / dev / gitlab. Один hostname или слово «сервер» не определяют, какой доступ нужен. У одного проекта могут быть разные базы и API, а у одного сервера — несколько окружений.
В полной рабочей версии стоит дополнительно сверять корень Git-репозитория и его origin. Учебный помощник из этой статьи проверяет точное совпадение тройки в реестре, но не определяет принадлежность текущей рабочей копии и не проверяет ветку. Это осознанная граница небольшого примера.
Что такая схема защищает, а что остаётся в зоне доверия
Практический результат — секрет не приходится вставлять в промпт, исходники, аргументы HTTP-команды или обычный вывод инструмента. Локальный процесс всё равно получает значение в память, а целевой сервис получает его в запросе по HTTPS. Для авторизации это необходимо.
Если ассистент может выполнять любые команды от вашего пользователя, читать Keychain или менять помощник и реестр, он потенциально может обойти этот рабочий маршрут. Инструкция «не показывай токен» и файл SKILL.md не создают технический запрет. Для более строгой границы нужен отдельный ограниченный исполнитель и контроль разрешённых операций.
Управляйте также правами самого токена. Для проверки профиля не нужен доступ к выпуску релизов или администрированию. Права локального файла 0600 ограничивают доступ других обычных пользователей; они не защищают от другого процесса того же пользователя или администратора.
Шаг 1. Подготовить пример и токен с минимальными правами
Скачать пример: помощник, skill, реестр и тесты · SHA-256 архива. Архив содержит открытый исходный код без рабочих адресов и учётных данных. Сначала просмотрите его; команды ниже выполняются из распакованного каталога.
Пример умеет две вещи: проверить наличие записи и выполнить GET /api/v4/user в GitLab. Для второго действия создайте в своём GitLab personal access token со scope read_user и подходящим сроком действия. Этот scope даёт чтение профиля пользователя; он не предназначен для чтения pipeline или публикации релизов. Описание scopes в GitLab.
Создавайте токен самостоятельно в интерфейсе сервиса. Не отправляйте его ассистенту. В следующем шаге он понадобится только для скрытого ввода в локальном терминале.
python3 --version
python3 -m unittest discover -s tests -v
Тесты используют вымышленные значения и подменяют Keychain и HTTP-вызовы. Они проверяют поведение помощника, не создавая токены и не обращаясь к вашему GitLab.
Шаг 2. Описать цель без секретных значений
В файле registry.example.json замените демонстрационный HTTPS-адрес на адрес своего GitLab. В этом примере поддерживается GitLab в корне домена на стандартном порту 443. Адрес не должен содержать логин, пароль, токен, query string или путь к API.
{
"version": 1,
"targets": [
{
"project": "demo-web",
"environment": "dev",
"resource": "gitlab",
"origin": "https://gitlab.example.com",
"keychain_service": "agent-access.demo-web.dev.gitlab",
"keychain_account": "read-user"
}
]
}
Имена demo-web, dev и gitlab — учебные. Если вы меняете их, согласованно измените keychain_service и команды. read-user — метка записи, не ваш логин в GitLab. Метка dev также не ограничивает права токена на стороне сервиса: их задаёт сам GitLab.
mkdir -p "$HOME/.config/agent-access"
chmod 700 "$HOME/.config/agent-access"
test ! -e "$HOME/.config/agent-access/registry.json" && \
install -m 600 registry.example.json \
"$HOME/.config/agent-access/registry.json"
Если реестр уже существует, последняя команда его не заменит. Просмотрите текущую конфигурацию и добавьте новую цель вручную, избегая дубликатов. Реестр находится вне репозитория: значения секретов там отсутствуют, но реальные адреса и названия ресурсов всё равно могут быть внутренней информацией.
Шаг 3. Добавить токен в Keychain через скрытый ввод
Откройте обычный локальный терминал без записи сессии и выполните команду самостоятельно. Встроенная справка security help add-generic-password рекомендует ставить -w последним аргументом, чтобы получить приглашение ввода вместо передачи значения в командной строке.
/usr/bin/security default-keychain -d user
/usr/bin/security add-generic-password \
-s agent-access.demo-web.dev.gitlab \
-a read-user \
-T "" \
-w
Первая команда показывает выбранную по умолчанию пользовательскую связку. Вторая добавляет запись в неё и запрашивает значение без отображения. После -w ничего не дописывайте: токен вводится в появившееся приглашение. В команде нет -U, поэтому существующая запись не будет молча заменена. -T "" убирает автоматическое доверие к приложению, создающему запись.
При последующем чтении macOS может показать системное окно разрешения. Решение в нём принимает владелец Mac. Разовое разрешение и постоянное доверие — разные действия; постоянное разрешение общему инструменту вроде /usr/bin/security не ограничивается одним skill. Не выбирайте доступ для всех приложений ради устранения запроса. Как Apple описывает доступ приложений к Keychain.
Не запускайте вручную извлечение с выводом значения «для проверки». Наличие записи и возможность авторизации проверяются отдельными командами ниже.
Шаг 4. Проверить доступ через помощник
python3 keychain-gitlab-read/scripts/gitlab_read.py \
status demo-web dev gitlab
python3 keychain-gitlab-read/scripts/gitlab_read.py \
check demo-web dev gitlab
status ищет метаданные записи без запроса её значения. check читает токен внутри процесса, выполняет фиксированный HTTPS-запрос и выдаёт краткий результат. Например:
{"target":"demo-web/dev/gitlab","origin":"https://gitlab.example.com","operation":"check"}
{"status":"authenticated"}
Здесь адрес намеренно демонстрационный: до его замены реальный check откажется работать. Первая строка — предварительная информация о цели; вторая появится только после успешной проверки вашего сервиса.
В gitlab_read.py нет произвольного URL, shell-команды, метода записи или функции «показать токен». Используется стандартная проверка TLS; перенаправления отклоняются. Токен проходит из захваченного вывода системной утилиты в память помощника и затем в заголовок запроса. Тело ответа API, заголовки и исключения с деталями запроса не печатаются.
Это полезнее общего secret exec ... для первого примера: у команды маленькая, проверяемая задача. Если другой инструмент требует переменную окружения, помните, что секрет станет доступен этому процессу и может попасть в его диагностику. Такой способ передачи требует отдельной проверки логирования.
Шаг 5. Подключить skill к AI-ассистенту
В архиве есть готовая папка keychain-gitlab-read. В актуальной документации Codex пользовательские skills размещаются в ~/.agents/skills; для навыков репозитория предусмотрена .agents/skills внутри проекта. Проверьте расположение, которое поддерживает установленная версия вашего ассистента. Документация по skills.
mkdir -p "$HOME/.agents/skills"
test ! -e "$HOME/.agents/skills/keychain-gitlab-read" && \
cp -R keychain-gitlab-read "$HOME/.agents/skills/"
После установки убедитесь, что навык появился в списке; при необходимости откройте новую сессию. Его можно явно вызвать так:
Используй $keychain-gitlab-read.
Проверь авторизацию demo-web / dev / gitlab.
Верни только цель и статус, без значения токена.
SKILL.md объясняет, когда выбирать помощник, какие команды разрешены и как трактовать ошибки. Код выполняет проверку. Общие договорённости репозитория можно записать в AGENTS.md, но не нужно копировать туда реестр и секреты. Инструкции через AGENTS.md.
У другого AI-ассистента формат подключения может отличаться. Сохраните те же границы: локальный вызов проверенного помощника, точная цель, ограниченная операция и небольшой результат. Если доступен только MCP, обёртка должна предоставлять конкретную операцию проверки, а не метод, возвращающий произвольный секрет.
Как читать результаты и не перепутать отказ с отсутствием
| Результат | Что подтверждено | Следующее действие |
|---|---|---|
present | Найдены метаданные записи. | При необходимости выполнить авторизованный check; значение может быть недоступно или просрочено. |
not_found | В выбранной связке не найдено совпадение. | Сверить связку, service и account вручную. Не создавать дубликат вслепую. |
unavailable / keychain_unavailable | Проверка или чтение не завершились. | Проверить локальную сессию, блокировку и разрешение системы. Не считать запись потерянной. |
authenticated | Фиксированный запрос к профилю прошёл. | Не делать вывод о правах на репозиторий, CI или релиз. |
gitlab_http_401 / gitlab_http_403 | API отклонил запрос. | Сверить срок, scope и сервер. Не печатать токен для диагностики. |
redirect_refused | Сервис вернул перенаправление. | Проверить адрес и конфигурацию сервиса; не пересылать секрет на новый адрес автоматически. |
Общий request_failed намеренно не раскрывает детали запроса. Начните с проверки DNS, времени на Mac, HTTPS-сертификата и доступности сервиса без токена. Не отключайте проверку сертификата ради прохождения теста.
Готовый промпт для адаптации под свою работу
Если нужен другой API или более строгая привязка к проектам, передайте ассистенту требования и исходники примера. Значения секретов для проектирования не нужны.
Адаптируй локальный механизм доступа для моего AI-ассистента на macOS.
Сначала прочитай пример и согласуй недостающую цель:
проект, окружение, ресурс и разрешённую операцию.
Значения секретов храни в Keychain, ссылки на записи —
в отдельном реестре вне репозитория.
Сделай помощник с точным выбором цели и ограниченным набором действий.
Для работы с кодом сверь корень Git и очищенный от credentials origin.
Не добавляй произвольные URL, shell-команды или вывод секретов.
Читай секрет внутри локального процесса и не включай его
в аргументы команд, логи, отчёты и результаты для модели.
Проверяй TLS; не пересылай авторизацию при перенаправлении.
Подготовь SKILL.md, установку и тесты на вымышленных данных:
неверное окружение, дубликат цели, отказ Keychain,
редирект, ошибка API и отсутствие секрета в выводе.
Для первоначального ввода дай мне скрытое приглашение в терминале.
Не запрашивай токен в чате. Начни с операции чтения;
новые действия записи требуют отдельного согласованного объёма работы.
После адаптации проверьте не только удачный сценарий. Команда для отсутствующего окружения должна остановиться до чтения Keychain. Ошибка API не должна распечатывать заголовки. Если тестовый сервер отражает присланное значение в ответе, помощник не должен передать его модели.
Как развивать схему: Git, серверы и смена токенов
Для Git по HTTPS используйте механизм credential helper, для SSH — ключи и агент SSH; этот пример generic password предназначен для API-токена. Пароль базы, токен чтения задач и право выпуска релиза должны быть отдельными ресурсами, если у них разные области применения. Реестр помогает выбрать их, но не заменяет права на стороне сервиса.
При ротации сначала определите запись по точной тройке, обновите её через скрытый ввод и проверьте нужную операцию. Если сервис допускает параллельное действие токенов, старый можно отозвать после проверки нового. При утечке старое значение следует отозвать сразу, даже если придётся прервать работу. Удаление сообщения или очистка локального файла не отзывает токен.
На удалённом сервере и в CI нужен собственный способ выдачи секретов. Постоянно доступная login-связка рабочего Mac не должна становиться зависимостью unattended-задач. Этот материал решает более узкую задачу: удобная локальная работа ассистента без обычного копирования секретов в переписку.
О том, как такой доступ дополняет локальную разработку и проверку релизов, — в статье о GitLab, OrbStack и AI-агентах.
Что проверено в опубликованном примере
Исходный код помощника прошёл 11 автоматических проверок: выбор цели, права реестра, отсутствие секретов в аргументах и выводе, отказ от HTTP и перенаправлений, различение ошибок Keychain и фильтрация результата. Формат skill проверен валидатором. Команда скрытого ввода сверена со встроенной справкой macOS.
Рабочие учётные данные в этот публичный пример не переносились. Тесты подменяют Keychain и сеть; успешная авторизация в конкретном GitLab читателя проверяется им после настройки. Это небольшой исходный пример для адаптации, без обещания изоляции от произвольного кода того же пользователя.
