"""Full HTTP/FastAPI plus PostgreSQL contract for the unchanged legacy Agent.""" import os import unittest from uuid import UUID from fastapi.testclient import TestClient from app.agent_auth.service import hash_agent_secret from app.config import settings from app.main import app SITE_A = UUID("00000000-0000-4000-8000-000000001a01") SITE_B = UUID("00000000-0000-4000-8000-000000001a02") ZONE_C = UUID("00000000-0000-4000-8000-000000001a03") MINER_A = UUID("00000000-0000-4000-8000-000000001a11") MINER_B = UUID("00000000-0000-4000-8000-000000001a12") LEGACY_AGENT = "legacy-plexus-http" ENROLLED_AGENT = "enrolled-http-agent" REVOKED_AGENT = "revoked-http-agent" ENROLLED_SECRET = "enrolled-http-agent-secret" REVOKED_SECRET = "revoked-http-agent-secret" ZONE_A_NETWORK = "10.31.0.0/24" ZONE_B_NETWORK = "10.81.0.0/24" ZONE_C_NETWORK = "10.82.0.0/24" def connect(): from app.agent_auth.repository import default_connection_factory return default_connection_factory() class LegacyAgentHttpPostgresTests(unittest.TestCase): @classmethod def setUpClass(cls): if os.environ.get("MINEROPS_LEGACY_HTTP_POSTGRES_DISPOSABLE") != "1": raise unittest.SkipTest( "full-stack legacy contract requires its disposable runner" ) if settings.minerops_agent_id != LEGACY_AGENT: raise AssertionError("runner did not bind the configured legacy identity") connection = connect() try: with connection.cursor() as cur: cur.execute( """ SELECT agent_zone_id FROM minerops_site_agents WHERE agent_id = %s """, (LEGACY_AGENT,), ) cls.zone_a = cur.fetchone()[0] cur.execute( """ SELECT id FROM agent_zones WHERE site_id = %s AND name = 'Default Zone' """, (SITE_B,), ) cls.zone_b = cur.fetchone()[0] cur.execute( """ INSERT INTO agent_zone_network_ranges (agent_zone_id, network) VALUES (%s, %s::cidr), (%s, %s::cidr) """, (cls.zone_a, ZONE_A_NETWORK, cls.zone_b, ZONE_B_NETWORK), ) cur.execute( """ INSERT INTO agent_zones (id, site_id, name) VALUES (%s, %s, 'Revoked Contract Zone') """, (ZONE_C, SITE_B), ) cur.execute( """ INSERT INTO agent_zone_network_ranges (agent_zone_id, network) VALUES (%s, %s::cidr) """, (ZONE_C, ZONE_C_NETWORK), ) cur.execute( """ INSERT INTO minerops_site_agents ( agent_id, site_id, agent_zone_id, site_name, display_name, agent_secret_hash, credential_created_at, credential_revoked_at, legacy_auth_disabled_at ) VALUES (%s, %s, %s, 'Contract Site B', 'Enrolled Agent', %s, now(), NULL, now()), (%s, %s, %s, 'Contract Site B', 'Revoked Agent', %s, now() - interval '1 hour', now(), now() - interval '1 hour') """, ( ENROLLED_AGENT, SITE_B, cls.zone_b, hash_agent_secret(ENROLLED_SECRET), REVOKED_AGENT, SITE_B, ZONE_C, hash_agent_secret(REVOKED_SECRET), ), ) connection.commit() finally: connection.close() # Deliberately do not enter TestClient as a context manager. That keeps # unrelated application startup jobs out of this focused HTTP contract # while exercising the real ASGI middleware, dependencies, and routes. cls.client = TestClient(app) @classmethod def tearDownClass(cls): cls.client.close() @staticmethod def legacy_headers(): return {"X-MinerOps-Agent-Secret": settings.minerops_agent_shared_secret} @staticmethod def agent_headers(agent_id, secret): return { "X-MinerOps-Agent-ID": agent_id, "X-MinerOps-Agent-Secret": secret, } def assert_no_credentials(self, response): lowered = response.text.lower() for forbidden in ( "agent_secret_hash", "credential_created_at", "token_hash", settings.minerops_agent_shared_secret.lower(), ENROLLED_SECRET.lower(), REVOKED_SECRET.lower(), ): self.assertNotIn(forbidden, lowered) def test_10_secret_only_config_is_legacy_identity_and_zone_bound(self): response = self.client.get( "/api/agent/config?agent_id=" + ENROLLED_AGENT + "&agent_zone_id=" + str(self.zone_b), headers=self.legacy_headers(), ) self.assertEqual(response.status_code, 200, response.text) payload = response.json() self.assertEqual(payload["agent_id"], LEGACY_AGENT) self.assertEqual(payload["agent_zone_id"], str(self.zone_a)) self.assertEqual( [item["cidr"] for item in payload["ip_ranges"]], [ZONE_A_NETWORK], ) self.assertNotIn(ZONE_B_NETWORK, response.text) self.assertNotIn(ZONE_C_NETWORK, response.text) self.assert_no_credentials(response) def test_20_known_miners_returns_only_migrated_legacy_zone(self): response = self.client.get( "/api/agent/known-miners", headers=self.legacy_headers() ) self.assertEqual(response.status_code, 200, response.text) self.assertEqual( [item["miner_id"] for item in response.json()["miners"]], [str(MINER_A)], ) self.assertNotIn(str(MINER_B), response.text) self.assert_no_credentials(response) def test_30_exact_old_checkin_shape_succeeds_and_spoofing_fails(self): old_body = { "agent_id": LEGACY_AGENT, "site_name": "Plexus", "hostname": "legacy-contract-host", "version": "0.4-command-queue", "ip_address": "", "local_time": "2026-08-31T00:00:00Z", } response = self.client.post( "/api/agent/checkin", headers=self.legacy_headers(), json=old_body ) self.assertEqual(response.status_code, 200, response.text) self.assertEqual(response.json()["agent_id"], LEGACY_AGENT) self.assertEqual(response.json()["agent_zone_id"], str(self.zone_a)) self.assert_no_credentials(response) spoofed = self.client.post( "/api/agent/checkin?agent_id=" + ENROLLED_AGENT, headers=self.legacy_headers(), json={**old_body, "agent_id": "body-spoof-agent"}, ) self.assertEqual(spoofed.status_code, 422, spoofed.text) connection = connect() try: with connection.cursor() as cur: cur.execute( "SELECT count(*) FROM minerops_site_agents WHERE agent_id = %s", ("body-spoof-agent",), ) self.assertEqual(cur.fetchone()[0], 0) finally: connection.close() def test_40_global_secret_rejects_unknown_and_enrolled_explicit_ids(self): for agent_id, expected_status in ( ("unknown-agent", 403), (ENROLLED_AGENT, 401), ): with self.subTest(agent_id=agent_id): response = self.client.get( "/api/agent/config", headers=self.agent_headers( agent_id, settings.minerops_agent_shared_secret ), ) self.assertEqual(response.status_code, expected_status, response.text) self.assert_no_credentials(response) def test_50_enrolled_agent_uses_per_agent_secret_and_own_zone(self): response = self.client.get( "/api/agent/config", headers=self.agent_headers(ENROLLED_AGENT, ENROLLED_SECRET), ) self.assertEqual(response.status_code, 200, response.text) payload = response.json() self.assertEqual(payload["agent_id"], ENROLLED_AGENT) self.assertEqual(payload["agent_zone_id"], str(self.zone_b)) self.assertEqual( [item["cidr"] for item in payload["ip_ranges"]], [ZONE_B_NETWORK], ) self.assertNotIn(ZONE_A_NETWORK, response.text) self.assertNotIn(ZONE_C_NETWORK, response.text) self.assert_no_credentials(response) def test_60_revoked_credential_cannot_use_per_agent_or_global_secret(self): for secret in (REVOKED_SECRET, settings.minerops_agent_shared_secret): with self.subTest(secret_kind="global" if secret != REVOKED_SECRET else "agent"): response = self.client.get( "/api/agent/config", headers=self.agent_headers(REVOKED_AGENT, secret), ) self.assertEqual(response.status_code, 403, response.text) self.assert_no_credentials(response) def test_90_durably_retired_legacy_identity_loses_secret_only_fallback(self): connection = connect() try: with connection.cursor() as cur: cur.execute( """ UPDATE minerops_site_agents SET legacy_auth_disabled_at = now() WHERE agent_id = %s """, (LEGACY_AGENT,), ) connection.commit() finally: connection.close() response = self.client.get( "/api/agent/config", headers=self.legacy_headers() ) self.assertEqual(response.status_code, 401, response.text) self.assert_no_credentials(response) if __name__ == "__main__": unittest.main()