test(tradein/auth): сторож не должен зеленеть от съехавшей области (#2715)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 3m6s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped

Ревью: `rglob` по несуществующему каталогу не падает — отдаёт пусто, нарушителей
ноль, тест зелёный навсегда. Достаточно переложить файл в подкаталог tests/
(их восемь, и прецедент такого сторожа лежит именно в подкаталоге), чтобы
`parents[1]` уехал и сторож замолчал. Ровно тот класс, от которого детектор уже
защищён (test_detector_actually_detects), а область — нет. Одна строка:
`_OWNER.exists()` в теле теста; проверено мутацией области — краснеет.

Плюс слепые зоны названы и закреплены исполняемо: строковый доступ
`getattr(mod, "verify_password")` и прямой `bcrypt.checkpw` в обход модуля
сторож НЕ ловит. От намеренного обхода он не защищает и не может — только от
нечаянного. Было требованием ревью назвать это в коде, а не подразумевать.

Refs #2715
This commit is contained in:
bot-backend 2026-08-06 19:20:19 +05:00
parent 1dc3a08563
commit 3a7dbd4dda

View file

@ -20,6 +20,13 @@
которую `grep 'verify_password('` не поймал бы вовсе то есть ровно ту, ради
которой сторож и написан.
ЧЕГО СТОРОЖ НЕ ВИДИТ, и это записано тут, а не подразумевается: строкового
доступа (`getattr(mod, "verify_password")`) и обхода модуля целиком (прямой
`bcrypt.checkpw`). От НАМЕРЕННОГО обхода он не защищает и не может только от
нечаянного, а нечаянный и есть частый случай. Обе непойманные формы закреплены
исполняемо (`test_detector_blind_spots_are_known`), чтобы «не ловим» было
проверенным фактом, а не обещанием в тексте.
Без БД и без сети только чтение файлов.
"""
@ -68,8 +75,28 @@ def test_detector_actually_detects() -> None:
assert not _references_verify_password("# verify_password тут только в комментарии")
def test_detector_blind_spots_are_known() -> None:
"""Слепые зоны — зафиксированы, а не забыты.
Обе формы обходят сторож НАМЕРЕННЫМ усилием: строковый доступ к атрибуту и
обход модуля целиком. Ловить их AST'ом можно было бы только ценой ложняков
(любой `getattr` с любой строкой, любой вызов bcrypt), а цена ложняка
требование выключить сторож. Тест держит это знание исполняемым: захочет
однажды детектор их ловить покраснеет здесь и заставит осознанно
переписать и этот тест, и текст модуля.
"""
assert not _references_verify_password('fn = getattr(password_mod, "verify_password")')
assert not _references_verify_password("bcrypt.checkpw(plain.encode(), hashed.encode())")
def test_sync_verify_password_is_called_from_one_place_only() -> None:
"""В `app/` синхронную сверку не поминает никто, кроме её собственного модуля."""
# Область сканирования жива. `rglob` по несуществующему каталогу не падает —
# отдаёт пусто, нарушителей ноль, сторож зелен НАВСЕГДА. Достаточно
# переложить этот файл в подкаталог tests/ (их уже восемь, и прецедент
# такого сторожа лежит именно в подкаталоге), чтобы `parents[1]` уехал.
assert _OWNER.exists(), f"область сканирования съехала: {_APP_DIR}"
offenders = [
str(path.relative_to(_BACKEND_ROOT))
for path in sorted(_APP_DIR.rglob("*.py"))