fix(HEL-494): enforce datahub as sole website market boundary
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
+72
-17
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import ast
|
||||
import json
|
||||
import re
|
||||
import threading
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
@@ -15,6 +16,7 @@ from backend.data.datahub.realtime_proxy import HubRealtimeProxy
|
||||
from backend.data.datahub.settings import DATASETS, DatahubSettings, DatasetFlags
|
||||
from backend.data.providers.tushare_transport import TushareError
|
||||
from backend.features.market.charts import MarketChartClient
|
||||
from backend.features.system.service import SystemServiceMixin
|
||||
from tests.test_datahub_bridge import FakeClient, FakeLegacy, flags
|
||||
|
||||
|
||||
@@ -220,6 +222,63 @@ def blocked_urlopen(request, timeout=None):
|
||||
|
||||
|
||||
class HubExclusiveWebsiteTests(unittest.TestCase):
|
||||
def test_website_availability_depends_on_hub_not_provider_credentials(self) -> None:
|
||||
service = SystemServiceMixin()
|
||||
service._system_credentials = {}
|
||||
service.data_gateway = build_data_gateway({}, datahub_settings=_enabled_settings())
|
||||
self.assertTrue(service.configured)
|
||||
self.assertEqual(service.token, "datahub")
|
||||
|
||||
def test_website_vault_scrubs_historical_provider_credentials(self) -> None:
|
||||
class Vault:
|
||||
@staticmethod
|
||||
def decrypt_json(payload):
|
||||
if isinstance(payload, str):
|
||||
return json.loads(payload)
|
||||
return dict(payload)
|
||||
|
||||
@staticmethod
|
||||
def encrypt_json(payload):
|
||||
return dict(payload)
|
||||
|
||||
class Database:
|
||||
system = {
|
||||
"tushare_token": "old-tushare",
|
||||
"ifind_refresh_token": "old-refresh",
|
||||
"ifind_access_token": "old-access",
|
||||
}
|
||||
personal = {"tushare_token": "old-personal", "llm_primary_model": "model"}
|
||||
|
||||
def get_system_setting(self, _name):
|
||||
return dict(self.system)
|
||||
|
||||
@staticmethod
|
||||
def first_user_id():
|
||||
return 1
|
||||
|
||||
def get_user_credentials(self, _user_id):
|
||||
return dict(self.personal)
|
||||
|
||||
@staticmethod
|
||||
def list_user_credentials():
|
||||
return [{"user_id": 1, "encrypted_payload": '{"tushare_token":"old-personal"}'}]
|
||||
|
||||
def save_system_setting(self, _name, payload):
|
||||
self.system = dict(payload)
|
||||
|
||||
def save_user_credentials(self, _user_id, payload):
|
||||
self.personal = dict(payload)
|
||||
|
||||
service = SystemServiceMixin()
|
||||
service.database = Database()
|
||||
service.vault = Vault()
|
||||
service.system_lock = threading.Lock()
|
||||
loaded = service._load_system_credentials({})
|
||||
for key in ("tushare_token", "ifind_refresh_token", "ifind_access_token"):
|
||||
self.assertNotIn(key, loaded)
|
||||
self.assertNotIn(key, service.database.system)
|
||||
self.assertNotIn(key, service.database.personal)
|
||||
|
||||
def test_query_never_calls_website_tushare_transport(self) -> None:
|
||||
client = FakeClient()
|
||||
legacy = FakeLegacy(TushareError("website tushare must stay dark"))
|
||||
@@ -340,7 +399,6 @@ class HubExclusiveWebsiteTests(unittest.TestCase):
|
||||
market = gateway.tushare()
|
||||
market_quotes = market.try_quotes(["600000.SH"])
|
||||
auction = market.query("stk_auction", {"trade_date": "20240902"}, "")
|
||||
gateway.ifind.set_credentials("refresh-token", "access-token")
|
||||
self.assertEqual(rows[0]["涨停原因"], "重组")
|
||||
self.assertEqual(len(quotes), 3)
|
||||
self.assertEqual(chart[-1]["close"], 10.2)
|
||||
@@ -349,23 +407,20 @@ class HubExclusiveWebsiteTests(unittest.TestCase):
|
||||
self.assertIsNone(market.realtime_aggregator)
|
||||
self.assertEqual(market.token, "datahub")
|
||||
|
||||
def test_set_credentials_posts_to_hub_not_ifind(self) -> None:
|
||||
seen: list[str] = []
|
||||
def test_website_does_not_accept_or_forward_provider_credentials(self) -> None:
|
||||
proxy = HubIfindProxy(DatahubBridge(_enabled_settings(), FakeClient()))
|
||||
self.assertFalse(hasattr(proxy, "set_credentials"))
|
||||
client_source = (ROOT / "backend" / "data" / "datahub" / "client.py").read_text(encoding="utf-8")
|
||||
application_source = (ROOT / "backend" / "application.py").read_text(encoding="utf-8")
|
||||
self.assertNotIn("/v1/credentials", client_source)
|
||||
self.assertNotIn("ifind_refresh_token", application_source)
|
||||
|
||||
def urlopen(request, timeout=None):
|
||||
url = str(getattr(request, "full_url", None) or request)
|
||||
seen.append(url)
|
||||
if any(host in url for host in BLOCKED_HOSTS):
|
||||
raise AssertionError(f"website opened blocked host: {url}")
|
||||
return _Resp(hub_payload(request))
|
||||
|
||||
settings = _enabled_settings()
|
||||
hub_client = DatahubClient(settings, urlopen=urlopen)
|
||||
proxy = HubIfindProxy(DatahubBridge(settings, hub_client))
|
||||
proxy.set_credentials("refresh-token", "access-token")
|
||||
self.assertTrue(any("/v1/credentials/ifind" in url for url in seen))
|
||||
self.assertFalse(any("51ifind.com" in url for url in seen))
|
||||
self.assertFalse(any("quantapi" in url for url in seen))
|
||||
def test_site_configuration_depends_on_hub_not_provider_credentials(self) -> None:
|
||||
service = SystemServiceMixin()
|
||||
service._system_credentials = {}
|
||||
service.data_gateway = build_data_gateway({}, datahub_settings=_enabled_settings())
|
||||
self.assertTrue(service.configured)
|
||||
self.assertEqual(service.token, "datahub")
|
||||
|
||||
def test_compose_passes_ifind_env_to_hub(self) -> None:
|
||||
overlay = (ROOT / "compose.datahub.yaml").read_text(encoding="utf-8")
|
||||
|
||||
Reference in New Issue
Block a user