8 / 8
Сквозные потоки и диагностика
Все прошлые главы разбирали части системы по отдельности. Эта собирает их в одну картину и работает как справочник — сюда стоит вернуться, когда что-то ведёт себя не так, как ожидалось.
Вся система целиком
┌────────────────────────┐
│ athanor.yaml │ публичный ключ, expose-флаги,
│ (не секретен, можно │ access_mode, deploy.remote_path
│ коммитить в git) │
└───────────┬────────────┘
│ описывает политику для
▼
athanor init ──► age identity ──► ~/.config/athanor/identity.txt
(общая на все (приватный │ единственный способ
проекты, если ключ) │ расшифровать
не --own-key) ▼
┌──────────────────┐
athanor add ───────стдин─────►│ internal/store │◄──── Store.Get/Set/Run
(значение не (json) │ (в памяти │ единая точка входа
аргументом!) │ │ процесса) │ для всех каналов
▼ └─────────┬──────────┘
sops --encrypt │
(age-recipient) │ Store.Run(): подстановка в
│ │ exec.Cmd.Env дочернего процесса
▼ │
secrets.enc.yaml ◄────────┘
(всегда зашифрован)
│
┌─────────────┼──────────────────┬───────────────────┐
▼ ▼ ▼ ▼
athanor list athanor tui athanor serve-mcp athanor deploy
(имена, не (человек, (агент, недоверенный (копирует бинарник +
значения) доверенный контекст — Exposable() манифест + secrets.enc.yaml
локальный проверяется только + identity.txt на VPS)
контекст) для get_secret)
Каналы доступа: кто что видит
| Канал | Проверяет expose? |
Что в итоге видит потребитель | Пишет в audit-лог? |
|---|---|---|---|
athanor list |
— (не отдаёт значения вовсе) | только имена секретов | нет |
athanor tui (enter/y) |
нет — доверенный локальный контекст | значение секрета | нет |
athanor run -- CMD |
нет | окружение CMD; команда может напечатать или отправить секрет |
да |
MCP get_secret |
да | значение секрета текстом (только если Exposable(name)) |
нет |
MCP run_with_secrets |
нет | окружение и вывод CMD; команда может напечатать или отправить секрет |
да |
athanor deploy <host> |
— (переносит весь набор целиком) | сервер получает и шифротекст, и сам ключ | нет |
Порядок диагностики
Когда система ведёт себя не так, как ожидалось, есть смысл проверять по порядку — от фундамента наверх:
- Ничего не расшифровывается (
athanor list/run/tuiпадают с ошибкой sops) — проверьте, что identity-файл лежит по ожидаемому пути (./identity.txt, если проект создавался с--own-key, иначе~/.config/athanor/identity.txt) и что его публичный ключ совпадает сrecipientвathanor.yaml. Расхождение ключа иrecipient— самая частая причина. get_secretотказывает, хотя вы ждали значение — проверьтеexposeу конкретного секрета вathanor.yamlиaccess_modeна верхнем уровне манифеста. Помните:--full-accessуserve-mcpиaccess_mode: fullв файле — два независимых способа получить один и тот же эффект.run_with_secretsотрабатывает, но нужного значения нет в выводе команды — это не баг: секрет доступен через переменную окружения внутри запущенного процесса, а сам вывод инструмента — это только stdout/stderr этого процесса. Если команда не печатает переменную явно, инструмент её и не покажет. Если команда печатает много данных, проверьте такжеstdoutTruncated/stderrTruncated: каждый поток ограничен 1 МиБ.- Общий секрет между проектами не синхронизируется — проверьте, что
оба
athanor.yamlуказывают на буквально один и тот жеsecrets_file— путь разрешается относительно каждого манифеста отдельно, и легко случайно получить два разных файла с похожими путями. athanor deployпадает на smoke-тесте — проверьте вручнуюssh <host>тем же способом, каким пользуется deploy (алиас или ключ из~/.ssh/config). Deploy не решает проблемы SSH-доступа сам, только сообщает о них.
Контрольный вопрос. У вас два проекта на разных VPS, у секрета в одном
из них стоит expose: true, но при вызове get_secret через MCP-сервер
второго проекта тот же секрет недоступен. Это баг?
Ответ: нет. athanor serve-mcp, запущенный из каталога одного проекта,
работает только с манифестом и secrets_file этого проекта — даже если оба
проекта используют один и тот же общий age-ключ, expose-флаги и сам
список секретов у каждого манифеста свои, если только оба явно не
указывают на один secrets_file.