From 55a67e5c45a0a78fc9a68d12631ac1f50bec3d4c Mon Sep 17 00:00:00 2001 From: bot-backend Date: Sat, 5 Sep 2026 23:03:16 +0500 Subject: [PATCH] =?UTF-8?q?fix(tradein):=20=D0=BC=D0=B0=D1=81=D0=BA=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D1=81=D0=B5=D0=BA=D1=80?= =?UTF-8?q?=D0=B5=D1=82=20=D0=B8=20=D0=B2=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D1=80=D0=B0=D1=85=20=D1=81=20=D0=BF=D1=80=D0=B5?= =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=D0=BE=D0=BC=20(#3154)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ревью-minor: якорь [?&] вплотную к имени пропускал client_secret=, refresh_token=, auth_token=, webhook_secret=. Разрешаем префикс [\w.-]* перед альтернацией — маскируем имена, ОКАНЧИВАЮЩИЕСЯ на чувствительное слово. Кейс not_a_secret_name заменён на честные отрицательные: ?secretary= и ?tokens_page= (не оканчиваются на secret/token) плюс /api/v1/token-info в пути. Co-Authored-By: Claude Fable 5.1 --- tradein-mvp/backend/app/core/log_scrub.py | 8 +++++--- .../backend/tests/test_3154_query_secret_scrub.py | 11 ++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tradein-mvp/backend/app/core/log_scrub.py b/tradein-mvp/backend/app/core/log_scrub.py index af44c3d6..9336cec9 100644 --- a/tradein-mvp/backend/app/core/log_scrub.py +++ b/tradein-mvp/backend/app/core/log_scrub.py @@ -20,10 +20,12 @@ from __future__ import annotations import logging import re -# Имена параметров, значение которых маскируем. Значение — до следующего `&`, -# пробела или кавычки (access-строка uvicorn обрамляет запрос кавычками). +# Имена параметров, значение которых маскируем: имя ОКАНЧИВАЕТСЯ на чувствительное +# слово, поэтому перед альтернацией допускаем префикс (`client_secret`, +# `refresh_token`, `webhook_secret`). Значение — до следующего `&`, пробела или +# кавычки (access-строка uvicorn обрамляет запрос кавычками). _SENSITIVE_QUERY = re.compile( - r"([?&](?:secret|token|api[-_]?key|apikey|access[-_]?token|password|signature|sig)=)" + r"([?&][\w.-]*(?:secret|token|api[-_]?key|apikey|access[-_]?token|password|signature|sig)=)" r"[^&\s\"'<>]+", re.IGNORECASE, ) diff --git a/tradein-mvp/backend/tests/test_3154_query_secret_scrub.py b/tradein-mvp/backend/tests/test_3154_query_secret_scrub.py index 512c9905..e5c7c10e 100644 --- a/tradein-mvp/backend/tests/test_3154_query_secret_scrub.py +++ b/tradein-mvp/backend/tests/test_3154_query_secret_scrub.py @@ -91,6 +91,11 @@ def test_app_logger_via_root_handler_masks_secret() -> None: f"/hook?api_key={_SECRET}", f"/hook?apiKey={_SECRET}", f'"GET /hook?access_token={_SECRET} HTTP/1.1"', + # Имя с префиксом: чувствительное слово в КОНЦЕ имени параметра. + f"/hook?client_secret={_SECRET}", + f"/hook?webhook_secret={_SECRET}", + f"/hook?refresh_token={_SECRET}", + f"/hook?auth_token={_SECRET}", ], ) def test_sensitive_param_names_are_masked(raw: str) -> None: @@ -104,7 +109,11 @@ def test_sensitive_param_names_are_masked(raw: str) -> None: [ "GET /api/v1/trade-in/offers?limit=50&city=Екатеринбург", "https://metrics.gendsgn.ru/ingest/loki/api/v1/push", - "/hook?not_a_secret_name=value", + # Имя НЕ оканчивается на чувствительное слово — маскировать нечего. + "/hook?secretary=anna", + "/hook?tokens_page=2", + # `token-info` в ПУТИ, а не в query: значения там нет вовсе. + "GET /api/v1/token-info?limit=5", ], ) def test_innocent_lines_untouched(raw: str) -> None: