security(discovery): enforce Zone isolation and retire unsafe legacy writers

Bind Agent observations, review, enrichment and telemetry to current Zone
and inventory authority. Preserve immutable MAC ownership and historical
snapshots with stale-result rejection and transactional security audits.

Retire unbound direct/range/scheduled discovery and one/bulk legacy summary
writes in both modes. Require reconciled exact inventory identity or
explicit Zone-scoped IP selection for CSV metadata imports.

Independent Blocker #1 application-security re-audit: PASS on tree
cf863aadc9. Evidence: 141 focused PostgreSQL/HTTP
tests passed; Chromium and PowerShell checks passed. Two documented baseline
source assertions remain unchanged. Production deployment is not approved.
This commit is contained in:
lussierj committed 2026-10-17 00:45:04 +00:00
1 parent e898f283ab
commit 8b0d32cd6b
26 files changed
+3798 -4092

No files matched your search

+53 -28
View File
@@ -42,6 +42,7 @@ class FakeRepository:
self.agent = None
self.saved = []
self.assign_result = {MINER_A: "assigned"}
self.discovery_match = None
def get_agent(self, agent_id):
return self.agent if self.agent and self.agent["agent_id"] == agent_id else None
@@ -107,6 +108,11 @@ class FakeRepository:
],
}
def find_miner_in_zone(self, *, agent_id, agent_zone_id, mac_address, ip_address):
self.discovery_match_request = {'agent_id':agent_id,'agent_zone_id':agent_zone_id,
'mac_address':mac_address,'ip_address':ip_address}
return self.discovery_match
def assign_miners_to_zone(self, miner_ids, agent_zone_id):
self.assigned = (list(miner_ids), agent_zone_id)
return {miner_id: self.assign_result.get(miner_id, "miner_not_found")
@@ -136,6 +142,7 @@ class AgentZoneModelTests(unittest.TestCase):
class AgentZoneServiceTests(unittest.TestCase):
def setUp(self):
self.repository = FakeRepository()
self.repository.agent = {"agent_id":"agent-a","site_id":SITE_A,"agent_zone_id":ZONE_A,"site_name":"North"}
self.service = AgentZoneService(self.repository)
def checkin(self, **kwargs):
@@ -144,14 +151,14 @@ class AgentZoneServiceTests(unittest.TestCase):
AgentCheckinRequest(agent_id="agent-a", site_name="North", **kwargs),
)
def test_explicit_first_assignment_and_same_assignment_are_allowed(self):
def test_established_assignment_and_same_assignment_are_allowed(self):
first = self.checkin(site_id=SITE_A, agent_zone_id=ZONE_A)
second = self.checkin(site_id=SITE_A, agent_zone_id=ZONE_A)
self.assertTrue(first.routing_available)
self.assertEqual(second.agent_zone_id, ZONE_A)
def test_explicit_zone_site_mismatch_and_identity_spoof_are_rejected(self):
with self.assertRaisesRegex(AgentZoneValidationError, "does not belong"):
with self.assertRaisesRegex(AgentZoneValidationError, "cannot change Sites"):
self.checkin(site_id=SITE_B, agent_zone_id=ZONE_A)
with self.assertRaisesRegex(AgentZoneValidationError, "authenticated"):
self.service.checkin(
@@ -181,34 +188,20 @@ class AgentZoneServiceTests(unittest.TestCase):
self.assertEqual(result.agent_zone_id, ZONE_A)
def test_transitional_resolution_requires_exactly_one_enabled_zone(self):
single = self.checkin(site_id=SITE_A)
self.assertEqual(single.agent_zone_id, ZONE_A)
self.repository.agent = None
self.repository.zones = {}
zero = self.checkin(site_id=SITE_A)
self.assertEqual(zero.routing_reason, "agent_zone_unavailable")
self.repository.agent = None
self.repository.zones = {
ZONE_A: zone(),
ZONE_B: zone(ZONE_B, SITE_A, name="Room 2"),
}
many = self.checkin(site_id=SITE_A)
self.assertEqual(many.routing_reason, "agent_zone_ambiguous")
self.assertIsNone(many.agent_zone_id)
for zones in [{}, {ZONE_A: zone()}, {ZONE_A:zone(),ZONE_B:zone(ZONE_B,SITE_A)}]:
self.repository.zones=zones
self.repository.agent=None
with self.assertRaisesRegex(AgentZoneValidationError,"administrator-established"):
self.checkin(site_id=SITE_A)
def test_disabled_zone_is_not_selected_and_existing_assignment_is_factual(self):
self.repository.zones[ZONE_A]["is_enabled"] = False
unassigned = self.checkin(site_id=SITE_A)
self.assertEqual(unassigned.routing_reason, "agent_zone_unavailable")
self.repository.agent = {
"agent_id": "agent-a", "site_id": SITE_A,
"agent_zone_id": ZONE_A, "site_name": "North",
}
existing = self.service.checkin(
"agent-a", AgentCheckinRequest(agent_id="agent-a")
)
self.assertEqual(existing.routing_reason, "agent_zone_disabled")
self.assertEqual(existing.agent_zone_id, ZONE_A)
self.repository.zones[ZONE_A]["is_enabled"]=False
existing=self.service.checkin("agent-a",AgentCheckinRequest(agent_id="agent-a"))
self.assertEqual(existing.routing_reason,"agent_zone_disabled")
self.assertEqual(existing.agent_zone_id,ZONE_A)
self.repository.agent=None
with self.assertRaisesRegex(AgentZoneValidationError,"administrator-established"):
self.checkin(site_id=SITE_A)
def test_payload_is_sanitized_before_persistence(self):
request = AgentCheckinRequest.model_validate({
@@ -255,9 +248,41 @@ class AgentZoneServiceTests(unittest.TestCase):
self.assertNotIn("10.80.0.0/24", str(configuration))
def test_discovery_match_uses_only_authenticated_agent_zone(self):
self.checkin(site_id=SITE_A, agent_zone_id=ZONE_A)
self.repository.discovery_match = {"id": MINER_A, "matched_by": "mac"}
result = self.service.match_discovered_miner(
"agent-a",
mac_address="02:00:00:00:16:21",
ip_address="192.0.2.21",
)
self.assertEqual(result.miner_id, MINER_A)
self.assertEqual(result.matched_by, "mac")
self.assertEqual(
self.repository.discovery_match_request["agent_zone_id"], ZONE_A
)
def test_discovery_match_rejects_stale_recorded_zone_without_querying(self):
self.checkin(site_id=SITE_A, agent_zone_id=ZONE_A)
result = self.service.match_discovered_miner(
"agent-a",
recorded_zone_id=ZONE_B,
mac_address="02:00:00:00:16:21",
ip_address="192.0.2.21",
)
self.assertIsNone(result.miner_id)
self.assertEqual(result.routing_reason, "agent_zone_conflict")
self.assertFalse(hasattr(self.repository, "discovery_match_request"))
class AgentZoneRouterTests(unittest.TestCase):
def setUp(self):
self.repository = FakeRepository()
self.repository.agent = {"agent_id":"agent-a","site_id":SITE_A,"agent_zone_id":ZONE_A,"site_name":"North"}
self.service = AgentZoneService(self.repository)
self.app = FastAPI()
self.app.include_router(router)