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:
1 parent
e898f283ab
commit
8b0d32cd6b
26 files changed
+3798
-4092
No files matched your search
@@ -10,6 +10,7 @@ from app.agent_zones.exceptions import (
|
||||
from app.agent_zones.models import (
|
||||
AgentCheckinRequest,
|
||||
AgentCheckinResponse,
|
||||
AgentDiscoveryMinerMatch,
|
||||
AgentZoneRoutingContext,
|
||||
AgentZoneCreateRequest,
|
||||
AgentZoneSummary,
|
||||
@@ -81,6 +82,8 @@ class AgentZoneService:
|
||||
self.validate_agent_identity(authenticated_agent_id, request.agent_id)
|
||||
|
||||
existing = self.repository.get_agent(authenticated_agent_id)
|
||||
if not existing or existing.get("agent_zone_id") is None:
|
||||
raise AgentZoneValidationError("Agent requires an administrator-established Zone assignment")
|
||||
requested_site = request.site_id
|
||||
requested_zone = request.agent_zone_id
|
||||
final_site = requested_site or (existing or {}).get("site_id")
|
||||
@@ -199,6 +202,30 @@ class AgentZoneService:
|
||||
],
|
||||
}
|
||||
|
||||
def match_discovered_miner(
|
||||
self,
|
||||
agent_id: str,
|
||||
*,
|
||||
mac_address: str | None,
|
||||
ip_address: str | None,
|
||||
recorded_zone_id: UUID | None = None,
|
||||
) -> AgentDiscoveryMinerMatch:
|
||||
routing = self.routing_context(agent_id, recorded_zone_id)
|
||||
if routing.routing_reason or routing.agent_zone_id is None:
|
||||
return AgentDiscoveryMinerMatch(**routing.model_dump())
|
||||
|
||||
match = self.repository.find_miner_in_zone(
|
||||
agent_id=agent_id,
|
||||
agent_zone_id=routing.agent_zone_id,
|
||||
mac_address=mac_address,
|
||||
ip_address=ip_address,
|
||||
)
|
||||
return AgentDiscoveryMinerMatch(
|
||||
**routing.model_dump(),
|
||||
miner_id=match["id"] if match else None,
|
||||
matched_by=match["matched_by"] if match else None,
|
||||
)
|
||||
|
||||
def associate_miners_from_agent(
|
||||
self, agent_id: str, miner_ids: list[UUID]
|
||||
) -> MinerZoneAssociationResult:
|
||||
|
||||
Reference in new issue
Block a user