185 lines
6.1 KiB
Python
185 lines
6.1 KiB
Python
from __future__ import annotations
|
|
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock
|
|
|
|
import pytest
|
|
|
|
from src.services.host_ansible_controlled_executor import (
|
|
queue_host_ansible_controlled_action,
|
|
)
|
|
|
|
|
|
def _ollama111_incident() -> SimpleNamespace:
|
|
return SimpleNamespace(
|
|
incident_id="INC-OLLAMA111-001",
|
|
project_id="awoooi",
|
|
alertname="Ollama111Unavailable",
|
|
alert_category="ai_provider",
|
|
severity=SimpleNamespace(value="P2"),
|
|
affected_services=["ollama-local"],
|
|
signals=[
|
|
SimpleNamespace(
|
|
alert_name="Ollama111Unavailable",
|
|
labels={
|
|
"alertname": "Ollama111Unavailable",
|
|
"host": "111",
|
|
"instance": "192.168.0.111",
|
|
"service": "ollama-local",
|
|
},
|
|
annotations={},
|
|
)
|
|
],
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_host_action_queues_exact_typed_ansible_candidate() -> None:
|
|
enqueuer = AsyncMock(
|
|
return_value={
|
|
"schema_version": "ai_decision_controlled_executor_handoff_v1",
|
|
"status": "controlled_check_mode_queued",
|
|
"queued": True,
|
|
"side_effect_performed": False,
|
|
"single_writer_executor": "awoooi-ansible-executor-broker",
|
|
"automation_run_id": "run-ollama111",
|
|
"trace_id": "trace-ollama111",
|
|
"work_item_id": "AIA-SRE-008",
|
|
"active_blockers": [],
|
|
}
|
|
)
|
|
|
|
receipt = await queue_host_ansible_controlled_action(
|
|
incident=_ollama111_incident(),
|
|
requested_action="reconcile host service ollama-local",
|
|
risk_level="low",
|
|
source="test_host_systemd",
|
|
requested_host="host_111",
|
|
enqueuer=enqueuer,
|
|
)
|
|
|
|
assert receipt["queued"] is True
|
|
assert receipt["runtime_write_performed"] is False
|
|
assert receipt["repair_executed"] is False
|
|
assert receipt["repair_verified"] is False
|
|
assert receipt["incident_closure_allowed"] is False
|
|
assert receipt["typed_route"]["target_kind"] == "host_launchagent"
|
|
assert receipt["typed_route"]["executor"] == "host_ansible_executor"
|
|
assert receipt["typed_route"]["verifier"] == (
|
|
"ollama111_k3s_path_independent_verifier"
|
|
)
|
|
assert receipt["typed_route"]["allowed_catalog_ids"] == [
|
|
"ansible:111-ollama-fallback"
|
|
]
|
|
enqueuer.assert_awaited_once()
|
|
proposal = enqueuer.await_args.kwargs["proposal_data"]
|
|
assert proposal["risk_level"] == "medium"
|
|
assert proposal["cross_domain_fallback_allowed"] is False
|
|
assert proposal["check_mode_required_before_apply"] is True
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_host_action_blocks_requested_host_mismatch_without_queue() -> None:
|
|
enqueuer = AsyncMock()
|
|
|
|
receipt = await queue_host_ansible_controlled_action(
|
|
incident=_ollama111_incident(),
|
|
requested_action="reconcile host service ollama-local",
|
|
risk_level="medium",
|
|
source="test_host_systemd",
|
|
requested_host="192.168.0.110",
|
|
enqueuer=enqueuer,
|
|
)
|
|
|
|
assert receipt["queued"] is False
|
|
assert receipt["status"] == "requested_host_typed_route_mismatch"
|
|
assert receipt["runtime_write_performed"] is False
|
|
enqueuer.assert_not_awaited()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize(
|
|
"malformed_receipt",
|
|
[
|
|
{"queued": True},
|
|
{
|
|
"schema_version": "ai_decision_controlled_executor_handoff_v1",
|
|
"status": "controlled_executor_queue_failed",
|
|
"queued": True,
|
|
"side_effect_performed": False,
|
|
"single_writer_executor": "awoooi-ansible-executor-broker",
|
|
"automation_run_id": "run-1",
|
|
"trace_id": "trace-1",
|
|
"work_item_id": "AIA-SRE-008",
|
|
"active_blockers": [],
|
|
},
|
|
{
|
|
"schema_version": "ai_decision_controlled_executor_handoff_v1",
|
|
"status": "controlled_check_mode_queued",
|
|
"queued": True,
|
|
"side_effect_performed": True,
|
|
"single_writer_executor": "awoooi-ansible-executor-broker",
|
|
"automation_run_id": "run-1",
|
|
"trace_id": "trace-1",
|
|
"work_item_id": "AIA-SRE-008",
|
|
"active_blockers": [],
|
|
},
|
|
],
|
|
)
|
|
async def test_malformed_broker_receipt_fails_closed(
|
|
malformed_receipt: dict,
|
|
) -> None:
|
|
receipt = await queue_host_ansible_controlled_action(
|
|
incident=_ollama111_incident(),
|
|
requested_action="reconcile host service ollama-local",
|
|
risk_level="medium",
|
|
source="test_host_systemd",
|
|
requested_host="192.168.0.111",
|
|
enqueuer=AsyncMock(return_value=malformed_receipt),
|
|
)
|
|
|
|
assert receipt["queued"] is False
|
|
assert receipt["status"] == "controlled_executor_receipt_invalid"
|
|
assert receipt["runtime_write_performed"] is False
|
|
assert receipt["incident_closure_allowed"] is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_unknown_host_asset_fails_closed_without_fallback() -> None:
|
|
enqueuer = AsyncMock()
|
|
incident = SimpleNamespace(
|
|
incident_id="INC-UNKNOWN-HOST",
|
|
project_id="awoooi",
|
|
alertname="HostServiceDown",
|
|
alert_category="host_resource",
|
|
severity=SimpleNamespace(value="P2"),
|
|
affected_services=["mystery-daemon"],
|
|
signals=[
|
|
SimpleNamespace(
|
|
alert_name="HostServiceDown",
|
|
labels={
|
|
"alertname": "HostServiceDown",
|
|
"instance": "192.168.0.199",
|
|
"service": "mystery-daemon",
|
|
},
|
|
annotations={},
|
|
)
|
|
],
|
|
)
|
|
|
|
receipt = await queue_host_ansible_controlled_action(
|
|
incident=incident,
|
|
requested_action="reconcile host service mystery-daemon",
|
|
risk_level="medium",
|
|
source="test_host_systemd",
|
|
requested_host="192.168.0.199",
|
|
enqueuer=enqueuer,
|
|
)
|
|
|
|
assert receipt["queued"] is False
|
|
assert receipt["status"] == "asset_identity_unresolved"
|
|
assert receipt["typed_route"]["drift_work_item_id"].startswith(
|
|
"AIA-ASSET-DRIFT-"
|
|
)
|
|
enqueuer.assert_not_awaited()
|