fix(admin): дать отзыву доступа вторую попытку, а лимиту устройств — порядок снимков
Предыдущий проход сделал правильным порядок «сначала долговременная запись, потом разрыв сессии» и правильно запретил откат при неудаче разрыва. Способа прийти к согласованному состоянию ПОТОМ он не дал: у двух операций повтор не работал вовсе. Импорт, заменивший auth_id: после неудавшегося /kick старое значение не хранится нигде, повтор того же файла читает из базы уже новое и рвёт его, а cron пропускал незнакомый authID молча — dao.ListPeer просто не возвращала строку. Живая сессия оставалась навсегда. Снижение maxDevices: повтор формы даёт 1 < 1 -> false, разрыва больше нет. Лимит устройств в политику доступа не входит и входить не должен — это свойство сессий, — поэтому механизма схождения у него не было. enforcePeerAccess стал сверкой живых сессий: обход идёт по каждому authID из /online. Нет строки в базе -> kick; peerAccessDenied -> kick; непригодный maxDevices -> kick; устройств больше разрешённого -> kick. Отказ базы при этом не рвёт ничего. Ни таблицы отложенных операций, ни очереди retry: список живых сессий уже есть, и это /online. Отдельно закрыт второй TOCTOU лимита устройств. Учёт выданных разрешений закрыл сравнение двух одинаковых снимков, но сетевой запрос выполнялся вне блокировки, поэтому снимки приходили в резервацию в произвольном порядке и устаревший откатывал lastOnline назад, возвращая уже занятое место. Это не data race — память защищена мьютексом, и -race здесь молчит принципиально. Последовательность «прочитать /online -> занять место» выполняется под замком по authId; глобальный замок не годится, внутри идёт сетевой запрос. Учёт разрешений больше не растёт бесконечно: запись снималась только на ветке отказа, поэтому в карте копились удалённые пиры и переписанные импортом идентификаторы. Уборка идёт по фактической картине подключений. Гейты приёмки доращены под все три инварианта и проверены в обе стороны. Go 1.26.7 -> 1.26.8. Документация приведена в соответствие в двух местах, где описывала снятую архитектуру. Разбор: docs/acceptance/2026-09-02-v1.0.0-rc3-preflight-findings.md
This commit is contained in:
+9
-3
@@ -46,9 +46,15 @@ HY2XS_TARGET_ARCH=amd64
|
||||
# более новые), а не по удобству.
|
||||
#
|
||||
# Было 1.21.13 — линия вне поддержки. На ней `govulncheck ./...` находил 21
|
||||
# ВЫЗЫВАЕМУЮ уязвимость, из них 17 в stdlib. На 1.26.7 — ноль.
|
||||
GO_VERSION=1.26.7
|
||||
GO_LINUX_AMD64_SHA256=ffb5f8de10c62550dfddab66b36b57030721e0a44a3218e9e1181d7b59f121ca
|
||||
# ВЫЗЫВАЕМУЮ уязвимость, из них 17 в stdlib. На 1.26.x — ноль.
|
||||
#
|
||||
# Patch-релиз держится актуальным по той же причине: stdlib целиком попадает в
|
||||
# бинарь, поэтому «на один патч позади» — это свойство выпускаемого артефакта,
|
||||
# а не среды сборки. 1.26.8 вышел 2026-09-01 (fixes в cgo, компиляторе,
|
||||
# runtime, `debug/elf` и `os`); major при этом не меняется — линия 1.26
|
||||
# поддерживается, и переход на 1.27 ради номера не нужен.
|
||||
GO_VERSION=1.26.8
|
||||
GO_LINUX_AMD64_SHA256=d0f743b33e8d8945e6b1f432edd15785c70507121d6e2a723b21285eddf8b57b
|
||||
|
||||
# Bun выбирает артефакт по наличию AVX2, поэтому одной контрольной суммы
|
||||
# архитектурно недостаточно: обе должны быть зафиксированы заранее.
|
||||
|
||||
Reference in New Issue
Block a user