вход переехал на доверенный заголовок Authelia вместо собственного OIDC
- пришедшего называет заголовок Remote-User от прокси, и верят ему только с адреса из перечня trusted_proxies; своего входа у сервиса не осталось — ни корня /auth, ни кук, ни срока сессии, ни секрета клиента в конфиге и в базе - учётная запись заводится первым обращением: EnsureUser в пакете хранилища, шаг схемы 202608220001 с колонкой provider_login и снятыми правилами users - cmd/oidcstub заменён на cmd/devtools с подкомандой proxy; заодно закрыт унаследованный DL3066 — пользователь образа назван числом
This commit is contained in:
+38
-15
@@ -15,7 +15,7 @@
|
||||
[conventions/go-linters.md](conventions/go-linters.md).
|
||||
|
||||
- [intake](../openspec/specs/intake/spec.md) — **приём по HTTP плюс наличие
|
||||
входов**: приём за сессией, имя отправителя не доходит ни до
|
||||
входов**: приём только от узнанного, имя отправителя не доходит ни до
|
||||
хранилища, ни до журнала, метка метрики несёт только известное расширение, а
|
||||
наблюдатель видит единственный поднятый вход. Задачи
|
||||
`http-handler-tests-never-green` и `no-user-filename-in-log` 2026-08-11,
|
||||
@@ -51,9 +51,10 @@
|
||||
неизвестного пути — разметка вне корней сервиса, отказ внутри, — срок хранения
|
||||
ответов и то, что раздача пишет в журнал. Задача `spa-skeleton` 2026-08-15;
|
||||
- [access](../openspec/specs/access/spec.md) — кто пришёл в сервис и пускают ли
|
||||
его дальше: вход через внешнего провайдера OIDC, чем предъявляется сессия, что
|
||||
её прекращает и какие адреса остаются открытыми. Задача `oidc-login`
|
||||
2026-08-12. Здесь же разграничение записей по владельцу: принятая запись
|
||||
его дальше: узнавание по заголовку доверенного источника, заведение учётной
|
||||
записи первым обращением и то, какие адреса остаются открытыми. Собственный
|
||||
вход через OIDC жил здесь с 2026-08-12 по 2026-08-22 и убран задачей
|
||||
`trusted-header-login` — вместе с куками, сессией и её сроком. Здесь же разграничение записей по владельцу: принятая запись
|
||||
принадлежит тому, кто её принёс, чужая неотличима от несуществующей, а ничьей
|
||||
записи не бывает вовсе — колонка владельца пустого значения не принимает.
|
||||
Задачи `record-ownership` и `remove-telegram-intake` 2026-08-14.
|
||||
@@ -150,6 +151,18 @@
|
||||
этого шага делает хуже и молчит. Лечится повторной выкладкой нового образа;
|
||||
обратного шага схемы нет и не планируется. Порог перехода назван прямо: до
|
||||
выкладки `record-centric-model` откат образа работает, после — нет.
|
||||
- **Откат образа через шаг схемы `202608220001` обрывает вход.** Шаг закрывает
|
||||
правила коллекции пользователей наглухо, а прежний образ заводил учётную
|
||||
запись внутренним запросом обмена кода — и этот запрос закрытое правило
|
||||
отвергает. Проверено прогоном прежнего кода поверх нового каталога данных:
|
||||
вход отвечает `401`, в журнале «storage rejected the exchange with code 403».
|
||||
Порог тот же по форме, что и у `202608140002`: до выкладки
|
||||
`trusted-header-login` откат работает, после — нет, и лечится он повторной
|
||||
выкладкой вперёд. Обратного шага схемы нет и не планируется.
|
||||
|
||||
Окно этого порога сегодня пусто: сервис не выложен, а откат уже не работает с
|
||||
шага `202608140002`. Строка стоит здесь потому, что порог принято называть
|
||||
прямо, а не потому, что риск сегодня чем-то грозит.
|
||||
- **Внешние зависимости поимённо и чем каждая отказывает.** Столбец «отвечает
|
||||
медленно» читается вместе с тем, что таймаута нет ни у одного обращения
|
||||
наружу — [database.md](database.md), «Настройки с числовым значением»:
|
||||
@@ -199,7 +212,8 @@
|
||||
| Отображение доменной ошибки в ответ | `internal/controller/http.mapDomainError` — код, машиночитаемый код отказа и сообщение человеку; ветвь по умолчанию определена, новая ветвь заводится добавлением сюда. Отказы, рождённые слоями библиотеки (предел тела, ограничитель частоты, неизвестный путь), к той же форме приводит слой `OneErrorForm`, стоящий снаружи всех прочих |
|
||||
| Состояния отбора списка | `internal/entity.ListFilter` вместе с `WorkingStages` и `TerminalStages` — предикаты выводятся из дескриптора рубежа, а не пишутся строкой запроса |
|
||||
| Уборка имени файла отправителя | `internal/entity.SanitizeOriginalFilename` — режет по пределу и убирает управляющие знаки; зовёт её приём |
|
||||
| Адресное пространство сервиса | `internal/controller/http.ServiceMounts` — перечень корней и адресов наблюдения. Он **порождает** регистрацию наших маршрутов, а не описывает её, и из него же выводятся правило неизвестного пути и уровень журнала |
|
||||
| Адресное пространство сервиса | `internal/controller/http.ServiceMounts` — перечень корней и адресов наблюдения. Он **порождает** регистрацию наших маршрутов, а не описывает её, и из него же выводятся правило неизвестного пути, уровень журнала и область действия узнавания |
|
||||
| Узнавание предъявителя | `pbrepo.EnsureUser` — поиск учётной записи по логину у провайдера и заведение при первом обращении. Дом правила один и лежит в хранилище, а не в транспорте: второй способ представиться (личные токены) возьмёт этот же метод, а уложенное куском в слой оно разошлось бы двумя копиями. Транспорт читает заголовок, судит адрес пира и зовёт метод — `internal/controller/http.TrustedHeaderIdentity` |
|
||||
|
||||
Единых точек, которых **нет** и которые ожидались бы: идентификаторы
|
||||
генерируются вызовом `uuid.NewString()` по месту. Время из этого перечня ушло
|
||||
@@ -217,11 +231,20 @@
|
||||
Сборка трёхступенчатая: приложение, бинарник, рабочий слой. Приложение
|
||||
собирается первым — вшивание требует готового каталога, — а в рабочий слой Node
|
||||
не попадает. Финальный слой — alpine с `ca-certificates` и `ffmpeg`, процесс
|
||||
работает под непривилегированным пользователем `transcriber`.
|
||||
работает под непривилегированным пользователем `transcriber` — в образе он
|
||||
назван числом, `USER 1000:1000`, а не именем: имя разрешает в идентификатор сам
|
||||
образ, и хост, которому надо понять владельца файлов в смонтированном каталоге,
|
||||
разрешить его не может. Числа те же, что при заведении пользователя.
|
||||
|
||||
Ступень бинарника собирает **одну** точку входа — `./cmd/transcriber`, а не весь
|
||||
пакет: рядом в `cmd/` живёт `oidcstub`, подставной провайдер OIDC для локального
|
||||
входа, и в образе ему делать нечего.
|
||||
пакет: рядом в `cmd/` живёт `devtools`, оснастка разработчика, и в образе ей
|
||||
делать нечего.
|
||||
|
||||
Оснастка лежит **одним** пакетом с подкомандами, а не пакетом на инструмент, и
|
||||
это счёт, а не вкус: каждый отдельный пакет стоит четырёх мест — строка сборки
|
||||
здесь, «Деплой» в этом файле, «Команды» в памятке, `README`, — и забытая строка
|
||||
сборки тихо кладёт инструмент разработчика в боевой образ. Один пакет платит эти
|
||||
четыре места однажды, сколько бы подкоманд в нём ни завелось.
|
||||
|
||||
Ступень приложения стоит на образе с glibc, а не на alpine, и решает это не вес:
|
||||
у musl запрос имени идёт `A` и `AAAA` разом и ждёт **оба** ответа, поэтому
|
||||
@@ -237,13 +260,13 @@ DNS-сервер, молчащий на `AAAA`, оставляет устано
|
||||
|
||||
## Открытые вопросы
|
||||
|
||||
- **Учётные записи.** Вход через OIDC решён и развёрнут 2026-08-12: провайдер —
|
||||
Authelia, ответ провайдера обрабатывает PocketBase, а не наш код
|
||||
([ADR](adr/ADR-2026-08-11-pocketbase-storage-with-admin-panel.md)), сессия
|
||||
живёт кукой `transcriber_session` и сама себя не продлевает. Норма —
|
||||
[access](../openspec/specs/access/spec.md), решения —
|
||||
[ADR-2026-08-12-session-without-refresh](adr/ADR-2026-08-12-session-without-refresh.md)
|
||||
и [ADR-2026-08-12-oidc-exchange-via-own-route](adr/ADR-2026-08-12-oidc-exchange-via-own-route.md).
|
||||
- **Учётные записи.** Кто пришёл, сервис узнаёт заголовком, который ставит
|
||||
обратный прокси, сходив к Authelia; учётная запись заводится первым обращением
|
||||
и находится по логину у провайдера. Задача `trusted-header-login` 2026-08-22.
|
||||
Собственного входа, куки и срока сессии у сервиса не осталось — отзыв доступа
|
||||
судит провайдер на каждом запросе, а не однажды выданное значение. Норма —
|
||||
[access](../openspec/specs/access/spec.md), решение —
|
||||
[ADR-2026-08-22-login-by-trusted-header](adr/ADR-2026-08-22-login-by-trusted-header.md).
|
||||
**Не решено одно:** как связать чат Telegram с учётной записью — от этого
|
||||
зависит возвращение убранного входа.
|
||||
Панель администратора при этом Authelia не закрывает: у неё свой пароль
|
||||
|
||||
Reference in New Issue
Block a user