From 9d37ee46873757754c57d2e098bf5f86bf08915f Mon Sep 17 00:00:00 2001 From: jxxghp Date: Mon, 28 Sep 2026 16:53:28 +0800 Subject: [PATCH] fix(nettest): authenticate network proxy GitHub probe --- app/application/nettest/catalogue.py | 3 ++- tests/test_nettest_probe_contract.py | 37 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/app/application/nettest/catalogue.py b/app/application/nettest/catalogue.py index 4d9a8f1e7..f87b0102c 100644 --- a/app/application/nettest/catalogue.py +++ b/app/application/nettest/catalogue.py @@ -513,7 +513,7 @@ def _build_network_proxy_rules( def _build_network_proxy_rule(settings: SettingsReader) -> Optional[NetworkTestRule]: - """用 GitHub API 请求验证当前配置的通用出站代理。""" + """沿用 GitHub 身份请求 API,验证当前配置的通用出站代理。""" proxy_config = settings("PROXY", None) proxy_address = settings("PROXY_HOST", None) if not proxy_address and isinstance(proxy_config, Mapping): @@ -530,6 +530,7 @@ def _build_network_proxy_rule(settings: SettingsReader) -> Optional[NetworkTestR url="https://api.github.com", proxy=True, allowed_redirect_prefixes=("https://api.github.com/",), + headers=_freeze_headers(settings("GITHUB_HEADERS", None)), display_address=(proxy_url if "://" in proxy_url else f"http://{proxy_url}"), ) diff --git a/tests/test_nettest_probe_contract.py b/tests/test_nettest_probe_contract.py index ef9bf08cf..533d8b4eb 100644 --- a/tests/test_nettest_probe_contract.py +++ b/tests/test_nettest_probe_contract.py @@ -4,6 +4,8 @@ import asyncio from types import SimpleNamespace from unittest.mock import AsyncMock, Mock +import pytest + from app.application.network import NetworkTestService @@ -82,3 +84,38 @@ def test_theaudiodb_probe_uses_configured_key_and_module_health_endpoint() -> No "https://www.theaudiodb.com/api/v1/json/" "custom-audio-key/search.php?s=coldplay" ) + + +@pytest.mark.parametrize("github_headers", [None, {"Authorization": "Bearer github-token"}]) +def test_network_proxy_probe_uses_configured_github_identity(github_headers) -> None: + """通用代理探针应沿用 GitHub API 身份,且公开目录不泄漏认证头。""" + captured = {} + + async def respond(method, url, **options): + """按请求是否携带预期身份模拟 GitHub API 响应。""" + captured.update(method=method, url=url, **options) + return SimpleNamespace( + status_code=200 if options["headers"] == github_headers else 403, + headers={}, + text="{}", + aclose=AsyncMock(), + ) + + transport = SimpleNamespace(request=AsyncMock(side_effect=respond)) + service = _network_test_service( + transport, + PROXY={"https": "http://proxy.example:7890"}, + PROXY_HOST="http://proxy.example:7890", + GITHUB_HEADERS=github_headers, + ) + + public_target = next(target for target in service.list_targets() if target.id == "network_proxy") + result = asyncio.run(service.execute(target_id="network_proxy")) + + assert result.success + assert captured["method"] == "GET" + assert captured["url"] == "https://api.github.com" + assert captured["proxy"] == {"https": "http://proxy.example:7890"} + assert captured["headers"] == github_headers + assert public_target.address == "http://proxy.example:7890" + assert "github-token" not in public_target.address