feat(tracker): unified auth boundary — gossip HMAC + validator token + admin-gated reads (alpha 01/02/20, ADR-0017)

Wire server.py handlers to the auth helper: forfeit requires validator
service token or admin session (client API keys rejected); billing summary/
settlements/registry-wallets and benchmark endpoints require admin/service;
the three gossip mutation endpoints require a fresh hive HMAC signature and
outgoing gossip pushes are signed. Dashboard sends its session token on
panel fetches. Existing tests updated for the new gates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dobromir Popov
2026-07-05 00:08:25 +02:00
parent 7414ce1e29
commit 81719ed84b
12 changed files with 4591 additions and 4557 deletions

View File

@@ -12,8 +12,11 @@ import pytest
from meshnet_gateway.server import GatewayServer, _banned_route_wallet
from meshnet_node.server import StubNodeServer
from meshnet_contracts import LocalSolanaContracts
from meshnet_tracker.auth import sign_hive_request
from meshnet_tracker.server import TrackerServer, _NodeEntry, _registration_ban_error
_TEST_HIVE_SECRET = "test-hive-secret"
def _post_json(url: str, payload: dict) -> dict:
data = json.dumps(payload).encode()
@@ -1558,7 +1561,7 @@ def test_stats_sqlite_persistence_survives_restart(tmp_path):
def test_stats_gossip_endpoint_merges_peer_slice():
tracker = TrackerServer()
tracker = TrackerServer(hive_secret=_TEST_HIVE_SECRET)
port = tracker.start()
try:
peer_payload = {
@@ -1571,7 +1574,14 @@ def test_stats_gossip_endpoint_merges_peer_slice():
}
},
}
_post_json(f"http://127.0.0.1:{port}/v1/stats/gossip", peer_payload)
body = json.dumps(peer_payload).encode()
req = urllib.request.Request(
f"http://127.0.0.1:{port}/v1/stats/gossip", data=body,
headers={"Content-Type": "application/json", **sign_hive_request(_TEST_HIVE_SECRET, body)},
method="POST",
)
with urllib.request.urlopen(req) as r:
r.read()
combined = _get_json(f"http://127.0.0.1:{port}/v1/stats")
assert "remote-model" in combined["models"]