docs: record implementation decisions in code review plan
test / test (push) Has been cancelled

Resolved open questions: fail-open+log for auth IP, add CSRF tokens,
typed template structs, slog migration, rate limiter eviction policy
(nearest-expiry, blocked buckets protected), guide URL as full path.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
mix
2026-08-19 17:23:21 +03:00
co-authored by Cursor
parent 0aa7318a41
commit 5a41d34cac
+8 -6
View File
@@ -36,7 +36,7 @@ SelfPost — зрелый, хорошо структурированный пр
### 2.4 [Low] Утечка резервации inflight при обрыве SMTP ### 2.4 [Low] Утечка резервации inflight при обрыве SMTP
- **Файл:** `internal/milter/inflight.go` - **Файл:** `internal/milter/inflight.go`
- **Суть:** если SMTP-соединение обрывается без `Abort()`, резервация живёт до TTL (60 сек). При высокой нагрузке возможен ложный отказ. - **Суть:** если SMTP-соединение обрывается без `Abort()`, резервация живёт до TTL (60 сек). При высокой нагрузке возможен ложный отказ.
- **Исправление:** TTL достаточен, но стоит задокументировать компромисс. - **Исправление:** задокументировать компромисс в `docs/security.md`.
--- ---
@@ -61,7 +61,8 @@ SelfPost — зрелый, хорошо структурированный пр
### 4.1 [Medium] Fail-open milter auth IP при ошибке БД ### 4.1 [Medium] Fail-open milter auth IP при ошибке БД
- **Файл:** `internal/milter/authip.go` - **Файл:** `internal/milter/authip.go`
- **Суть:** при недоступности БД `authIPAllowed()` возвращает `true` — любой IP может отправлять. - **Суть:** при недоступности БД `authIPAllowed()` возвращает `true` — любой IP может отправлять.
- **Исправление:** логировать предупреждение, рассмотреть опциональный fail-closed режим. - **Исправление:** оставить fail-open + добавить warning log.
- **Решение:** (b) fail-open с предупреждением.
### 4.2 [Medium] Нет ограничения stdin в DMARC-ingest ### 4.2 [Medium] Нет ограничения stdin в DMARC-ingest
- **Файл:** `cmd/panel/dmarc_ingest.go` - **Файл:** `cmd/panel/dmarc_ingest.go`
@@ -71,12 +72,12 @@ SelfPost — зрелый, хорошо структурированный пр
### 4.3 [Medium] Вытеснение bucket'ов в auth rate limiter ### 4.3 [Medium] Вытеснение bucket'ов в auth rate limiter
- **Файл:** `internal/web/auth/ratelimit.go`, `makeRoom()` - **Файл:** `internal/web/auth/ratelimit.go`, `makeRoom()`
- **Суть:** при >10000 IP атакующий может вытеснить легитимные rate-limit записи, сбросив счётчики. - **Суть:** при >10000 IP атакующий может вытеснить легитимные rate-limit записи, сбросив счётчики.
- **Исправление:** вытеснять bucket с ближайшим expiry, а не самый старый. - **Исправление:** вытеснять bucket с ближайшим expiry, но заблокированные bucket'ы (failures >= max) не вытесняются до истечения TTL.
### 4.4 [Medium] Нет CSRF-токенов — только `Sec-Fetch-Site` / `Origin` ### 4.4 [Medium] Нет CSRF-токенов — только `Sec-Fetch-Site` / `Origin`
- **Файл:** `internal/web/security.go` - **Файл:** `internal/web/security.go`
- **Суть:** защита зависит от браузера. В `docs/security.md` решение задокументировано с обоснованием, но defense-in-depth рекомендует токен. - **Суть:** защита зависит от браузера. В `docs/security.md` решение задокументировано с обоснованием, но defense-in-depth рекомендует токен.
- **Статус:** осознанный компромисс; задокументирован. Оставить как есть или добавить per-session токен. - **Решение:** добавить per-session CSRF-токен.
### 4.5 [Low] CSP `unsafe-inline` для стилей ### 4.5 [Low] CSP `unsafe-inline` для стилей
- **Файл:** `internal/web/security.go` - **Файл:** `internal/web/security.go`
@@ -169,14 +170,14 @@ SelfPost — зрелый, хорошо структурированный пр
### 8.1 [Medium] CHANGELOG записывает удаление plan-файлов, которые ещё не удалены ### 8.1 [Medium] CHANGELOG записывает удаление plan-файлов, которые ещё не удалены
- **Суть:** `[Unreleased]` Removed перечисляет 6 plan-файлов, но файлы ещё на диске. - **Суть:** `[Unreleased]` Removed перечисляет 6 plan-файлов, но файлы ещё на диске.
- **Исправление:** удалить файлы или убрать запись из CHANGELOG. - **Исправление:** проверить — файлы уже удалены; если да, пункт закрыт.
### 8.2 [Minor] `schema-migrations.md` — заголовок говорит v9, цепочка на v10 ### 8.2 [Minor] `schema-migrations.md` — заголовок говорит v9, цепочка на v10
- **Исправление:** обновить заголовок и добавить индекс из миграции 0010. - **Исправление:** обновить заголовок и добавить индекс из миграции 0010.
### 8.3 [Low] ~40 ссылок на `spec N` в build/deploy-файлах ### 8.3 [Low] ~40 ссылок на `spec N` в build/deploy-файлах
- **Суть:** CHANGELOG `[0.5.0]` говорит «код больше не ссылается на спецификацию», но shell-скрипты и Dockerfile не были очищены. - **Суть:** CHANGELOG `[0.5.0]` говорит «код больше не ссылается на спецификацию», но shell-скрипты и Dockerfile не были очищены.
- **Исправление:** удалить или заменить ссылки на spec в build/, deploy/, Makefile, ранних миграциях. - **Исправление:** удалить ссылки на spec; где уместно — заменить на ссылку на актуальный документ.
### 8.4 [Low] `dmarc-ingest` symlink не документирован в `architecture.md` ### 8.4 [Low] `dmarc-ingest` symlink не документирован в `architecture.md`
- **Исправление:** добавить абзац в секцию Mail path. - **Исправление:** добавить абзац в секцию Mail path.
@@ -227,6 +228,7 @@ SelfPost — зрелый, хорошо структурированный пр
### 10.2 [Low] Hardcoded URL guide ### 10.2 [Low] Hardcoded URL guide
- `help.html` и `help_drawer.html` содержат захардкоженный GitHub URL вместо `{{.SourceURL}}`. - `help.html` и `help_drawer.html` содержат захардкоженный GitHub URL вместо `{{.SourceURL}}`.
- **Решение:** формировать полный путь `{{.SourceURL}}/blob/main/docs/...`.
### 10.3 [Low] `.pair` vs `.split` — непоследовательность имён ### 10.3 [Low] `.pair` vs `.split` — непоследовательность имён
- DMARC-шаблоны используют `class="pair"` для того же layout, что другие страницы называют `class="split"`. - DMARC-шаблоны используют `class="pair"` для того же layout, что другие страницы называют `class="split"`.