Files
minerops/backend/tests/test_agent_commands.py
T
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

334 lines
14 KiB
Python

"""Focused tests for authenticated Agent queue transport."""
import unittest
from datetime import datetime, timezone
from pathlib import Path
from fastapi import FastAPI
from fastapi.testclient import TestClient
from app.agent_auth.service import AgentAuthService
from app.agent_commands.dependencies import (
get_agent_auth_service,
get_agent_command_service,
)
from app.agent_commands.exceptions import (
AgentCommandConflict,
AgentResultValidationError,
)
from app.agent_commands.models import AgentCommandResultRequest, MinerControlResultPayload
from app.agent_commands.repository import CLAIM_COMMANDS_SQL
from app.agent_commands.router import router
from app.agent_commands.service import AgentCommandService
from app.config import settings
NOW = datetime(2026, 8, 24, tzinfo=timezone.utc)
def agent_source_root() -> Path | None:
container_root = Path("/agents/windows")
if container_root.is_dir():
return container_root
repository_root = Path(__file__).parents[2] / "agents" / "windows"
return repository_root if repository_root.is_dir() else None
class FakeRepository:
def __init__(self, row=None):
self.row = row or {
"id": "command-1", "agent_id": "test-agent",
"command_type": "poll_known_miners_now", "command_status": "claimed",
"request_payload": {"action": "suspend"},
}
self.finished = []
def claim_pending(self, agent_id, limit=5):
return [{
"command_id": "command-1", "command_type": "poll_known_miners_now",
"request_payload": {"action": "suspend"}, "created_at": NOW,
}]
def get_command(self, command_id):
return self.row if command_id == self.row.get("id") else None
def finish_command(self, *args):
self.finished.append(args)
if args[2] == "cancelled":
raise AgentCommandConflict(args[4])
def typed_result(**overrides):
result = {
"schema_version": 1,
"command_accepted": True,
"verification_attempted": False,
"verification_status": "unconfirmed",
"observed_service_state": None,
"observed_performance_mode": None,
"failure_code": None,
}
result.update(overrides)
return result
class AgentCommandServiceTests(unittest.TestCase):
def test_claim_query_uses_skip_locked_and_deterministic_order(self):
self.assertIn("FOR UPDATE SKIP LOCKED", CLAIM_COMMANDS_SQL)
self.assertIn("ORDER BY created_at, id", CLAIM_COMMANDS_SQL)
self.assertIn("queue.command_status = 'pending'", CLAIM_COMMANDS_SQL)
def test_typed_result_is_strict_and_sanitized(self):
repository = FakeRepository()
request = AgentCommandResultRequest(
command_id="command-1", status="completed",
result_payload=typed_result(), error_message="raw 192.0.2.10 vendor exception",
)
AgentCommandService(repository).submit_result("test-agent", request)
finished = repository.finished[0]
self.assertIn("[address]", finished[4])
self.assertNotIn("192.0.2.10", str(finished))
def test_wrong_agent_pending_and_terminal_results_are_rejected(self):
request = AgentCommandResultRequest(
command_id="command-1", status="completed", result_payload=typed_result()
)
with self.assertRaises(AgentCommandConflict):
AgentCommandService(FakeRepository()).submit_result("wrong-agent", request)
for queue_status in ("pending", "completed", "failed", "cancelled"):
with self.subTest(status=queue_status), self.assertRaises(AgentCommandConflict):
row = FakeRepository().row.copy()
row["command_status"] = queue_status
AgentCommandService(FakeRepository(row)).submit_result("test-agent", request)
def test_invalid_status_and_secret_fields_are_rejected(self):
with self.assertRaises(Exception):
AgentCommandResultRequest(
command_id="command-1", status="unknown", result_payload={}
)
for forbidden in ("password", "account", "token", "raw_response"):
with self.subTest(field=forbidden):
repository = FakeRepository()
request = AgentCommandResultRequest(
command_id="command-1", status="completed",
result_payload={**typed_result(), forbidden: "sensitive"},
)
with self.assertRaises(ValueError):
MinerControlResultPayload.model_validate(request.result_payload)
def test_suspend_resume_cannot_claim_confirmation(self):
for status in ("confirmed", "verification_failed"):
with self.subTest(status=status):
request = AgentCommandResultRequest(
command_id="command-1", status="completed",
result_payload=typed_result(
verification_attempted=True, verification_status=status
),
)
repository = FakeRepository()
repository.row["command_type"] = "miner_control"
with self.assertRaisesRegex(AgentCommandConflict, "physical_control_disabled_stage_a"):
AgentCommandService(repository).submit_result("test-agent", request)
class FakeAgentAuthRepository:
def get_credential(self, agent_id):
return None
class AgentCommandRouterTests(unittest.TestCase):
def setUp(self):
self.app = FastAPI()
self.app.include_router(router)
self.repository = FakeRepository()
self.app.dependency_overrides[get_agent_command_service] = lambda: AgentCommandService(
self.repository
)
self.app.dependency_overrides[get_agent_auth_service] = lambda: AgentAuthService(
FakeAgentAuthRepository()
)
self.client = TestClient(self.app)
self.old_id = settings.minerops_agent_id
self.old_secret = settings.minerops_agent_shared_secret
settings.minerops_agent_id = "test-agent"
settings.minerops_agent_shared_secret = "test-secret"
def tearDown(self):
settings.minerops_agent_id = self.old_id
settings.minerops_agent_shared_secret = self.old_secret
self.client.close()
def headers(self, agent="test-agent"):
return {
"X-MinerOps-Agent-ID": agent,
"X-MinerOps-Agent-Secret": "test-secret",
}
def test_poll_accepts_secret_only_legacy_agent_and_ignores_query_spoofing(self):
before_claim_calls = []
self.app.state.agent_command_before_claim = lambda: before_claim_calls.append(True)
self.assertEqual(self.client.get("/api/agent/commands/pending").status_code, 401)
self.assertEqual(
self.client.get(
"/api/agent/commands/pending",
headers={"X-MinerOps-Agent-Secret": "test-secret"},
).status_code,
200,
)
self.assertEqual(
self.client.get(
"/api/agent/commands/pending?agent_id=other", headers=self.headers()
).status_code,
200,
)
# Agent polling may claim already queued commands, but must never invoke
# a legacy scheduler/materializer as a side effect.
self.assertEqual(before_claim_calls, [])
self.assertEqual(
self.client.get(
"/api/agent/commands/pending", headers=self.headers("other")
).status_code,
403,
)
def test_result_requires_strict_claimed_contract(self):
response = self.client.post(
"/api/agent/commands/result",
headers=self.headers(),
json={
"command_id": "command-1", "status": "completed",
"result_payload": typed_result(),
},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["status"], "completed")
self.assertEqual(
self.client.post(
"/api/agent/commands/result", headers=self.headers(),
json={"command_id": "command-1", "status": "other",
"result_payload": {}},
).status_code,
422,
)
class AgentSourceContractTests(unittest.TestCase):
def test_agent_typed_path_has_locked_commands_and_no_default_credentials(self):
root = agent_source_root()
if root is None:
self.skipTest("Windows Agent source is not mounted")
service = (root / "MinerOpsAgentService.ps1").read_text()
control = (root / "MinerOpsControl.ps1").read_text()
main = (Path(__file__).parents[1] / "app" / "main.py").read_text()
powershell = "\n".join(path.read_text() for path in root.glob("*.ps1"))
self.assertNotIn('DefaultValue "super"', service)
self.assertNotIn('DefaultValue "super"', powershell)
self.assertIn('"X-MinerOps-Agent-ID"', service)
self.assertIn('.agent_zone_id', service)
self.assertIn('"agent_zone_id"', (root / "config.example.json").read_text())
self.assertNotIn("?agent_id=", service)
self.assertIn("physical_control_disabled_stage_a", control)
self.assertNotIn('"set.miner.', control)
self.assertNotIn("$Payload.performance_mode", control)
self.assertNotIn("api3_account =", control)
self.assertNotIn("api3_password =", control)
for forbidden in ("raw_response", "raw_command", "raw_exception"):
with self.subTest(field=forbidden):
self.assertNotIn(forbidden, control.lower())
self.assertNotIn('"agent_secret": secret', main)
self.assertNotIn('"secret_length":', main)
self.assertIn('"secret_configured": bool(secret)', main)
def test_deployment_preserves_local_state_and_registers_established_tasks(self):
root = agent_source_root()
if root is None:
self.skipTest("Windows Agent source is not mounted")
install = (root / "install.ps1").read_text()
uninstall = (root / "uninstall.ps1").read_text()
for task in (
"MinerOpsAgent", "MinerOpsAgentTray",
"MinerOpsApi3Enrichment", "MinerOpsPoolPoller",
):
self.assertIn(task, install)
self.assertIn(task, uninstall)
for local_path in ("agent-config.json", "agent-state.json", "logs"):
self.assertNotIn(f'"{local_path}"', install)
self.assertNotIn(f'"{local_path}"', uninstall)
self.assertNotIn("agent_secret", install.lower())
self.assertNotIn("api3_password", install.lower())
if __name__ == "__main__":
unittest.main()
class AgentTransportIsolationSourceTests(unittest.TestCase):
def test_known_miners_and_pool_snapshots_are_agent_zone_scoped(self):
from app.main import minerops_agent_known_miners, agent_pool_snapshots
from inspect import getsource
for fn,method in [(minerops_agent_known_miners,"known"),(agent_pool_snapshots,"snapshots")]:
source=getsource(fn)
self.assertIn("Depends(require_agent_identity)",source)
self.assertIn("discovery_dispatch",source)
self.assertIn("agent_id=authenticated_agent_id",source)
def test_windows_machine_pollers_send_agent_identity(self):
root = agent_source_root()
if root is None:
self.skipTest("Windows Agent source is not mounted")
for filename in (
"MinerOpsPoolPoller.ps1",
"MinerOpsApi3EnrichmentPoller.ps1",
"EnrichOneMiner.ps1",
):
with self.subTest(filename=filename):
source = (root / filename).read_text()
self.assertIn("X-MinerOps-Agent-ID", source)
self.assertIn("X-MinerOps-Agent-Secret", source)
class AgentEnrichmentIsolationSourceTests(unittest.TestCase):
def test_enrichment_routes_require_agent_identity_and_zone_scope(self):
from app import main
from inspect import getsource
for fn in [main.minerops_agent_miner_enrichment,main.minerops_agent_miner_enrichment_v2,main.minerops_agent_miner_enrichment_v3]:
source=getsource(fn)
self.assertIn("Depends(require_agent_identity)",source)
self.assertIn("discovery_dispatch",source)
self.assertIn("agent_id=authenticated_agent_id",source)
def test_api3_uses_authenticated_identity_and_never_global_agent_identity(self):
from app.main import minerops_agent_api3_enrichment
from inspect import getsource
source=getsource(minerops_agent_api3_enrichment)
self.assertIn("Depends(require_agent_identity)",source)
self.assertIn("discovery_dispatch",source)
self.assertIn("agent_id=authenticated_agent_id",source)
def test_legacy_config_remains_explicitly_legacy_only(self):
main = (Path(__file__).parents[1] / "app" / "main.py").read_text()
start = main.index('@app.get("/api/agent/config")')
end = main.index("\n@app.", start + 1)
route = main[start:end]
self.assertIn("minerops_require_agent_secret(request)", route)
self.assertIn('"site_name": "Plexus"', route)
self.assertNotIn("Depends(require_agent_identity)", route)
def test_disabled_old_command_routes_are_fixed_retirement_responses(self):
main = (Path(__file__).parents[1] / "app" / "main.py").read_text()
for decorator in (
'@app.get("/api/agent/commands/pending-disabled-old")',
'@app.post("/api/agent/commands/result-disabled-old")',
):
with self.subTest(decorator=decorator):
start = main.index(decorator)
end = main.index("\n@app.", start + 1)
route = main[start:end]
self.assertIn("status_code=410", route)
self.assertNotIn("minerops_require_agent_secret", route)
self.assertNotIn("request.json", route)
self.assertNotIn("minerops_agent_command_queue", route)