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
@@ -204,6 +204,8 @@ class AgentZoneRepository:
|
||||
ip_address = EXCLUDED.ip_address,
|
||||
last_checkin_at = now(),
|
||||
last_payload = EXCLUDED.last_payload
|
||||
WHERE minerops_site_agents.site_id IS NOT DISTINCT FROM EXCLUDED.site_id
|
||||
AND minerops_site_agents.agent_zone_id IS NOT DISTINCT FROM EXCLUDED.agent_zone_id
|
||||
""",
|
||||
(
|
||||
agent_id,
|
||||
@@ -216,6 +218,8 @@ class AgentZoneRepository:
|
||||
Jsonb(payload),
|
||||
),
|
||||
)
|
||||
if cur.rowcount != 1:
|
||||
raise AgentZoneConflict("Agent assignment changed concurrently")
|
||||
connection.commit()
|
||||
except UniqueViolation as exc:
|
||||
connection.rollback()
|
||||
@@ -294,6 +298,20 @@ class AgentZoneRepository:
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
def find_miner_in_zone(self, *, agent_id: str, agent_zone_id: UUID,
|
||||
mac_address: str | None, ip_address: str | None) -> dict | None:
|
||||
"""Retained helper uses the same atomic authority/collision boundary as HTTP."""
|
||||
from app.discovery.repository import DiscoveryRepository, reject
|
||||
repository = DiscoveryRepository(self._connection_factory)
|
||||
with repository.transaction() as cur:
|
||||
context = repository.context(cur, agent_id)
|
||||
if context['agent_zone_id'] != agent_zone_id:
|
||||
reject('discovery_stale_authority')
|
||||
if not mac_address and not ip_address:
|
||||
return None
|
||||
row = repository.match(cur, context, {'mac_address': mac_address, 'ip_address': ip_address})
|
||||
return {'id': row['id'], 'matched_by': 'mac' if mac_address else 'ip'} if row else None
|
||||
|
||||
def assign_miners_to_zone(
|
||||
self, miner_ids: Iterable[UUID], agent_zone_id: UUID
|
||||
) -> dict[UUID, str]:
|
||||
@@ -326,15 +344,7 @@ class AgentZoneRepository:
|
||||
elif miner["site_id"] not in {None, zone["site_id"]}:
|
||||
outcomes[miner_id] = "site_conflict"
|
||||
else:
|
||||
cur.execute(
|
||||
"""
|
||||
UPDATE miners
|
||||
SET site_id = %s, agent_zone_id = %s, updated_at = now()
|
||||
WHERE id = %s AND agent_zone_id IS NULL
|
||||
""",
|
||||
(zone["site_id"], agent_zone_id, miner_id),
|
||||
)
|
||||
outcomes[miner_id] = "assigned"
|
||||
outcomes[miner_id] = "miner_zone_unassigned"
|
||||
connection.commit()
|
||||
return outcomes
|
||||
except Exception:
|
||||
|
||||
Reference in new issue
Block a user