fix(scrapers): don't leak proxy creds in parse_proxy_url ValueError (#1945)
All checks were successful
CI / frontend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 6s
CI / openapi-codegen-check (pull_request) Successful in 1m52s
CI / backend-tests (pull_request) Successful in 14m11s

parse_proxy_url raised ValueError(f"...{proxy_url!r}") embedding the FULL proxy
URL incl. password. Это исключение всплывает в run_region_sweep try → пишется в
kn_scrape_runs.error (str(e)[:2000]) + log_progress + logger.exception→Sentry —
малформный proxy URL утёк бы пароль. Теперь сообщение содержит только scheme,
без сырого URL/creds. Happy-path лог уже server-only (host:port), creds не пишет.

test: ValueError-сообщение НЕ содержит пароль/юзера/сырой URL.
This commit is contained in:
Light1YT 2026-06-28 17:42:33 +05:00
parent aafcb208e9
commit 906f89db98
2 changed files with 14 additions and 1 deletions

View file

@ -57,7 +57,9 @@ def parse_proxy_url(proxy_url: str | None) -> dict[str, str] | None:
return None
parts = urlsplit(proxy_url)
if not parts.hostname:
raise ValueError(f"proxy URL без host: {proxy_url!r}")
# НЕ эхо-им сырой proxy_url — он содержит пароль, а это исключение
# всплывает в kn_scrape_runs.error / log_progress / Sentry (#1945 sec-review).
raise ValueError(f"proxy URL без host (scheme={parts.scheme!r})")
scheme = parts.scheme or "http"
server = f"{scheme}://{parts.hostname}"
if parts.port:

View file

@ -69,6 +69,17 @@ class TestParseProxyUrl:
with pytest.raises(ValueError):
parse_proxy_url("http://:8080")
def test_error_does_not_leak_credentials(self) -> None:
# ValueError всплывает в kn_scrape_runs.error / log_progress / Sentry —
# НЕ должен содержать пароль (#1945 sec-review).
bad = "http://secretuser:secretpass@:8080" # есть creds, но нет host
with pytest.raises(ValueError) as exc:
parse_proxy_url(bad)
msg = str(exc.value)
assert "secretpass" not in msg
assert "secretuser" not in msg
assert bad not in msg
class TestBrowserSessionThrottleThreading:
"""concurrency/jitter/proxy прокидываются в инстанс-поля BrowserSession."""