From 3a7dbd4dda1b2fecbea3f99c4ff9dbe4d1ffeecf Mon Sep 17 00:00:00 2001 From: bot-backend Date: Thu, 6 Aug 2026 19:20:19 +0500 Subject: [PATCH] =?UTF-8?q?test(tradein/auth):=20=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=B6=20=D0=BD=D0=B5=20=D0=B4=D0=BE=D0=BB=D0=B6=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B7=D0=B5=D0=BB=D0=B5=D0=BD=D0=B5=D1=82=D1=8C=20?= =?UTF-8?q?=D0=BE=D1=82=20=D1=81=D1=8A=D0=B5=D1=85=D0=B0=D0=B2=D1=88=D0=B5?= =?UTF-8?q?=D0=B9=20=D0=BE=D0=B1=D0=BB=D0=B0=D1=81=D1=82=D0=B8=20(#2715)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ревью: `rglob` по несуществующему каталогу не падает — отдаёт пусто, нарушителей ноль, тест зелёный навсегда. Достаточно переложить файл в подкаталог tests/ (их восемь, и прецедент такого сторожа лежит именно в подкаталоге), чтобы `parents[1]` уехал и сторож замолчал. Ровно тот класс, от которого детектор уже защищён (test_detector_actually_detects), а область — нет. Одна строка: `_OWNER.exists()` в теле теста; проверено мутацией области — краснеет. Плюс слепые зоны названы и закреплены исполняемо: строковый доступ `getattr(mod, "verify_password")` и прямой `bcrypt.checkpw` в обход модуля сторож НЕ ловит. От намеренного обхода он не защищает и не может — только от нечаянного. Было требованием ревью назвать это в коде, а не подразумевать. Refs #2715 --- .../backend/tests/test_password_call_sites.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tradein-mvp/backend/tests/test_password_call_sites.py b/tradein-mvp/backend/tests/test_password_call_sites.py index 1cda0b34..48e37a9d 100644 --- a/tradein-mvp/backend/tests/test_password_call_sites.py +++ b/tradein-mvp/backend/tests/test_password_call_sites.py @@ -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"))