Files
minerops/backend/tests/test_discovery_security_postgres.py
lussierj 8b0d32cd6b 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.
2026-10-17 00:45:04 +00:00

1212 lines
45 KiB
Python

"""Discovery authority: real PostgreSQL + registered HTTP routes; disposable only."""
from concurrent.futures import ThreadPoolExecutor
import copy, json, os, threading, time, unittest
from uuid import uuid4
from unittest.mock import patch
from fastapi.testclient import TestClient
from psycopg.rows import dict_row
from psycopg.types.json import Jsonb
from app.main import app
from app.config import settings
from app.identity import create_access_token
from app.agent_auth.service import hash_agent_secret
from app.agent_zones.repository import default_connection_factory as connect
from app.discovery.repository import DiscoveryRepository
class DiscoveryFixtures:
@classmethod
def setUpClass(cls):
if (
os.getenv("MINEROPS_DISCOVERY_DISPOSABLE") != "1"
or settings.postgres_db != "discovery_review"
):
raise RuntimeError("Explicit disposable discovery database required")
def setUp(self):
self.sites = [uuid4(), uuid4()]
self.zones = [uuid4(), uuid4()]
self.agents = ["discovery-test-" + uuid4().hex for _ in range(2)]
self.uid = uuid4()
self.secrets = ["disposable-" + a for a in self.agents]
self.client = TestClient(app, raise_server_exceptions=True)
self.addCleanup(self.client.close)
self.transport = patch(
"app.main.send_whatsminer_read_command",
side_effect=AssertionError("No miner I/O"),
).start()
self.addCleanup(patch.stopall)
with connect() as c, c.cursor() as q:
for site, zone, agent in zip(self.sites, self.zones, self.agents):
q.execute(
"INSERT INTO sites(id,name) VALUES (%s,%s)", (site, str(site))
)
q.execute(
"INSERT INTO agent_zones(id,site_id,name) VALUES (%s,%s,'Zone')",
(zone, site),
)
q.execute(
"INSERT INTO agent_zone_network_ranges(agent_zone_id,network) VALUES (%s,'198.51.100.0/24')",
(zone,),
)
q.execute(
"""INSERT INTO minerops_site_agents(agent_id,site_id,agent_zone_id,site_name,agent_secret_hash,credential_created_at)
VALUES (%s,%s,%s,'Test',%s,now())""",
(
agent,
site,
zone,
hash_agent_secret(self.secrets[self.agents.index(agent)]),
),
)
q.execute(
"INSERT INTO users(id,username,display_name,password_hash,role_id) SELECT %s,%s,'Reviewer','unused',id FROM roles WHERE name='Admin'",
(self.uid, str(self.uid)),
)
self.admin = {
"Authorization": "Bearer "
+ create_access_token(str(self.uid), str(self.uid), "Admin")
}
self.repo = DiscoveryRepository()
def headers(self, i=0):
return {
"X-MinerOps-Agent-ID": self.agents[i],
"X-MinerOps-Agent-Secret": self.secrets[i],
}
def remap(self, value):
if isinstance(value, dict):
return {k: self.remap(v) for k, v in value.items()}
if isinstance(value, list):
return [self.remap(v) for v in value]
if (
isinstance(value, str)
and value.startswith("02:12:34:00:00:")
and len(value) == 17
):
return (
"02:"
+ ":".join(f"{v:02X}" for v in self.uid.bytes[:4])
+ ":"
+ value[-2:]
)
return value
def post(self, path, body, agent=0):
return self.client.post(
path, json=self.remap(body), headers=self.headers(agent)
)
def review(self, row, action="add_to_inventory", **overrides):
return self.client.post(
"/api/agent/discoveries/review",
json={
"discovery_id": row["id"],
"version": row["version"],
"action": action,
**overrides,
},
headers=self.admin,
)
def observe(self, ip="198.51.100.10", mac="02:12:34:00:00:10", agent=0, **extra):
result = self.post(
"/api/agent/discoveries",
{
"agent_id": self.agents[agent],
"discoveries": [{"ip_address": ip, "mac_address": mac, **extra}],
},
agent,
)
self.assertEqual(result.status_code, 200, result.text)
return result.json()["discoveries"][0]
def miner(self, i=0, ip="198.51.100.10", mac=None):
mid = uuid4()
mac = self.remap(mac)
mac = mac or "02:" + ":".join(f"{v:02X}" for v in mid.bytes[:5])
with connect() as c, c.cursor() as q:
q.execute(
"""INSERT INTO miners(id,site_id,agent_zone_id,current_ip,current_mac,status) VALUES (%s,%s,%s,%s,%s,'online')""",
(mid, self.sites[i], self.zones[i], ip, mac),
)
return mid, mac
def scalar(self, sql, args=()):
with connect() as c, c.cursor() as q:
q.execute(sql, args)
return q.fetchone()[0]
def durable(self):
data = {}
with connect() as c, c.cursor() as q:
for table in [
"miners",
"miner_mac_ownerships",
"miner_network_identities",
"miner_status_snapshots",
"minerops_agent_discoveries",
"audit_logs",
"minerops_agent_command_queue",
]:
q.execute(
"SELECT to_jsonb(t) FROM " + table + " t ORDER BY to_jsonb(t)::text"
)
data[table] = q.fetchall()
return data
def known(self, i=0):
r = self.client.get("/api/agent/known-miners", headers=self.headers(i))
self.assertEqual(r.status_code, 200, r.text)
return r.json()["miners"]
class DiscoverySecurityTests(DiscoveryFixtures, unittest.TestCase):
def test_same_ip_distinct_zones_review_is_stable_and_scoped(self):
a = self.observe(mac="02:12:34:00:00:11")
b = self.observe(agent=1, mac="02:12:34:00:00:12")
before = self.scalar(
"SELECT to_jsonb(d) FROM minerops_agent_discoveries d WHERE id=%s",
(b["id"],),
)
r = self.review(a)
self.assertEqual(r.status_code, 200, r.text)
self.assertEqual(
self.scalar(
"SELECT to_jsonb(d) FROM minerops_agent_discoveries d WHERE id=%s",
(b["id"],),
),
before,
)
self.assertEqual(
self.scalar(
"SELECT agent_zone_id FROM miners WHERE id=%s", (r.json()["miner_id"],)
),
self.zones[0],
)
r = self.review(b)
self.assertEqual(r.status_code, 200, r.text)
def test_ignore_non_miner_do_not_touch_other_zone(self):
for action, ip in [("ignore", "198.51.100.11"), ("non_miner", "198.51.100.12")]:
a = self.observe(ip=ip, mac=None)
b = self.observe(ip=ip, mac=None, agent=1)
self.assertEqual(self.review(a, action).status_code, 200)
self.assertEqual(
self.scalar(
"SELECT discovery_status FROM minerops_agent_discoveries WHERE id=%s",
(b["id"],),
),
"new",
)
def test_foreign_current_and_historical_mac_are_conflicts(self):
mid, mac = self.miner(1)
for spelling in [mac, mac.lower(), mac.replace(":", "-"), mac.replace(":", "")]:
row = self.observe(ip="198.51.100.20", mac=spelling)
self.assertEqual(row["discovery_status"], "zone_conflict")
self.assertIsNone(row["matched_miner_id"])
self.assertEqual(self.review(row).status_code, 409)
with connect() as c, c.cursor() as q:
q.execute("UPDATE miners SET current_mac=NULL WHERE id=%s", (mid,))
row = self.observe(ip="198.51.100.21", mac=mac)
self.assertEqual(row["discovery_status"], "zone_conflict")
self.assertEqual(
self.scalar(
"SELECT miner_id FROM miner_mac_ownerships WHERE normalized_mac=%s",
(mac.replace(":", "").lower(),),
),
mid,
)
def test_local_duplicate_ip_and_contradictory_ids_fail(self):
self.miner()
self.miner()
row = self.observe(mac=None)
self.assertEqual(row["discovery_status"], "zone_conflict")
self.assertEqual(self.review(row).status_code, 409)
def test_spoofed_identity_and_zone_do_not_authorize(self):
r = self.post(
"/api/agent/discoveries", {"agent_id": self.agents[1], "discoveries": []}
)
self.assertEqual(r.status_code, 403)
r = self.post(
"/api/agent/discoveries",
{
"agent_zone_id": str(self.zones[1]),
"site_id": str(self.sites[1]),
"discoveries": [{"ip_address": "198.51.100.1"}],
},
)
self.assertEqual(r.status_code, 200, r.text)
self.assertEqual(r.json()["agent_zone_id"], str(self.zones[0]))
for headers in [
{},
{"X-MinerOps-Agent-ID": self.agents[1], "X-MinerOps-Agent-Secret": "wrong"},
]:
self.assertIn(
self.client.post(
"/api/agent/discoveries", json={"discoveries": []}, headers=headers
).status_code,
[401, 403],
)
def test_review_permissions_and_missing_stable_id(self):
row = self.observe()
r = self.post(
"/api/agent/discoveries/review",
{"discovery_id": row["id"], "version": row["version"], "action": "ignore"},
)
self.assertEqual(r.status_code, 401)
uid = uuid4()
with connect() as c, c.cursor() as q:
q.execute(
"INSERT INTO users(id,username,display_name,password_hash,role_id) SELECT %s,%s,'No authority','unused',id FROM roles WHERE name='Read Only'",
(uid, str(uid)),
)
headers = {
"Authorization": "Bearer "
+ create_access_token(str(uid), str(uid), "Read Only")
}
self.assertEqual(
self.client.post(
"/api/agent/discoveries/review",
headers=headers,
json={
"discovery_id": row["id"],
"version": row["version"],
"action": "ignore",
},
).status_code,
403,
)
before = self.durable()
for path, body in [
(
"/api/agent/discoveries/enrich-match",
{"discovery_id": row["id"], "version": row["version"]},
),
("/api/agent/commands/run-poll-now", {"agent_id": self.agents[0]}),
("/api/agent/commands/scan-new-miners", {"agent_id": self.agents[0]}),
]:
self.assertEqual(
self.client.post(path, json=body, headers=headers).status_code, 403
)
self.assertEqual(self.post(path, body).status_code, 401)
self.assertEqual(before, self.durable())
self.assertEqual(
self.client.post(
"/api/agent/discoveries/review",
headers=self.admin,
json={"ip_address": "198.51.100.10", "action": "ignore"},
).status_code,
422,
)
def test_stale_disabled_unassigned_and_unproved_history_rejected(self):
row = self.observe()
with connect() as c, c.cursor() as q:
q.execute(
"UPDATE agent_zones SET is_enabled=false,updated_at=now() WHERE id=%s",
(self.zones[0],),
)
self.assertEqual(self.review(row).status_code, 409)
self.assertEqual(
self.scalar(
"SELECT count(*) FROM miners WHERE agent_zone_id=%s", (self.zones[0],)
),
0,
)
with connect() as c, c.cursor() as q:
q.execute(
"UPDATE agent_zones SET is_enabled=true,updated_at=now() WHERE id=%s",
(self.zones[0],),
)
q.execute(
"UPDATE minerops_agent_discoveries SET agent_zone_id=NULL WHERE id=%s",
(row["id"],),
)
self.assertEqual(self.review(row).status_code, 409)
def test_stale_version_superseded_observation_and_inventory_change(self):
row = self.observe()
self.assertEqual(self.review(row, version="stale").status_code, 409)
newer = self.observe(hostname="newer")
self.assertEqual(self.review(row).status_code, 409)
self.miner(mac="02:12:34:00:00:10")
self.assertEqual(self.review(newer).status_code, 409)
def test_approval_retry_is_idempotent_and_audited(self):
row = self.observe()
one = self.review(row)
two = self.review(row)
self.assertEqual(one.status_code, 200, one.text)
self.assertEqual(one.json(), two.json())
self.assertEqual(
self.scalar(
"SELECT count(*) FROM audit_logs WHERE entity_id=%s AND action='discovery.reviewed'",
(row["id"],),
),
1,
)
self.assertEqual(
self.scalar(
"SELECT count(*) FROM miners WHERE agent_zone_id=%s", (self.zones[0],)
),
1,
)
def test_concurrent_approvals_create_one_miner(self):
row = self.observe()
def work():
return self.repo.review(
{
"discovery_id": row["id"],
"version": row["version"],
"action": "add_to_inventory",
},
{"id": str(self.uid), "username": "reviewer"},
)
with ThreadPoolExecutor(2) as pool:
a, b = [f.result() for f in [pool.submit(work), pool.submit(work)]]
self.assertEqual(a, b)
self.assertEqual(
self.scalar(
"SELECT count(*) FROM miners WHERE agent_zone_id=%s", (self.zones[0],)
),
1,
)
def test_audit_denial_rolls_back_miner_and_observation(self):
row = self.observe()
role = "b1_limited_" + uuid4().hex[:10]
with connect() as c, c.cursor() as q:
q.execute("CREATE ROLE " + role)
q.execute("GRANT USAGE ON SCHEMA public TO " + role)
q.execute("GRANT SELECT ON ALL TABLES IN SCHEMA public TO " + role)
q.execute(
"GRANT INSERT,UPDATE ON miners,minerops_agent_discoveries,miner_mac_ownerships,minerops_site_agents,agent_zones,agent_zone_network_ranges TO "
+ role
)
def limited():
c = connect()
c.execute("SET ROLE " + role)
return c
before = self.durable()
with self.assertRaisesRegex(Exception, "audit_logs"):
DiscoveryRepository(limited).review(
{
"discovery_id": row["id"],
"version": row["version"],
"action": "add_to_inventory",
},
{"id": str(self.uid)},
)
self.assertEqual(before, self.durable())
def test_queue_targets_observing_agent_and_claim_is_validated(self):
row = self.observe(agent=1)
r = self.client.post(
"/api/agent/discoveries/enrich-match",
json={"discovery_id": row["id"], "version": row["version"]},
headers=self.admin,
)
self.assertEqual(r.status_code, 200, r.text)
qid = r.json()["command_id"]
self.assertEqual(
self.scalar(
"SELECT agent_id FROM minerops_agent_command_queue WHERE id=%s", (qid,)
),
self.agents[1],
)
claims = self.client.get("/api/agent/commands/pending", headers=self.headers(1))
self.assertEqual(claims.status_code, 200, claims.text)
self.assertEqual([v["command_id"] for v in claims.json()["commands"]], [qid])
body = {
"discovery_id": row["id"],
"version": row["version"],
"command_id": qid,
"ip_address": "198.51.100.10",
"mac_address": "02:12:34:00:00:10",
"model": "Enriched",
}
result = self.post("/api/agent/miner-enrichment-v3", body, 1)
self.assertEqual(result.status_code, 200, result.text)
original = self.scalar(
"SELECT raw_payload FROM minerops_agent_discoveries WHERE id=%s",
(row["id"],),
)
self.assertNotIn("command_id", original)
self.assertNotEqual(result.json()["discovery"]["id"], row["id"])
def test_arbitrary_or_stale_enrichment_command_cannot_dispatch(self):
self.assertEqual(
self.client.post(
"/api/agent/discoveries/enrich-match",
json={"ip_address": "198.51.100.10"},
headers=self.admin,
).status_code,
422,
)
row = self.observe()
r = self.client.post(
"/api/agent/discoveries/enrich-match",
json={"discovery_id": row["id"], "version": row["version"]},
headers=self.admin,
)
self.assertEqual(r.status_code, 200, r.text)
self.assertEqual(self.review(row, "ignore").status_code, 200)
claims = self.client.get("/api/agent/commands/pending", headers=self.headers())
self.assertEqual(claims.status_code, 200, claims.text)
self.assertEqual(claims.json()["commands"], [])
self.assertEqual(
self.scalar(
"SELECT command_status FROM minerops_agent_command_queue WHERE id=%s",
(r.json()["command_id"],),
),
"cancelled",
)
def test_enrichment_versions_and_foreign_targets_preserve_history(self):
a, am = self.miner()
b, bm = self.miner(1, ip="198.51.100.11")
known = self.known()[0]
before = self.durable()
for endpoint in [
"miner-enrichment",
"miner-enrichment-v2",
"miner-enrichment-v3",
]:
for overrides in [
{"miner_id": str(b)},
{"ip_address": "198.51.100.11"},
{"mac_address": bm},
{"miner_version": "invalid"},
]:
body = {**known, "hostname": "attempt", **overrides}
self.assertEqual(
self.post("/api/agent/" + endpoint, body).status_code, 409
)
self.assertEqual(before, self.durable())
result = self.post(
"/api/agent/miner-enrichment-v2",
{**known, "hostname": "allowed", "raw_version": {"read": True}},
)
self.assertEqual(result.status_code, 200, result.text)
self.assertEqual(
self.scalar("SELECT current_mac FROM miners WHERE id=%s", (a,)), am
)
self.assertEqual(
self.scalar("SELECT count(*) FROM miners WHERE id IN (%s,%s)", (a, b)), 2
)
self.assertEqual(
self.post(
"/api/agent/miner-enrichment-v2", {**known, "hostname": "stale"}
).status_code,
409,
)
def test_snapshot_cannot_claim_unassigned_or_foreign_miner(self):
mid, m = self.miner()
known = self.known()[0]
with connect() as c, c.cursor() as q:
q.execute("UPDATE miners SET agent_zone_id=NULL WHERE id=%s", (mid,))
before = self.durable()
self.assertEqual(
self.post(
"/api/agent/miner-snapshots", {"miners": [{**known, "online": True}]}
).status_code,
409,
)
self.assertEqual(self.durable(), before)
def test_positive_poll_pool_and_api3_telemetry(self):
mid, m = self.miner()
known = self.known()[0]
r = self.post(
"/api/agent/miner-snapshots",
{
"miners": [
{
**known,
"online": True,
"responses": {"summary": {"json": {"Msg": {"MHS av": 123}}}},
}
]
},
)
self.assertEqual(r.status_code, 200, r.text)
known = self.known()[0]
r = self.post(
"/api/agent/pool-snapshots",
{"pool_snapshots": [{**known, "pools": [{"URL": "simulated"}]}]},
)
self.assertEqual(r.status_code, 200, r.text)
r = self.post(
"/api/agent/api3-enrichment",
{
"items": [
{
**known,
"ip": known["ip_address"],
"mac": m,
"api3_supported": True,
}
]
},
)
self.assertEqual(r.status_code, 200, r.text)
def test_malformed_unicode_and_outside_network_payloads(self):
for body in [
[],
None,
{"discoveries": {}},
{"discoveries": [{"ip_address": "203.0.113.1"}]},
{"discoveries": [{"ip_address": "198.51.100.1\u200b"}]},
{
"discoveries": [
{
"ip_address": "198.51.100.1",
"mac_address": "02:12:34:00:00:11\u0000",
}
]
},
]:
before = self.durable()
r = self.post("/api/agent/discoveries", body)
self.assertIn(r.status_code, [409, 422], r.text)
self.assertEqual(before, self.durable())
def test_concurrent_disable_waits_for_mutation_authority_lock(self):
row = self.observe()
entered = threading.Event()
release = threading.Event()
original = self.repo.audit
def audit(cur, *args, **kwargs):
if args[0] == "discovery.reviewed":
entered.set()
self.assertTrue(release.wait(5))
return original(cur, *args, **kwargs)
self.repo.audit = audit
def work():
return self.repo.review(
{
"discovery_id": row["id"],
"version": row["version"],
"action": "ignore",
},
{"id": str(self.uid)},
)
with ThreadPoolExecutor(2) as pool:
future = pool.submit(work)
self.assertTrue(entered.wait(5))
def disable():
with connect() as c:
c.execute(
"UPDATE agent_zones SET is_enabled=false,updated_at=now() WHERE id=%s",
(self.zones[0],),
)
blocked = pool.submit(disable)
time.sleep(0.1)
self.assertFalse(blocked.done())
release.set()
future.result()
blocked.result()
self.assertEqual(self.review(row).status_code, 409)
def test_read_target_revalidated_before_simulated_transport(self):
row = self.observe(agent=1)
q = self.client.post(
"/api/agent/discoveries/enrich-match",
headers=self.admin,
json={"discovery_id": row["id"], "version": row["version"]},
).json()
self.client.get("/api/agent/commands/pending", headers=self.headers(1))
body = {
"command_id": q["command_id"],
"discovery_id": row["id"],
"version": row["version"],
}
result = self.post("/api/agent/discovery-target", body, 1)
self.assertEqual(result.status_code, 200, result.text)
self.assertEqual(result.json()["ip_address"], "198.51.100.10")
self.assertEqual(
self.post("/api/agent/discovery-target", body, 0).status_code, 409
)
self.review(row, "ignore")
self.assertEqual(
self.post("/api/agent/discovery-target", body, 1).status_code, 409
)
self.transport.assert_not_called()
def test_initial_and_concurrent_self_assignment_is_prohibited(self):
with connect() as c:
c.execute(
"UPDATE minerops_site_agents SET agent_zone_id=NULL WHERE agent_id=%s",
(self.agents[0],),
)
def check():
return self.post(
"/api/agent/checkin",
{
"agent_id": self.agents[0],
"site_id": str(self.sites[0]),
"agent_zone_id": str(self.zones[0]),
},
).status_code
with ThreadPoolExecutor(2) as pool:
self.assertEqual(list(pool.map(lambda _: check(), range(2))), [422, 422])
self.assertIsNone(
self.scalar(
"SELECT agent_zone_id FROM minerops_site_agents WHERE agent_id=%s",
(self.agents[0],),
)
)
def test_pool_and_api3_foreign_or_nested_contradictions_rollback(self):
a, am = self.miner()
b, bm = self.miner(1, ip="198.51.100.11")
known = self.known()[0]
before = self.durable()
self.assertEqual(
self.post(
"/api/agent/pool-snapshots",
{"pool_snapshots": [{**known, "miner_id": str(b), "pools": [{}]}]},
).status_code,
409,
)
for extra in [{"agent_id": self.agents[1]}, {}]:
body = {
**extra,
"items": [
{
**known,
"ip": known["ip_address"],
"mac": am,
"api3_supported": True,
"device_info": {"msg": {"network": {"ip": "198.51.100.11"}}},
}
],
}
self.assertIn(
self.post("/api/agent/api3-enrichment", body).status_code, [403, 409]
)
self.assertEqual(before, self.durable())
def test_actual_observation_update_failure_rolls_back_insert_and_audit(self):
row = self.observe()
name = "b1_failure_" + uuid4().hex
with connect() as c:
c.execute(
"CREATE FUNCTION "
+ name
+ "() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF NEW.id='"
+ row["id"]
+ "' THEN RAISE EXCEPTION 'injected observation update'; END IF; RETURN NEW; END $$"
)
c.execute(
"CREATE TRIGGER "
+ name
+ " BEFORE UPDATE ON minerops_agent_discoveries FOR EACH ROW EXECUTE FUNCTION "
+ name
+ "()"
)
before = self.durable()
try:
with self.assertRaisesRegex(Exception, "injected observation update"):
self.repo.review(
{
"discovery_id": row["id"],
"version": row["version"],
"action": "add_to_inventory",
},
{"id": str(self.uid)},
)
self.assertEqual(before, self.durable())
finally:
with connect() as c:
c.execute("DROP TRIGGER " + name + " ON minerops_agent_discoveries")
c.execute("DROP FUNCTION " + name + "()")
def test_age_expiry_and_legacy_records_cannot_be_approved(self):
row = self.observe()
with connect() as c:
c.execute(
"UPDATE minerops_agent_discoveries SET created_at=now()-interval '1 hour' WHERE id=%s",
(row["id"],),
)
before = self.durable()
self.assertEqual(self.review(row).status_code, 409)
self.assertEqual(before, self.durable())
oid = str(uuid4())
with connect() as c:
c.execute(
"INSERT INTO minerops_agent_discoveries(id,agent_id,agent_zone_id,site_name,ip_address,raw_payload) VALUES (%s,%s,%s,'Legacy','198.51.100.12',%s) RETURNING updated_at",
(
oid,
self.agents[0],
self.zones[0],
Jsonb({"authority": "client-spoof"}),
),
)
with connect() as c, c.cursor() as q:
q.execute(
"SELECT updated_at FROM minerops_agent_discoveries WHERE id=%s", (oid,)
)
version = q.fetchone()[0].isoformat()
self.assertEqual(self.review({"id": oid, "version": version}).status_code, 409)
def test_historical_decision_and_raw_payload_not_overwritten_by_new_report(self):
row = self.observe()
self.review(row, "ignore")
old = self.scalar(
"SELECT to_jsonb(d) FROM minerops_agent_discoveries d WHERE id=%s",
(row["id"],),
)
self.observe(hostname="new report")
self.assertEqual(
old,
self.scalar(
"SELECT to_jsonb(d) FROM minerops_agent_discoveries d WHERE id=%s",
(row["id"],),
),
)
def test_changed_ownership_and_credential_revocation_invalidate_tokens(self):
mid, m = self.miner()
known = self.known()[0]
with connect() as c:
c.execute(
"UPDATE miners SET site_id=%s,agent_zone_id=%s,updated_at=now() WHERE id=%s",
(self.sites[1], self.zones[1], mid),
)
before = self.durable()
self.assertEqual(
self.post(
"/api/agent/miner-enrichment-v3", {**known, "model": "stale"}
).status_code,
409,
)
self.assertEqual(before, self.durable())
with connect() as c:
c.execute(
"UPDATE minerops_site_agents SET credential_revoked_at=now() WHERE agent_id=%s",
(self.agents[0],),
)
self.assertEqual(
self.post("/api/agent/discoveries", {"discoveries": []}).status_code, 403
)
def test_batch_bounds_stream_limit_stale_report_and_ipv6(self):
cases = [
{"discoveries": [{"ip_address": "198.51.100.1"}] * 129},
{
"discoveries": [
{
"ip_address": "198.51.100.1",
"discovered_at": "2000-01-01T00:00:00Z",
}
]
},
{"discoveries": [{"ip_address": "fe80::1%eth0"}]},
]
for body in cases:
self.assertIn(
self.post("/api/agent/discoveries", body).status_code, [409, 422]
)
response = self.client.post(
"/api/agent/discoveries",
headers=self.headers(),
content="x" * (1024 * 1024 + 1),
)
self.assertEqual(response.status_code, 413)
with connect() as c:
c.execute(
"INSERT INTO agent_zone_network_ranges(agent_zone_id,network) VALUES (%s,'2001:db8::/64')",
(self.zones[0],),
)
self.assertEqual(
self.observe(ip="2001:db8::12", mac=None)["ip_address"], "2001:db8::12"
)
def test_positive_telemetry_preserves_numeric_measurements(self):
mid, m = self.miner()
known = self.known()[0]
r = self.post(
"/api/agent/miner-snapshots",
{
"miners": [
{
**known,
"online": True,
"responses": {
"summary": {
"raw": json.dumps(
{
"Msg": {
"MHS av": 123,
"Power": 456,
"Fan Speed In": 789,
}
}
)
}
},
}
]
},
)
self.assertEqual(r.status_code, 200, r.text)
self.assertEqual(
self.scalar(
"SELECT mhs_av FROM miner_status_snapshots WHERE miner_id=%s ORDER BY observed_at DESC LIMIT 1",
(mid,),
),
123,
)
known = self.known()[0]
r = self.post(
"/api/agent/api3-enrichment",
{
"items": [
{
**known,
"ip": known["ip_address"],
"mac": m,
"api3_supported": True,
"miner_status": {
"msg": {
"summary": {"hash-average": 12},
"pools": [
{"id": 0, "url": "stratum+tcp://simulated.invalid"}
],
"edevs": [{"slot": 0, "hash-average": 12}],
}
},
}
]
},
)
self.assertEqual(r.status_code, 200, r.text)
self.assertEqual(
self.scalar(
"SELECT count(*) FROM miner_api3_hashboard_snapshots WHERE miner_id=%s",
(mid,),
),
1,
)
self.assertEqual(
self.scalar(
"SELECT count(*) FROM miner_pool_snapshots WHERE miner_id=%s", (mid,)
),
1,
)
def test_metadata_and_failed_api3_preserve_latest_measurements(self):
mid, m = self.miner()
room = uuid4()
with connect() as c, c.cursor() as q:
q.execute(
"INSERT INTO rooms(id,site_id,name) VALUES (%s,%s,'Observed room')",
(room, self.sites[0]),
)
q.execute(
"UPDATE miners SET room_id=%s,miner_sn='established-serial' WHERE id=%s",
(room, mid),
)
q.execute(
"INSERT INTO miner_status_snapshots(miner_id,mhs_av) VALUES (%s,123)",
(mid,),
)
known = self.known()[0]
self.assertEqual(known["room_name"], "Observed room")
response = self.post(
"/api/agent/miner-enrichment-v3",
{**known, "hostname": "read-metadata", "raw_version": {"read": True}},
)
self.assertEqual(response.status_code, 200, response.text)
self.assertEqual(
self.scalar(
"SELECT new_value_json->'raw_version' FROM audit_logs WHERE action='discovery.miner_enriched' AND entity_id=%s ORDER BY created_at DESC LIMIT 1",
(str(mid),),
),
{"read": True},
)
known = self.known()[0]
failed = {
**known,
"ip": known["ip_address"],
"mac": m,
"api3_supported": False,
"api3_error": "simulated timeout",
}
response = self.post("/api/agent/api3-enrichment", {"items": [failed]})
self.assertEqual(response.status_code, 200, response.text)
self.assertEqual(response.json()["data"]["api3_failed"], 1)
self.assertEqual(response.json()["data"]["status_rows"], 0)
known = self.known()[0]
metadata = {
**failed,
**known,
"api3_supported": True,
"device_info": {
"msg": {
"miner": {
"type": "simulated-model",
"miner-sn": "established-serial",
},
"system": {
"api": "simulated-api",
"fwversion": "simulated-firmware",
"platform": "simulated-platform",
"apiswitch": "on",
},
}
},
}
response = self.post("/api/agent/api3-enrichment", {"items": [metadata]})
self.assertEqual(response.status_code, 200, response.text)
self.assertEqual(response.json()["data"]["api3_ok"], 1)
self.assertEqual(
self.scalar("SELECT api_version FROM miners WHERE id=%s", (mid,)),
"simulated-api",
)
self.assertEqual(
self.scalar(
"SELECT count(*) FROM miner_status_snapshots WHERE miner_id=%s", (mid,)
),
1,
)
self.assertEqual(
self.scalar(
"SELECT mhs_av FROM miner_status_snapshots WHERE miner_id=%s", (mid,)
),
123,
)
known = self.known()[0]
metadata.update(known)
metadata["device_info"]["msg"]["miner"]["miner-sn"] = "other-device"
before = self.durable()
self.assertEqual(
self.post("/api/agent/api3-enrichment", {"items": [metadata]}).status_code,
409,
)
self.assertEqual(before, self.durable())
def test_conflicting_aliases_and_serial_cannot_poison_matches(self):
mid, m = self.miner()
known = self.known()[0]
before = self.durable()
for body in [
{**known, "ip": "198.51.100.11"},
{**known, "mac": "02:99:99:99:99:99"},
]:
self.assertEqual(
self.post("/api/agent/miner-enrichment-v3", body).status_code, 409
)
self.assertEqual(before, self.durable())
other, mac = self.miner(1, ip="198.51.100.20")
with connect() as c:
c.execute("UPDATE miners SET miner_sn=%s WHERE id=%s", (str(other), other))
row = self.observe(ip="198.51.100.22", miner_sn=str(other))
self.assertEqual(row["discovery_status"], "zone_conflict")
self.assertEqual(self.review(row).status_code, 409)
for evidence in [
{"ip": "198.51.100.23"},
{"mac": "02:99:99:99:99:99"},
{"miner_id": str(other)},
]:
result = self.post(
"/api/agent/discoveries",
{
"discoveries": [
{
"ip_address": "198.51.100.24",
"mac_address": "02:12:34:00:00:24",
**evidence,
}
]
},
)
self.assertEqual(result.status_code, 200, result.text)
row = result.json()["discoveries"][0]
self.assertEqual(row["discovery_status"], "zone_conflict")
self.assertIsNone(row["matched_miner_id"])
self.assertEqual(self.review(row).status_code, 409)
def test_requeued_claimed_read_preserves_unknown_outcome_and_single_audit(self):
row = self.observe()
result = self.client.post(
"/api/agent/discoveries/enrich-match",
headers=self.admin,
json={"discovery_id": row["id"], "version": row["version"]},
)
qid = result.json()["command_id"]
self.client.get("/api/agent/commands/pending", headers=self.headers())
with connect() as c:
c.execute(
"UPDATE minerops_agent_command_queue SET command_status='pending' WHERE id=%s",
(qid,),
)
self.review(row, "ignore")
for _ in range(2):
self.assertEqual(
self.client.get(
"/api/agent/commands/pending", headers=self.headers()
).json()["commands"],
[],
)
self.assertEqual(
self.scalar(
"SELECT new_value_json->>'execution_outcome' FROM audit_logs WHERE action='discovery.command_rejected' AND new_value_json->>'command_id'=%s",
(qid,),
),
"unknown",
)
self.assertEqual(
self.scalar(
"SELECT count(*) FROM audit_logs WHERE action='discovery.command_rejected' AND new_value_json->>'command_id'=%s",
(qid,),
),
1,
)
def test_read_requests_can_repeat_and_explicit_request_ids_are_idempotent(self):
ids = []
for _ in range(2):
response = self.client.post(
"/api/agent/commands/run-poll-now",
headers=self.admin,
json={"agent_id": self.agents[0]},
)
self.assertEqual(response.status_code, 200, response.text)
ids.append(response.json()["command_id"])
self.assertNotEqual(*ids)
request_id = str(uuid4())
responses = [
self.client.post(
"/api/agent/commands/scan-new-miners",
headers=self.admin,
json={"agent_id": self.agents[0], "request_id": request_id},
).json()
for _ in range(2)
]
self.assertEqual(responses[0], responses[1])
def test_unaudited_legacy_observation_rewrite_is_rejected(self):
row = self.observe()
with connect() as connection:
connection.execute(
"UPDATE minerops_agent_discoveries SET updated_at=clock_timestamp(),discovery_status='known' WHERE id=%s",
(row["id"],),
)
row["version"] = self.scalar(
"SELECT updated_at FROM minerops_agent_discoveries WHERE id=%s",
(row["id"],),
).isoformat()
before = self.durable()
self.assertEqual(self.review(row).status_code, 409)
self.assertEqual(before, self.durable())
def test_two_zones_concurrently_approve_one_mac_with_one_winner(self):
a = self.observe()
b = self.observe(agent=1)
barrier = threading.Barrier(2)
def approve(row):
barrier.wait(5)
client = TestClient(app)
try:
return client.post(
"/api/agent/discoveries/review",
headers=self.admin,
json={
"discovery_id": row["id"],
"version": row["version"],
"action": "add_to_inventory",
},
).status_code
finally:
client.close()
with ThreadPoolExecutor(2) as pool:
results = list(pool.map(approve, [a, b]))
self.assertEqual(sorted(results), [200, 409])
self.assertEqual(
self.scalar(
"SELECT count(*) FROM miners WHERE agent_zone_id IN (%s,%s)",
tuple(self.zones),
),
1,
)
def test_claim_then_concurrent_review_blocks_and_target_is_revalidated(self):
row = self.observe()
qid = self.client.post(
"/api/agent/discoveries/enrich-match",
headers=self.admin,
json={"discovery_id": row["id"], "version": row["version"]},
).json()["command_id"]
entered = threading.Event()
release = threading.Event()
original = DiscoveryRepository.validate_command
def gated(repository, cur, agent, command):
if command.get("id", command.get("command_id")) == qid:
entered.set()
if not release.wait(5):
raise AssertionError("Claim gate timed out")
return original(repository, cur, agent, command)
with patch.object(
DiscoveryRepository, "validate_command", gated
), ThreadPoolExecutor(2) as pool:
claim = pool.submit(
lambda: self.client.get(
"/api/agent/commands/pending", headers=self.headers()
)
)
self.assertTrue(entered.wait(5))
review = pool.submit(lambda: self.review(row, "ignore"))
deadline = time.monotonic() + 3
waiting = 0
while time.monotonic() < deadline:
waiting = self.scalar(
"SELECT count(*) FROM pg_stat_activity WHERE datname=current_database() AND wait_event='advisory'"
)
if waiting:
break
time.sleep(0.02)
self.assertGreater(
waiting, 0, "Review did not reach a real PostgreSQL lock wait"
)
release.set()
self.assertEqual(claim.result().status_code, 200)
self.assertEqual(review.result().status_code, 200)
result = self.post(
"/api/agent/discovery-target",
{"command_id": qid, "discovery_id": row["id"], "version": row["version"]},
)
self.assertEqual(result.status_code, 409)
self.transport.assert_not_called()
if __name__ == "__main__":
unittest.main()