Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions bridge/dashboard_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import os
import json
import logging
import time
from flask import Blueprint, jsonify, request

Expand All @@ -33,6 +34,7 @@
# Cache configuration (in-memory for simplicity)
CACHE_TTL = 30 # seconds
_price_cache = {"data": None, "timestamp": 0}
logger = logging.getLogger(__name__)

# ─── Blueprint ────────────────────────────────────────────────────────────────
dashboard_bp = Blueprint("dashboard", __name__, url_prefix="/bridge/dashboard")
Expand Down Expand Up @@ -152,8 +154,9 @@ def get_bridge_health():
conn.execute("SELECT 1").fetchone()
health["rustchain"] = True
details["rustchain"] = "Database accessible"
except Exception as e:
details["rustchain"] = f"Database error: {str(e)}"
except Exception:
logger.exception("Dashboard health database check failed")
details["rustchain"] = "Database unavailable"

# Check Solana RPC (sync version)
try:
Expand All @@ -173,8 +176,9 @@ def get_bridge_health():
details["solana_rpc"] = "RPC responsive"
else:
details["solana_rpc"] = "RPC returned unexpected response"
except Exception as e:
details["solana_rpc"] = f"RPC error: {str(e)}"
except Exception:
logger.exception("Dashboard health Solana RPC check failed")
details["solana_rpc"] = "RPC unavailable"

# Bridge API is healthy if we got here
health["bridge_api"] = True
Expand All @@ -200,8 +204,9 @@ def get_bridge_health():
details["wrtc_mint"] = "Mint account exists"
else:
details["wrtc_mint"] = "Mint account not found"
except Exception as e:
details["wrtc_mint"] = f"Mint check error: {str(e)}"
except Exception:
logger.exception("Dashboard health wRTC mint check failed")
details["wrtc_mint"] = "Mint check unavailable"
else:
health["wrtc_mint"] = True # Skip if not configured
details["wrtc_mint"] = "Mint address not configured"
Expand Down
62 changes: 62 additions & 0 deletions bridge/test_dashboard_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
import time
import sys
import os
import urllib.request

# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from flask import Flask
from bridge.bridge_api import register_bridge_routes, init_bridge_db, get_db, _amount_to_base, STATE_COMPLETE
import bridge.dashboard_api as dashboard_api
from bridge.dashboard_api import register_dashboard_routes


Expand Down Expand Up @@ -186,6 +188,66 @@ def test_health_timestamp(self, client):
now = int(time.time())
assert abs(data['last_checked'] - now) < 5 # Within 5 seconds

def test_health_hides_database_exception_details(self, client, monkeypatch):
"""Health checks should not expose local DB paths or exception text."""
secret_error = "sqlite failure at C:/srv/rustchain/private/bridge.db"

class FailingDb:
def __enter__(self):
raise RuntimeError(secret_error)

def __exit__(self, *_args):
return False

def fail_rpc(*_args, **_kwargs):
raise RuntimeError("rpc unavailable")

monkeypatch.setattr(dashboard_api, "get_db", lambda: FailingDb())
monkeypatch.setattr(urllib.request, "urlopen", fail_rpc)

response = client.get('/bridge/dashboard/health')

assert response.status_code == 200
body = json.loads(response.data)
assert body["components"]["rustchain"] is False
assert body["details"]["rustchain"] == "Database unavailable"
assert secret_error not in response.get_data(as_text=True)

def test_health_hides_rpc_exception_details(self, client, monkeypatch):
"""Health checks should not expose RPC URLs or network exception text."""
secret_error = "GET https://internal-solana.local/rpc?token=secret failed"

def fail_rpc(*_args, **_kwargs):
raise RuntimeError(secret_error)

monkeypatch.setattr(urllib.request, "urlopen", fail_rpc)

response = client.get('/bridge/dashboard/health')

assert response.status_code == 200
body = json.loads(response.data)
assert body["components"]["solana_rpc"] is False
assert body["details"]["solana_rpc"] == "RPC unavailable"
assert secret_error not in response.get_data(as_text=True)

def test_health_hides_mint_exception_details(self, client, monkeypatch):
"""Health checks should not expose configured mint lookup errors."""
secret_error = "mint lookup failed for account 7xPrivateInternalMint"

def fail_rpc(*_args, **_kwargs):
raise RuntimeError(secret_error)

monkeypatch.setattr(dashboard_api, "WRTC_MINT_ADDRESS", "7xPrivateInternalMint")
monkeypatch.setattr(urllib.request, "urlopen", fail_rpc)

response = client.get('/bridge/dashboard/health')

assert response.status_code == 200
body = json.loads(response.data)
assert body["components"]["wrtc_mint"] is False
assert body["details"]["wrtc_mint"] == "Mint check unavailable"
assert secret_error not in response.get_data(as_text=True)


class TestDashboardTransactions:
"""Test /bridge/dashboard/transactions endpoint."""
Expand Down
Loading