Spaces:
Sleeping
Sleeping
| 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 | |
| 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() | |