# ADR-0001: sops-пути — только через `config.sops.secrets..path` **Статус:** accepted **Дата:** 2026-10-09 **Контекст:** sops-nix материализует секреты на `/run/secrets/` по умолчанию. Атрибут sops-блока (`config.sops.secrets.`) — единственный источник истины для on-disk пути. Любой `path =` override на sops-блоке плюс хардкод `"/run/secrets/"` в потребителе делает потребителя **молча** сломанным: `nixos-rebuild` проходит, сервис стартует, файл читается — но контент от прошлой версии или пустой. Симптом приходит из рантайма, не из CI. До этой правки (см. «Обратное») в кодовой базе были хардкоды путей в 5 местах: `authelia.nix`, `open-webui.nix`, `tape-rotation.nix`, `remnawave.nix`. В `remnawave.nix` тот же риск был двойной: путь хардкожен и в генераторе, и в контейнере → расхождение двух копий = silent breakage. **Рассматриваемые альтернативы:** 1. **A. `${config.sops.secrets..path}`** — единая точка истины. Любой `path =` override автоматически подхватывается потребителем. 2. **B. Хелпер `sopsPath = name: "/run/secrets/${name}"`** — был в `authelia.nix:51` до правки. Компактнее в написании, но тащит хардкод `/run/secrets/` в API и делает невозможным `path =` override без правки потребителя. 3. **C. `let envFile = "/run/secrets/${name}"; in { … }` для композитных случаев** — для `remnawave.nix`, где один и тот же env-файл читается и генератором, и контейнером. Используется, но с явным комментарием. **Решение:** выбран вариант **A** для прямого доступа к одному секрету и вариант **C** для композитных env-файлов в `remnawave.nix` (с комментарием). **Обоснование:** - **Единая точка истины.** Атрибут sops-блока — единственное место, где определяется on-disk путь. Потребитель ссылается на `${config.sops.secrets..path}`. - **Симметрия с `mkUserSecret`.** `users.nix:33-41` уже использует этот паттерн (`config.sops.secrets..path`) — единый стиль по репо. - **Без хелпера.** `sopsPath = name: "/run/secrets/${name}"` выглядит компактнее, но скрывает хардкод `/run/secrets/`. Когда кто-то добавит `path = "/var/lib/..."` в sops-блок, потребитель через хелпер молча сломается. - **Двухкопийный env-файл в remnawave.nix** — композитный случай, где `let`-биндинг в одном scope с комментарием «не дублировать литерал» делает связь явной. **Последствия:** - Позитивные: - `nix flake check` (после T1, T2) ловит несоответствие путей в compile-time. - `path =` override в sops-блоке не ломает потребителя молча. - Единый стиль по репо: 5 мест исправлены, новые пишутся по образцу. - Негативные: - Длиннее в написании, чем `"/run/secrets/${name}"`. - Риски: - Если кто-то добавит нового потребителя sops и напишет литерал `/run/secrets/` — молчаливое расхождение. Защита: код-ревью + кандидат в CI-проверки (`secrets/missing-paths.nix` или grep). **Invariant:** > Любой потребитель sops-секрета в `modules/` ссылается на путь через > `${config.sops.secrets..path}`, а не через литерал > `"/run/secrets/"`. Атрибут sops-блока — единственный источник > истины для on-disk пути. Зафиксировано в `.agent/rules/project-rules.md` (R1.7) + `analysis-report.md §8`. **Обратное (где было сломано до этой правки):** - `modules/server/authelia.nix:51,108,109` — через хелпер `sopsPath = name: "/run/secrets/${name}"`. - `modules/containers/open-webui.nix:95` — литеральный хардкод. - `modules/containers/tape-rotation.nix:61` — литеральный хардкод. - `modules/containers/remnawave.nix:61, 129, 136` — литеральный хардкод, в двух местах (генератор + контейнер). **Затронутые файлы (после правки):** - `modules/server/authelia.nix:107-108` - `modules/containers/open-webui.nix:101` - `modules/containers/tape-rotation.nix:63` - `modules/containers/remnawave.nix:16, 70, 138, 145` — `let`-биндинг для композитного env-файла (вариант C).