improve signed reads, crypto hardening, and scraper transport

This commit is contained in:
k
2026-06-14 21:43:43 +08:00
parent 54884f3e24
commit 78fb63be8e
27 changed files with 1326 additions and 202 deletions
+1 -1
View File
@@ -155,7 +155,7 @@ def test_adoption_error_codes_used_by_callers_are_all_defined():
# These are the codes referenced from app/api/positions.py +
# app/services/telegram_bot.py. Update both sites if you add one.
promised_codes = {
"no_subscription", "no_hl_key", "paper_mode",
"no_subscription", "no_hl_key", "paper_mode", "macro_disabled",
"key_decrypt_failed", "hl_read_failed",
"bad_mode", "circuit_breaker",
"already_adopted", "concurrency_cap",
+58
View File
@@ -0,0 +1,58 @@
"""enc:v2 envelope encryption (H4): roundtrip, legacy v1 compat, format checks."""
import base64
import hashlib
import pytest
from cryptography.fernet import Fernet
from app.services import crypto
@pytest.fixture(autouse=True)
def _kek(monkeypatch):
monkeypatch.setattr(crypto.settings, "encryption_key", "k" * 64)
# Reset module caches so each test derives from the patched KEK.
crypto._fernet_v1 = None
crypto._fernet_v2_cache.clear()
crypto._encrypt_salt = None
yield
crypto._fernet_v1 = None
crypto._fernet_v2_cache.clear()
crypto._encrypt_salt = None
def test_v2_roundtrip():
blob = crypto.encrypt_api_key("0x" + "ab" * 32)
assert blob.startswith(crypto.ENC_PREFIX_V2)
assert crypto.decrypt_api_key(blob) == "0x" + "ab" * 32
assert crypto.is_current_format(blob)
# Fits the hl_api_key String(256) column.
assert len(blob) <= 256
def test_v1_blob_still_decrypts():
# Build a v1 blob exactly the way the legacy code did.
digest = hashlib.sha256(("k" * 64).encode()).digest()
f = Fernet(base64.urlsafe_b64encode(digest))
blob = crypto.ENC_PREFIX_V1 + f.encrypt(b"secret-key").decode()
assert not crypto.is_current_format(blob)
assert crypto.decrypt_api_key(blob) == "secret-key"
def test_wrong_kek_raises(monkeypatch):
blob = crypto.encrypt_api_key("topsecret")
monkeypatch.setattr(crypto.settings, "encryption_key", "x" * 64)
crypto._fernet_v2_cache.clear()
with pytest.raises(RuntimeError):
crypto.decrypt_api_key(blob)
def test_malformed_v2_raises():
with pytest.raises(RuntimeError):
crypto.decrypt_api_key(crypto.ENC_PREFIX_V2 + "no-salt-separator")
def test_plaintext_refused_in_production(monkeypatch):
monkeypatch.setattr(crypto.settings, "environment", "production")
with pytest.raises(RuntimeError):
crypto.decrypt_api_key("raw-plaintext-key")
+38
View File
@@ -0,0 +1,38 @@
"""Unit tests for kol_analysis._derive_tier — the non-Twitter tier derivation
that lets blog/substack/podcast posts get the same trade_signal/directional/
noise tiers (and SIGNAL/VIEW badges + "Signals only" filter) as Twitter posts.
"""
from app.services.kol_analysis import _derive_tier
def _tk(action="mention", conviction=0.0):
return {"action": action, "conviction": conviction}
def test_no_tickers_is_noise():
assert _derive_tier([], 0.0) == "noise"
def test_only_mentions_is_noise():
assert _derive_tier([_tk("mention", 0.9)], 0.1) == "noise"
def test_high_conviction_directional_is_trade_signal():
assert _derive_tier([_tk("buy", 0.7)], 0.0) == "trade_signal"
def test_strong_divergence_is_trade_signal_even_without_ticker():
assert _derive_tier([], 0.8) == "trade_signal"
def test_low_conviction_directional_is_directional():
assert _derive_tier([_tk("bullish", 0.4)], 0.0) == "directional"
def test_moderate_divergence_is_directional():
assert _derive_tier([_tk("mention", 0.0)], 0.55) == "directional"
def test_boundary_conviction_0_6_is_trade_signal():
assert _derive_tier([_tk("sell", 0.6)], 0.0) == "trade_signal"
+2 -2
View File
@@ -97,10 +97,10 @@ async def test_open_positions_requires_signed_wallet_read(monkeypatch):
monkeypatch.setattr(positions, "verify_signed_request_any", fake_verify)
db = _Db([[]])
from app.services.signed_request import SignedReadCreds
result = await positions.get_open_positions(
wallet="0xABC",
ts=123,
sig="0xsig",
creds=SignedReadCreds(ts=123, sig="0xsig"),
db=db,
)