fix(agent): bind pre-decision evidence to runtime
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m37s
CD Pipeline / build-and-deploy (push) Successful in 5m1s
CD Pipeline / post-deploy-checks (push) Successful in 3m35s
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m37s
CD Pipeline / build-and-deploy (push) Successful in 5m1s
CD Pipeline / post-deploy-checks (push) Successful in 3m35s
This commit is contained in:
@@ -139,6 +139,38 @@ async def test_audited_provider_strips_internal_audit_context(monkeypatch):
|
||||
assert audit_calls[0]["incident_id"] == "INC-1"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_audited_provider_does_not_duplicate_first_class_gateway_audit(monkeypatch):
|
||||
audit_calls = []
|
||||
|
||||
async def fake_record_mcp_call(**kwargs):
|
||||
audit_calls.append(kwargs)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"src.services.mcp_audit_service.record_mcp_call",
|
||||
fake_record_mcp_call,
|
||||
)
|
||||
|
||||
provider = FakeProvider()
|
||||
audited = AuditedMCPToolProvider(provider)
|
||||
|
||||
result = await audited.execute(
|
||||
"kubectl_get",
|
||||
{
|
||||
"resource": "pods",
|
||||
"_mcp_audit": {
|
||||
"gateway_path": "awooop_mcp_gateway",
|
||||
"agent_role": "pre_decision_investigator",
|
||||
"incident_id": "INC-GW-1",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
assert provider.calls == [("kubectl_get", {"resource": "pods"})]
|
||||
assert audit_calls == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_agent_tool_executor_blocks_disallowed_tool():
|
||||
restart_tool = _tool("kubernetes", "kubectl_restart")
|
||||
|
||||
@@ -57,8 +57,26 @@ async def test_backfill_enqueues_catalog_matched_incident(monkeypatch: pytest.Mo
|
||||
yield fake_db
|
||||
|
||||
recorded: list[dict] = []
|
||||
call_order: list[str] = []
|
||||
|
||||
async def fake_evidence_collector(**kwargs):
|
||||
call_order.append("evidence")
|
||||
assert kwargs["project_id"] == "awoooi"
|
||||
assert kwargs["automation_run_id"]
|
||||
return MagicMock(
|
||||
snapshot_id="evidence-1",
|
||||
incident_id="INC-20260627-NODE110",
|
||||
sensors_succeeded=1,
|
||||
recent_logs="sanitized logs",
|
||||
)
|
||||
|
||||
async def fake_evidence_verifier(**kwargs):
|
||||
call_order.append("verify")
|
||||
assert kwargs["snapshot"].snapshot_id == "evidence-1"
|
||||
return True
|
||||
|
||||
async def fake_recorder(**kwargs):
|
||||
call_order.append("record")
|
||||
recorded.append(kwargs)
|
||||
return True
|
||||
|
||||
@@ -86,6 +104,8 @@ async def test_backfill_enqueues_catalog_matched_incident(monkeypatch: pytest.Mo
|
||||
recorder=fake_recorder,
|
||||
receipt_backfiller=fake_receipt_backfiller,
|
||||
retry_replayer=fake_retry_replayer,
|
||||
evidence_collector=fake_evidence_collector,
|
||||
evidence_verifier=fake_evidence_verifier,
|
||||
)
|
||||
|
||||
assert result["queued"] == 1
|
||||
@@ -95,8 +115,12 @@ async def test_backfill_enqueues_catalog_matched_incident(monkeypatch: pytest.Mo
|
||||
assert result["failed_apply_retry_check_mode_passed"] == 1
|
||||
assert result["failed_apply_retry_check_mode_failed"] == 0
|
||||
assert result["failed_apply_retry_stage_receipt_written"] == 1
|
||||
assert result["pre_decision_evidence_ready"] == 1
|
||||
assert result["pre_decision_evidence_blocked"] == 0
|
||||
assert call_order == ["evidence", "verify", "record"]
|
||||
assert recorded[0]["decision_path"] == "repair_candidate_controlled_queue"
|
||||
assert recorded[0]["incident"]["incident_id"] == "INC-20260627-NODE110"
|
||||
assert recorded[0]["automation_run_id"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -1368,6 +1368,7 @@ def test_ansible_decision_audit_payload_marks_repair_candidate_queue_claimable()
|
||||
)
|
||||
assert payload["input"]["executor_candidates"]
|
||||
assert payload["dry_run_result"]["check_mode_executed"] is False
|
||||
assert payload["input"]["project_id"] == "awoooi"
|
||||
|
||||
|
||||
def test_ansible_decision_audit_payload_exposes_check_mode_safety_flags() -> None:
|
||||
|
||||
@@ -21,6 +21,7 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from src.plugins.mcp.interfaces import MCPTool, MCPToolProvider, MCPToolResult
|
||||
@@ -33,12 +34,11 @@ from src.services.mcp_tool_registry import (
|
||||
)
|
||||
from src.services.pre_decision_investigator import (
|
||||
PreDecisionInvestigator,
|
||||
_build_tool_params,
|
||||
_compute_fingerprint,
|
||||
_fill_snapshot_dimension,
|
||||
_build_tool_params,
|
||||
)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Stubs
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -207,6 +207,12 @@ class TestComputeFingerprint:
|
||||
i2 = _stub_incident("Host", "prod", "pod1", "critical")
|
||||
assert _compute_fingerprint(i1) != _compute_fingerprint(i2)
|
||||
|
||||
def test_automation_run_id_prevents_cross_run_cache_reuse(self):
|
||||
incident = _stub_incident("HostErrorLogFlood", "infra", "", "warning")
|
||||
fp1 = _compute_fingerprint(incident, automation_run_id="run-1")
|
||||
fp2 = _compute_fingerprint(incident, automation_run_id="run-2")
|
||||
assert fp1 != fp2
|
||||
|
||||
def test_fingerprint_length_16(self):
|
||||
i = _stub_incident()
|
||||
fp = _compute_fingerprint(i)
|
||||
|
||||
Reference in New Issue
Block a user