From 82a4f6231aef96685276cd8d5fbf58a80d6d5d26 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Sat, 3 Oct 2026 02:04:14 +0800 Subject: [PATCH] fix: identify isolated account facts HTTP client explicitly Co-Authored-By: Codex --- ...diagnose_binance_account_facts_receiver.py | 7 +++++- scripts/publish_binance_account_facts.py | 2 ++ tests/test_binance_account_facts.py | 25 +++++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/scripts/diagnose_binance_account_facts_receiver.py b/scripts/diagnose_binance_account_facts_receiver.py index 7401fbc4..f9424d2b 100644 --- a/scripts/diagnose_binance_account_facts_receiver.py +++ b/scripts/diagnose_binance_account_facts_receiver.py @@ -9,6 +9,7 @@ from urllib.request import HTTPRedirectHandler, Request, build_opener QRS_ENDPOINT = "https://qsl-strategy-switch-console.pigbibi.workers.dev/api/internal/binance-account-facts" +_USER_AGENT = "QSL-AccountFacts-Readiness/1.0" _READINESS_FIELDS = {"ok", "ready", "binding_valid", "account_options_readable", "unique_match"} _READINESS_ERROR_FIELDS = _READINESS_FIELDS | {"error"} @@ -131,7 +132,11 @@ def diagnose_receiver(*, token: str, opener_factory=build_opener) -> ReceiverDia return ReceiverDiagnosis("token_missing") request = Request( QRS_ENDPOINT, - headers={"Authorization": f"Bearer {token}", "Accept": "application/json"}, + headers={ + "Authorization": f"Bearer {token}", + "Accept": "application/json", + "User-Agent": _USER_AGENT, + }, method="GET", ) try: diff --git a/scripts/publish_binance_account_facts.py b/scripts/publish_binance_account_facts.py index 4e26af43..e07e08bb 100644 --- a/scripts/publish_binance_account_facts.py +++ b/scripts/publish_binance_account_facts.py @@ -17,6 +17,7 @@ QRS_ENDPOINT = "https://qsl-strategy-switch-console.pigbibi.workers.dev/api/internal/binance-account-facts" +_USER_AGENT = "QSL-AccountFacts-Readiness/1.0" _HTTP_ERROR_LABELS = { (400, "invalid_binance_account_facts"): "http_400_report_invalid", (400, "invalid_binance_account_facts_time"): "http_400_report_time_invalid", @@ -95,6 +96,7 @@ def publish_account_facts(*, facts_path: Path, env) -> str: "Authorization": f"Bearer {token}", "Content-Type": "application/json", "Accept": "application/json", + "User-Agent": _USER_AGENT, }, method="POST", ) diff --git a/tests/test_binance_account_facts.py b/tests/test_binance_account_facts.py index 7acbc0af..2a81b5cf 100644 --- a/tests/test_binance_account_facts.py +++ b/tests/test_binance_account_facts.py @@ -1048,14 +1048,24 @@ def __exit__(self, *_args): def read(self, _limit): return json.dumps({"status": ack_status}).encode() + calls = [] + class Opener: def open(self, request, timeout): + calls.append((request, timeout)) assert request.method == "POST" assert request.full_url == publisher.QRS_ENDPOINT + assert request.get_header("User-agent") == "QSL-AccountFacts-Readiness/1.0" assert timeout == 20 return Response() - monkeypatch.setattr(publisher, "build_opener", lambda _handler: Opener()) + handlers = [] + + def build_opener(*received_handlers): + handlers.extend(received_handlers) + return Opener() + + monkeypatch.setattr(publisher, "build_opener", build_opener) assert publisher.publish_account_facts( facts_path=facts_path, env={ @@ -1063,6 +1073,8 @@ def open(self, request, timeout): "BINANCE_ACCOUNT_FACTS_SYNC_TOKEN": "synthetic-token", }, ) == ack_status + assert len(calls) == 1 + assert handlers == [publisher._NoRedirect] def test_publisher_rejects_legacy_recorded_ack(tmp_path, monkeypatch): @@ -1310,14 +1322,23 @@ def open(self, request, timeout): assert timeout == 15 return Response() - result = diagnosis.diagnose_receiver(token="synthetic-secret", opener_factory=lambda _handler: Opener()) + handlers = [] + + def opener_factory(*received_handlers): + handlers.extend(received_handlers) + return Opener() + + result = diagnosis.diagnose_receiver(token="synthetic-secret", opener_factory=opener_factory) assert result.category == "ready" assert result.http_status == 200 assert result.body_shape == "readiness" assert len(calls) == 1 + assert calls[0].full_url == diagnosis.QRS_ENDPOINT assert calls[0].method == "GET" assert calls[0].data is None assert calls[0].get_header("Authorization") == "Bearer synthetic-secret" + assert calls[0].get_header("User-agent") == "QSL-AccountFacts-Readiness/1.0" + assert handlers == [diagnosis._NoRedirect] assert "synthetic-secret" not in repr(result)