SimpleChatbot / hermes_overlay /tests /test_phase4_execution_audit.py
Amin
Deploy: HermesFace finalized project to HF Space
2e658e7
Raw
History Blame Contribute Delete
7.26 kB
from __future__ import annotations
import asyncio
import json
import pytest
import trading.domain.execution_service as execution_module
from trading.domain.approvals import create_approval
from trading.domain.execution_contracts import ExecuteApprovedPlanCommand
from trading.domain.execution_history import (
begin_execution,
finish_execution,
reconstruct_execution,
record_execution_event,
transition_execution,
)
from trading.domain.execution_service import ExecutionService
from trading.domain.execution_state import FAILED_SAFE
from trading.domain.identity_repo import ensure_paper_exchange_account
from trading.domain.plan_revalidation import PlanRevalidationResult
from trading.domain.plans_repo import create_plan
from trading.domain.risk_limits import MarketRiskContext
from trading.domain.schema import apply_migrations, connect
@pytest.fixture(autouse=True)
def _db(tmp_path, monkeypatch):
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
monkeypatch.setenv("TRADING_MODE", "paper")
monkeypatch.setenv("HERMES_EXECUTION_ENABLED", "true")
ok, messages = apply_migrations()
assert ok, messages
def _plan() -> dict:
return {
"symbol": "BTCUSDT",
"decision": "LONG",
"entry": 100.0,
"stop_loss": 95.0,
"take_profit": 110.0,
"leverage": 3,
"quantity": 1.0,
"risk_profile": "moderate",
"risk_percent": 0.01,
"futuresVerified": True,
"noTradeGuard": False,
"trading_readiness": "ready",
"executable": True,
"expires_at": "2099-01-01T00:00:00Z",
"field_sources": {"ticker": "datasource4", "orderbook": "datasource4"},
"field_metadata": {
"ticker": {"freshness": "fresh", "validity": "valid"},
"orderbook": {"freshness": "fresh", "validity": "valid"},
},
}
def _accepted(plan_id: str) -> PlanRevalidationResult:
return PlanRevalidationResult(
revalidation_id=f"rv-{plan_id}",
accepted=True,
reasons=(),
context_hash="revalidation-context-hash",
observed_price=100.0,
observed_spread_bps=1.25,
observed_slippage_percent=0.0002,
market_risk=MarketRiskContext(
provider_fresh=True,
reconciliation_clear=True,
spread_bps=1.25,
funding_rate=0.0001,
liquidity_ok=True,
),
orderbook={"bids": [[99.9, 100]], "asks": [[100.0, 100]]},
)
def test_approved_entry_audit_bundle_reconstructs_identifiers_decisions_and_exchange_io(monkeypatch):
owner_id = "audit-owner"
session_id = "audit-session"
account = ensure_paper_exchange_account(owner_id)
plan = create_plan(
_plan(), owner_id=owner_id, session_id=session_id, account_id=account.account_id
)
approval_id = create_approval(
plan["plan_id"], plan["plan_hash"], owner_id,
session_id=session_id, account_id=account.account_id,
)
async def accepted(plan_id, **_kwargs):
return _accepted(plan_id)
monkeypatch.setattr(execution_module, "revalidate_plan", accepted)
result = asyncio.run(ExecutionService().execute_approved_plan(
ExecuteApprovedPlanCommand(
plan_id=plan["plan_id"],
approval_id=approval_id,
owner_id=owner_id,
session_id=session_id,
account_id=account.account_id,
idempotency_key="audit-entry-once",
correlation_id="incident-correlation-1",
)
))
bundle = reconstruct_execution(result["execution_id"])
execution = bundle["execution"]
assert execution["execution_id"] == result["execution_id"]
assert execution["owner_id"] == owner_id
assert execution["session_id"] == session_id
assert execution["account_id"] == account.account_id
assert execution["plan_id"] == plan["plan_id"]
assert execution["approval_id"] == approval_id
assert execution["correlation_id"] == "incident-correlation-1"
assert execution["payload"]["plan_hash"] == plan["plan_hash"]
assert execution["payload"]["provider_snapshot_hash"] == plan["provider_snapshot_hash"]
assert execution["payload"]["revalidation_id"] == f"rv-{plan['plan_id']}"
assert execution["payload"]["revalidation_context_hash"] == "revalidation-context-hash"
assert execution["payload"]["risk_decision"] == "accepted"
assert execution["payload"]["risk_context"]["provider_fresh"] is True
reasons = [event["reason"] for event in bundle["events"]]
assert "exchange_request_prepared" in reasons
assert "exchange_result_received" in reasons
assert "protection_confirmed" in reasons
assert bundle["orders"]
order = bundle["orders"][0]
assert order["order_id"] == result["order_id"]
assert order["events"]
assert order["fills"]
assert {item["kind"] for item in order["protective_orders"]} == {"stop_loss", "take_profit"}
def test_execution_audit_redacts_payloads_events_and_error_text():
secret_values = {
"api_key": "API-VERY-SECRET",
"password": "PASSWORD-VERY-SECRET",
"bearer": "TOKEN-VERY-SECRET",
"auth": "AUTH-VERY-SECRET",
}
execution_id = begin_execution(
owner_id="redaction-owner",
session_id="redaction-session",
account_id=None,
symbol="BTC/USDT:USDT",
action="entry",
mode="paper",
correlation_id="redaction-correlation",
payload={
"api_key": secret_values["api_key"],
"nested": {"password": secret_values["password"]},
"header": f"Bearer {secret_values['bearer']}",
},
actor="redaction-owner",
)
record_execution_event(
execution_id,
actor="redaction-owner",
reason="redaction_probe",
payload={"authorization": f"Bearer {secret_values['auth']}"},
)
transition_execution(
execution_id,
FAILED_SAFE,
actor="redaction-owner",
reason="safe_failure",
payload={"secret": "TRANSITION-VERY-SECRET"},
)
finish_execution(
execution_id,
state=FAILED_SAFE,
error=RuntimeError(
"api_key=ERROR-VERY-SECRET password=ERROR-PASSWORD-VERY-SECRET"
),
payload={"refresh_token": "RESULT-VERY-SECRET"},
)
bundle = reconstruct_execution(execution_id)
serialized = json.dumps(bundle, sort_keys=True)
for value in (
*secret_values.values(),
"TRANSITION-VERY-SECRET",
"ERROR-VERY-SECRET",
"ERROR-PASSWORD-VERY-SECRET",
"RESULT-VERY-SECRET",
):
assert value not in serialized
assert "[REDACTED]" in serialized
assert bundle["execution"]["owner_id"] == "redaction-owner"
assert bundle["execution"]["session_id"] == "redaction-session"
assert bundle["execution"]["correlation_id"] == "redaction-correlation"
conn = connect()
try:
row = conn.execute(
"SELECT error_message FROM execution_history WHERE execution_id=?", (execution_id,)
).fetchone()
assert row is not None
assert "ERROR-VERY-SECRET" not in str(row[0])
assert "[REDACTED]" in str(row[0])
finally:
conn.close()