Повторный анализ кодовой базы (docs/reviews/2026-09-26-codebase-review-2.md) и доработки:
025 Ёмкость префикса — размер его подсети (а не сумма листьев); «Обзор» считает ёмкость
по корневым активным IPv4-префиксам и адреса внутри них.
026 Политика блокировки входа: 5 неудач на логин+IP, 20 на IP, 50 на логин со всех IP,
кроме известных IP (known_logins, миграция 0009) — владельца нельзя заблокировать анонимно.
027 Сериализация попыток входа по IP (advisory-lock после блокировки логина).
028 UI «Префиксы»: загрузка всех страниц (до 20 000), счётчики по total, предупреждение об усечении.
029 Advisory-lock по VRF для операций, меняющих дерево префиксов и раскладку адресов.
030 Исправление замечаний ревью 025-029: _lock_prefix (VRF блокируется до чтения префикса,
409 при одновременном переносе), константы политики входа перенесены в app/services.py.
Тесты: 14 passed (проверка ёмкости родителя приведена к семантике 025); сквозные сценарии
и гонки — docs/reviews/2026-09-26-changes-025-029-review.md, 2026-09-27-changes-030-review.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.3 KiB
5.3 KiB
Исправление замечаний 1–2 ревью изменений 025–029 (изменение 030)
Источник: docs/reviews/2026-09-26-changes-025-029-review.md, замечания № 1 и № 2. Только код. Тесты исполнитель не пишет и не запускает (тестирование — отдельный шаг).
1. Чтение префикса до блокировки VRF (низкая, 029)
Где: app/api/v1/prefixes.py — delete_prefix, update_prefix (при смене VRF), create_address.
Суть: префикс читается через get_or_404 до _lock_vrf. Возникают две проблемы:
- в
delete_prefixустаревшийp.parent_idиспользуется для переподвешивания детей; - если префикс параллельно переносят в другой VRF, блокируется не тот VRF (
p.vrf_idпрочитан до блокировки).
Решение:
- Хелпер
_lock_prefix(db, id: int, *extra_vrf_ids: int) -> Prefixрядом с_lock_vrf:- прочитать
vrf_idпрефикса отдельнымSELECT Prefix.vrf_id; нет строки — 404 «Префикс не найден»; _lock_vrf(db, vrf_id, *extra_vrf_ids)— все VRF одним вызовом, порядок по возрастанию id уже обеспечен_lock_vrf;- перечитать префикс под блокировкой:
select(Prefix).where(Prefix.id == id).with_for_update().execution_options(populate_existing=True), чтобы не взять устаревший объект из identity map сессии; - если перечитанный
vrf_idотличается от заблокированного (префикс успели перенести), повторить цикл, не больше 3 попыток, затем 409 «Префикс одновременно изменяется, повторите запрос». Блокировки транзакции при повторе не снимаются, это допустимо: порядок захвата внутри одной попытки по-прежнему возрастающий. Если «лишняя» блокировка ухудшает порядок между попытками, допустимо вместо повтора сразу возвращать 409. Выбрать вариант и указать его в SUMMARY.
- прочитать
- Применение:
delete_prefix:p = _lock_prefix(db, id)вместоget_or_404+_lock_vrf;create_address: то же;update_prefix: целевой VRF (body.vrf_id) известен из тела запроса до чтения префикса, поэтомуp = _lock_prefix(db, id, new_vrf)при заданномvrf_id, иначе обычныйget_or_404(без смены VRF дерево не меняется). Еслиnew_vrfсовпал с текущимp.vrf_id, лишняя блокировка того же VRF безвредна.allocate_subnetиallocate_nextуже читаютvrf_idдо блокировки; перевести их на_lock_prefixдля единообразия, сохранив поведение (FOR UPDATEстроки префикса есть в хелпере).
- Комментарии — кратко, со ссылкой на изменение 030.
2. Зависимость ротации от API-слоя (низкая, 026)
Где: app/rotation.py импортирует KNOWN_IP_DAYS из app.api.v1.auth.
Решение:
- Перенести константы политики входа —
LOGIN_WINDOW(сейчасWINDOW),MAX_PER_LOGIN_IP,MAX_PER_IP,MAX_PER_LOGIN,KNOWN_IP_DAYS— вapp/services.pyотдельным блоком с комментарием. app/api/v1/auth.pyимпортирует их изapp.services; внутренние имена вauth.pyне должны расходиться с перенесёнными.WINDOWзаменить наLOGIN_WINDOWпо месту, модульная docstring с.format(...)продолжает работать.app/rotation.pyимпортируетKNOWN_IP_DAYSизapp.services; импортapp.api.v1.authудалить.- Пространства ключей advisory-lock (
LOGIN_LOCK_NS,IP_LOCK_NS) остаются вauth.py.
Артефакты
docs/changes/030-review-fixes-025-029/SUMMARY.md: что сделано, выбранный вариант повтора из п. 1, отклонения.README.md— только если меняется описанное поведение (ожидается, что не меняется).
Проверка (выполняет ревьюер, не исполнитель)
- Импорт приложения;
rotation.pyне импортирует API-модули. - Параллельные сценарии по п. 1: удаление префикса ∥ вставка промежуточного префикса; перенос префикса в другой VRF ∥ создание адреса / удаление.
- Регрессия:
pytest -q.