ATHANOR
EN GitHub ↗

4 / 8

CLI и Store

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

Store: единственное место, где секрет живёт в памяти

internal/store.Store — прослойка между зашифрованным файлом и всем остальным (CLI, TUI, MCP-сервер). Делает она три вещи:

  • ленивая расшифровка — файл расшифровывается один раз за процесс, при первом обращении (load(), под флагом loaded), а не при каждом чтении;
  • Set/Delete — меняют карту значений в памяти и сразу перезаписывают весь secrets_file целиком через Encrypt (глава 2) — не точечно, а всем файлом за раз;
  • Run — запускает внешнюю команду, подставив каждый секрет в её окружение через exec.Cmd.Env, и пишет запись в audit-лог (глава 6).

Всё остальное в проекте — тонкая обвязка вокруг этих трёх операций.

Команды

athanor init

athanor init [--own-key] [--secrets-file PATH]

Создаёт athanor.yaml в текущей директории. Если ~/.config/athanor/identity.txt ещё нет — генерирует новую пару ключей age и предупреждает про бэкап; если уже есть — переиспользует её (отсюда и "один ключ на все проекты" из главы 2). --own-key создаёт identity локально в проекте (./identity.txt) вместо общей — для случаев, когда нужна более сильная изоляция. --secrets-file меняет путь по умолчанию (./secrets.enc.yaml) — например, чтобы сразу указать на файл, общий с другим проектом.

athanor key backup

Печатает содержимое identity-файла в stdout с предупреждением — и больше ничего умного не делает, намеренно. Единственная задача этой команды — дать вам сырой текст, который вы сами положите в менеджер паролей или на бумагу.

athanor add NAME [--expose]

athanor add DB_PASSWORD
value for DB_PASSWORD (hidden): ***
Saved DB_PASSWORD (expose=false)

Значение никогда не передаётся аргументом команды — только через скрытый ввод (term.ReadPassword, если stdin — терминал; иначе обычная строка из stdin, для случаев вроде echo "val" | athanor add KEY). Дело не в перестраховке: аргументы командной строки видны через ps любому процессу в системе, а скрытый ввод и stdin этого избегают.

Для нового имени expose по умолчанию равен false. При обновлении существующего секрета отсутствие флага сохраняет прежнюю политику; явный --expose включает выдачу через get_secret. Чтобы снова выключить её, измените expose в манифесте на false.

athanor list

Печатает имена секретов и их expose-статус — никогда значения. Тот же принцип, что и у самого манифеста: список секретов не секретен, секретны только их значения.

athanor run -- COMMAND [ARGS...]

athanor run -- npm run dev

Всё после -- — argv команды, а не строка shell. Секреты подставляются в окружение процесса и никуда больше. Это ровно тот же механизм, что и у run_with_secrets в MCP — просто вызванный человеком напрямую из терминала, без агента-посредника.

Контрольный вопрос. Почему athanor add не принимает значение секрета аргументом командной строки (athanor add KEY value), а всегда запрашивает его отдельно?

Ответ: аргументы команды видны любому локальному процессу через ps — значение оказалось бы в открытом виде в списке процессов, пусть и ненадолго. Скрытый ввод и stdin этого не допускают.