fix(HEL-412): 刷新降级不再整次失败,并补齐准备中提示
手动刷新与自动补跑共用可用数据判定:日线推算或上一交易日快照记为部分/准备中成功,避免前端误报刷新失败。HTTP JSON 解析错误不再把请求正文写入日志。 Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
co-authored by
Cursor
multica-agent
parent
0d13066386
commit
5085cacf0d
@@ -1,17 +1,21 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import tempfile
|
||||
import threading
|
||||
import unittest
|
||||
from http.server import ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
from urllib.error import HTTPError
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
from datahub.adapters.tushare import TushareAdapter
|
||||
from datahub.crypto import SecretVault
|
||||
from datahub.httpapp import make_handler
|
||||
from datahub.hub import Hub
|
||||
from datahub.logutil import JsonFormatter
|
||||
from datahub.settings import Settings
|
||||
from tests.fixtures import fake_transport
|
||||
|
||||
@@ -91,6 +95,53 @@ class AdminTests(unittest.TestCase):
|
||||
)
|
||||
self.assertEqual(ctx.exception.code, 401)
|
||||
|
||||
def test_invalid_json_does_not_log_request_body_secrets(self) -> None:
|
||||
secret = "SuperSecretPass1!"
|
||||
token = "hub-token-should-not-leak"
|
||||
raw = json.dumps({"password": secret, "token": token, "username": "hub_admin"}) + "{not-json"
|
||||
stream = io.StringIO()
|
||||
logger = logging.getLogger("datahub")
|
||||
handler = logging.StreamHandler(stream)
|
||||
handler.setFormatter(JsonFormatter())
|
||||
logger.addHandler(handler)
|
||||
previous_level = logger.level
|
||||
logger.setLevel(logging.DEBUG)
|
||||
try:
|
||||
req = Request(
|
||||
self.base + "/admin/api/login",
|
||||
data=raw.encode("utf-8"),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
with self.assertRaises(HTTPError) as ctx:
|
||||
urlopen(req, timeout=5)
|
||||
body = ctx.exception.read().decode("utf-8")
|
||||
self.assertEqual(ctx.exception.code, 400)
|
||||
self.assertNotIn(secret, body)
|
||||
self.assertNotIn(token, body)
|
||||
blob = stream.getvalue() + body
|
||||
self.assertNotIn(secret, blob)
|
||||
self.assertNotIn(token, blob)
|
||||
self.assertNotIn(raw, blob)
|
||||
finally:
|
||||
logger.removeHandler(handler)
|
||||
logger.setLevel(previous_level)
|
||||
|
||||
def test_json_formatter_drops_decode_error_document(self) -> None:
|
||||
secret = "ParseSecretTokenXYZ"
|
||||
formatter = JsonFormatter()
|
||||
logger = logging.getLogger("datahub.test")
|
||||
record = logger.makeRecord(
|
||||
"datahub.test", logging.ERROR, __file__, 1, "parse failed", (), None
|
||||
)
|
||||
try:
|
||||
json.loads('{"password": "%s"}{' % secret)
|
||||
except json.JSONDecodeError as exc:
|
||||
record.exc_info = (type(exc), exc, exc.__traceback__)
|
||||
blob = formatter.format(record)
|
||||
self.assertNotIn(secret, blob)
|
||||
self.assertIn("invalid json", blob)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user