Disable physical control through legacy HTTP/M30 producers, typed admission, queue dispatch and upgraded Windows executors. Restrict diagnostic transports to exact read-only operations, with ordinal PowerShell validation before sockets. Retire unsupported pending/claimed work with atomic, idempotent security audits. Preserve prior delivery evidence and report unknown outcomes after a prior claim, including explicitly repaired pending rows. Include containment, cancellation, concurrency and malformed-payload regressions and the old-Agent cutover runbook. Validation: independent final application-security revalidation PASS. Two unchanged baseline source-assertion failures are documented as exceptions. Production release still requires native Windows validation and verified fencing/stop/drain/upgrade; server cancellation alone cannot revoke a cached command held by an old Agent.
263 lines
11 KiB
Python
263 lines
11 KiB
Python
"""Real PostgreSQL integrity and routing tests for Agent Zones v1."""
|
|
|
|
import unittest
|
|
from uuid import UUID
|
|
from unittest.mock import patch
|
|
|
|
import psycopg
|
|
from psycopg.errors import ForeignKeyViolation, UniqueViolation
|
|
|
|
from app.agent_zones.repository import AgentZoneRepository
|
|
from app.config import settings
|
|
from app.miner_control.repository import MinerControlRepository
|
|
from app.miner_control.service import MinerControlService
|
|
from app.miner_control.exceptions import MinerControlUnavailable
|
|
from app.agent_commands.policy import PHYSICAL_CONTROL_DISABLED
|
|
|
|
|
|
SITE_A = UUID("00000000-0000-4000-8000-000000001630")
|
|
SITE_B = UUID("00000000-0000-4000-8000-000000001631")
|
|
ZONE_A = UUID("00000000-0000-4000-8000-000000001632")
|
|
ZONE_B = UUID("00000000-0000-4000-8000-000000001633")
|
|
ZONE_C = UUID("00000000-0000-4000-8000-000000001636")
|
|
MINER_UNASSIGNED = UUID("00000000-0000-4000-8000-000000001634")
|
|
MINER_OTHER = UUID("00000000-0000-4000-8000-000000001635")
|
|
AGENT_A = "agent-zone-postgres-a"
|
|
|
|
|
|
def connect():
|
|
return psycopg.connect(
|
|
host=settings.postgres_host,
|
|
port=settings.postgres_port,
|
|
dbname=settings.postgres_db,
|
|
user=settings.postgres_user,
|
|
password=settings.postgres_password,
|
|
connect_timeout=5,
|
|
)
|
|
|
|
|
|
class AgentZonePostgresTests(unittest.TestCase):
|
|
def assert_stage_a_unavailable(self, expected_zone, expected_agent):
|
|
repository = MinerControlRepository(connect)
|
|
context = repository.get_control_context(MINER_UNASSIGNED)
|
|
# Check actual routing facts independently of the unconditional Stage A
|
|
# reason. A changed assertion must not hide a Site fallback regression.
|
|
self.assertEqual(context["agent_zone_id"], expected_zone)
|
|
self.assertEqual(context["agent_id"], expected_agent)
|
|
projection = MinerControlService(repository).get_controls(MINER_UNASSIGNED)
|
|
for capability in (projection.service_control, projection.performance_mode_control):
|
|
self.assertEqual(capability.state, "unavailable")
|
|
self.assertEqual(capability.reason, PHYSICAL_CONTROL_DISABLED)
|
|
self.assertIsNone(projection.available_service_action)
|
|
with patch.object(repository, "enqueue_with_audit") as enqueue:
|
|
for action, value in (("suspend", None), ("resume", None), ("performance_mode", "high")):
|
|
with self.assertRaisesRegex(MinerControlUnavailable, PHYSICAL_CONTROL_DISABLED):
|
|
MinerControlService(repository).queue_control(
|
|
MINER_UNASSIGNED, action, requested_value=value,
|
|
actor_user_id=UUID("00000000-0000-4000-8000-000000001639"),
|
|
actor_username="zone-containment-test",
|
|
)
|
|
enqueue.assert_not_called()
|
|
return context
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
connection = connect()
|
|
try:
|
|
with connection.cursor() as cur:
|
|
cur.execute(
|
|
"INSERT INTO sites (id, name) VALUES (%s, 'Zone Test A'), "
|
|
"(%s, 'Zone Test B') ON CONFLICT (id) DO NOTHING",
|
|
(SITE_A, SITE_B),
|
|
)
|
|
cur.execute(
|
|
"INSERT INTO agent_zones (id, site_id, name) VALUES "
|
|
"(%s, %s, 'Main Room'), (%s, %s, 'Remote Room'), "
|
|
"(%s, %s, 'Unstaffed Zone') "
|
|
"ON CONFLICT (id) DO UPDATE SET is_enabled = true",
|
|
(ZONE_A, SITE_A, ZONE_B, SITE_B, ZONE_C, SITE_A),
|
|
)
|
|
cur.execute(
|
|
"INSERT INTO miners (id, site_id, asset_tag, current_ip, status, "
|
|
"api3_supported, first_seen_at, last_seen_at) VALUES "
|
|
"(%s, %s, 'ZONE-UNASSIGNED', '192.0.2.31', 'online', true, NULL, NULL), "
|
|
"(%s, %s, 'ZONE-OTHER', '192.0.2.32', 'online', true, NULL, NULL) "
|
|
"ON CONFLICT (id) DO UPDATE SET agent_zone_id = NULL",
|
|
(MINER_UNASSIGNED, SITE_A, MINER_OTHER, SITE_B),
|
|
)
|
|
cur.execute(
|
|
"UPDATE miners SET agent_zone_id = %s WHERE id = %s",
|
|
(ZONE_B, MINER_OTHER),
|
|
)
|
|
cur.execute(
|
|
"INSERT INTO minerops_site_agents ("
|
|
"agent_id, site_id, agent_zone_id, site_name, last_payload) "
|
|
"VALUES (%s, %s, %s, 'Zone Test A', '{\"control_available\":true}') "
|
|
"ON CONFLICT (agent_id) DO UPDATE SET site_id = EXCLUDED.site_id, "
|
|
"agent_zone_id = EXCLUDED.agent_zone_id, last_payload = EXCLUDED.last_payload",
|
|
(AGENT_A, SITE_A, ZONE_A),
|
|
)
|
|
connection.commit()
|
|
finally:
|
|
connection.close()
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
connection = connect()
|
|
try:
|
|
with connection.cursor() as cur:
|
|
cur.execute("DELETE FROM minerops_site_agents WHERE agent_id LIKE 'agent-zone-postgres-%'")
|
|
cur.execute("DELETE FROM miners WHERE id IN (%s, %s)", (MINER_UNASSIGNED, MINER_OTHER))
|
|
cur.execute("DELETE FROM agent_zone_network_ranges WHERE agent_zone_id IN (%s, %s, %s)", (ZONE_A, ZONE_B, ZONE_C))
|
|
cur.execute("DELETE FROM agent_zones WHERE id IN (%s, %s, %s)", (ZONE_A, ZONE_B, ZONE_C))
|
|
cur.execute("DELETE FROM sites WHERE id IN (%s, %s)", (SITE_A, SITE_B))
|
|
connection.commit()
|
|
finally:
|
|
connection.close()
|
|
|
|
def setUp(self):
|
|
connection = connect()
|
|
try:
|
|
with connection.cursor() as cur:
|
|
cur.execute(
|
|
"UPDATE agent_zones SET is_enabled = true "
|
|
"WHERE id IN (%s, %s, %s)",
|
|
(ZONE_A, ZONE_B, ZONE_C),
|
|
)
|
|
cur.execute(
|
|
"UPDATE miners SET agent_zone_id = NULL WHERE id = %s",
|
|
(MINER_UNASSIGNED,),
|
|
)
|
|
cur.execute(
|
|
"UPDATE miners SET site_id = %s, agent_zone_id = %s WHERE id = %s",
|
|
(SITE_B, ZONE_B, MINER_OTHER),
|
|
)
|
|
cur.execute(
|
|
"UPDATE minerops_site_agents SET site_id = %s, agent_zone_id = %s "
|
|
"WHERE agent_id = %s",
|
|
(SITE_A, ZONE_A, AGENT_A),
|
|
)
|
|
connection.commit()
|
|
finally:
|
|
connection.close()
|
|
|
|
def test_repository_lists_multiple_canonical_networks(self):
|
|
connection = connect()
|
|
try:
|
|
with connection.cursor() as cur:
|
|
cur.execute(
|
|
"INSERT INTO agent_zone_network_ranges (agent_zone_id, network) "
|
|
"VALUES (%s, '10.30.0.0/24'), (%s, '10.31.0.0/24') "
|
|
"ON CONFLICT DO NOTHING",
|
|
(ZONE_A, ZONE_A),
|
|
)
|
|
connection.commit()
|
|
finally:
|
|
connection.close()
|
|
listed = AgentZoneRepository(connect).list_zones(SITE_A)
|
|
self.assertEqual([item["network"] for item in listed[0]["networks"]],
|
|
["10.30.0.0/24", "10.31.0.0/24"])
|
|
|
|
def test_active_names_are_case_insensitively_unique_per_site(self):
|
|
connection = connect()
|
|
try:
|
|
with self.assertRaises(UniqueViolation), connection.cursor() as cur:
|
|
cur.execute(
|
|
"INSERT INTO agent_zones (site_id, name) VALUES (%s, 'main room')",
|
|
(SITE_A,),
|
|
)
|
|
finally:
|
|
connection.rollback()
|
|
connection.close()
|
|
|
|
def test_one_agent_per_zone_but_multiple_zones_per_site(self):
|
|
connection = connect()
|
|
try:
|
|
with self.assertRaises(UniqueViolation), connection.cursor() as cur:
|
|
cur.execute(
|
|
"INSERT INTO minerops_site_agents "
|
|
"(agent_id, site_id, agent_zone_id, site_name) "
|
|
"VALUES ('agent-zone-postgres-duplicate', %s, %s, 'Duplicate')",
|
|
(SITE_A, ZONE_A),
|
|
)
|
|
finally:
|
|
connection.rollback()
|
|
connection.close()
|
|
|
|
def test_composite_foreign_keys_reject_cross_site_assignment(self):
|
|
connection = connect()
|
|
try:
|
|
with self.assertRaises(ForeignKeyViolation), connection.cursor() as cur:
|
|
cur.execute(
|
|
"UPDATE miners SET agent_zone_id = %s WHERE id = %s",
|
|
(ZONE_A, MINER_OTHER),
|
|
)
|
|
finally:
|
|
connection.rollback()
|
|
connection.close()
|
|
|
|
def test_unassigned_miner_inherits_zone_and_existing_other_zone_wins(self):
|
|
repository = AgentZoneRepository(connect)
|
|
outcomes = repository.assign_miners_to_zone(
|
|
[MINER_UNASSIGNED, MINER_OTHER], ZONE_A
|
|
)
|
|
self.assertEqual(outcomes[MINER_UNASSIGNED], "assigned")
|
|
self.assertEqual(outcomes[MINER_OTHER], "agent_zone_conflict")
|
|
connection = connect()
|
|
try:
|
|
with connection.cursor() as cur:
|
|
cur.execute(
|
|
"SELECT id, agent_zone_id FROM miners WHERE id IN (%s, %s)",
|
|
(MINER_UNASSIGNED, MINER_OTHER),
|
|
)
|
|
assignments = dict(cur.fetchall())
|
|
finally:
|
|
connection.close()
|
|
self.assertEqual(assignments[MINER_UNASSIGNED], ZONE_A)
|
|
self.assertEqual(assignments[MINER_OTHER], ZONE_B)
|
|
|
|
def test_disabled_zone_blocks_control_without_site_fallback(self):
|
|
connection = connect()
|
|
try:
|
|
with connection.cursor() as cur:
|
|
cur.execute(
|
|
"UPDATE miners SET agent_zone_id = %s WHERE id = %s",
|
|
(ZONE_A, MINER_UNASSIGNED),
|
|
)
|
|
cur.execute("UPDATE agent_zones SET is_enabled = false WHERE id = %s", (ZONE_A,))
|
|
connection.commit()
|
|
finally:
|
|
connection.close()
|
|
try:
|
|
context = self.assert_stage_a_unavailable(ZONE_A, AGENT_A)
|
|
self.assertFalse(context["agent_zone_enabled"])
|
|
finally:
|
|
connection = connect()
|
|
try:
|
|
with connection.cursor() as cur:
|
|
cur.execute("UPDATE agent_zones SET is_enabled = true WHERE id = %s", (ZONE_A,))
|
|
connection.commit()
|
|
finally:
|
|
connection.close()
|
|
|
|
|
|
def test_enabled_zone_without_agent_does_not_fall_back_within_site(self):
|
|
connection = connect()
|
|
try:
|
|
with connection.cursor() as cur:
|
|
cur.execute(
|
|
"UPDATE miners SET agent_zone_id = %s WHERE id = %s",
|
|
(ZONE_C, MINER_UNASSIGNED),
|
|
)
|
|
connection.commit()
|
|
finally:
|
|
connection.close()
|
|
self.assert_stage_a_unavailable(ZONE_C, None)
|
|
|
|
def test_null_zone_does_not_fall_back_to_site_agent(self):
|
|
self.assert_stage_a_unavailable(None, None)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|