from __future__ import annotations import os os.environ.setdefault("DATABASE_URL", "postgresql+asyncpg://test:test@localhost/test") from fastapi import FastAPI from fastapi.testclient import TestClient from src.api.v1.iwooos import router from src.services.iwooos_wazuh_incident_response_closure import ( load_latest_iwooos_wazuh_incident_response_closure, validate_iwooos_wazuh_incident_response_closure_packet, ) def _client() -> TestClient: app = FastAPI() app.include_router(router) return TestClient(app) def _alert_receipt() -> dict[str, object]: return { "events": [{"provider_event_id": "alertmanager:received:wazuh-closure"}], "total": 1, "limit": 5, "source_status": "ready", } def _stage_receipts() -> list[dict[str, str]]: return [ {"stage_id": "sensor_source_receipt", "receipt_ref": "ref-sensor"}, {"stage_id": "normalized_asset_identity", "receipt_ref": "ref-asset"}, {"stage_id": "source_truth_diff", "receipt_ref": "ref-diff"}, {"stage_id": "ai_decision_candidate_action", "receipt_ref": "ref-ai"}, {"stage_id": "risk_policy_decision", "receipt_ref": "ref-policy"}, {"stage_id": "check_mode_dry_run_receipt", "receipt_ref": "ref-dry-run"}, {"stage_id": "bounded_execution_receipt", "receipt_ref": "ref-bounded"}, {"stage_id": "independent_post_verifier", "receipt_ref": "ref-post"}, { "stage_id": "km_rag_mcp_playbook_write_ack", "receipt_ref": "ref-km-rag-mcp-playbook", }, ] def _valid_packet() -> dict[str, object]: return { "trace_id": "iwooos-wazuh-p0-03-trace-001", "run_id": "iwooos-wazuh-p0-03-run-001", "work_item_id": "P0-03-WAZUH-INCIDENT-001", "asset_scope_aliases": ["managed_core_node_a", "managed_core_node_b"], "wazuh_event_receipt_ref": "ref-wazuh-event", "forensics_evidence_ref": "ref-forensics", "incident_case_ref": "ref-incident-case", "ai_decision_ref": "ref-ai-decision", "candidate_controlled_response_ref": "ref-controlled-response-candidate", "source_truth_diff_ref": "ref-source-truth-diff", "risk_policy_decision_ref": "ref-risk-policy", "check_mode_dry_run_ref": "ref-check-mode-dry-run", "bounded_execution_receipt_ref": "ref-bounded-execution", "rollback_plan_ref": "ref-rollback-plan", "post_verifier_ref": "ref-independent-post-verifier", "km_rag_mcp_playbook_writeback_ref": "ref-km-rag-mcp-playbook", "same_run_stage_receipts": _stage_receipts(), "runtime_boundary_ack": ( "runtime_gate_remains_closed_until_executor_post_verifier" ), "host_write_boundary_ack": "no_host_write_performed_by_validator", "secret_boundary_ack": "no_secret_value_collected_or_submitted", "live_wazuh_query_boundary_ack": ( "no_live_wazuh_query_performed_by_validator" ), } def test_wazuh_incident_response_closure_readback_exposes_same_run_contract() -> None: payload = load_latest_iwooos_wazuh_incident_response_closure( alert_receipt_readback=_alert_receipt() ) assert ( payload["schema_version"] == "iwooos_wazuh_incident_response_closure_readback_v1" ) assert ( payload["status"] == "wazuh_incident_response_same_run_candidate_missing_receipts" ) assert payload["summary"]["closure_packet_validator_available_count"] == 1 assert payload["summary"]["source_verifier_ready_count"] == 1 assert payload["summary"]["controlled_apply_preflight_ready_count"] == 1 assert payload["summary"]["allowlisted_dry_run_ready_count"] == 1 assert payload["summary"]["same_run_required_stage_count"] == 9 assert payload["summary"]["wazuh_event_accepted_count"] == 0 assert payload["summary"]["forensic_evidence_accepted_count"] == 0 assert payload["summary"]["incident_case_accepted_count"] == 0 assert payload["summary"]["same_run_source_stage_ready_count"] == 5 assert payload["summary"]["same_run_closure_candidate_ready_count"] == 0 assert payload["summary"]["same_run_closure_candidate_missing_count"] == 1 assert payload["summary"]["wazuh_incident_response_runtime_closed_count"] == 0 assert payload["summary"]["wazuh_active_response_authorized_count"] == 0 assert payload["boundaries"]["runtime_execution_authorized"] is False assert payload["boundaries"]["wazuh_active_response_authorized"] is False assert payload["boundaries"]["secret_value_collection_allowed"] is False def test_wazuh_incident_response_closure_packet_accepts_redacted_same_run_receipts() -> None: payload = validate_iwooos_wazuh_incident_response_closure_packet( _valid_packet(), alert_receipt_readback=_alert_receipt(), ) assert ( payload["schema_version"] == "iwooos_wazuh_incident_response_closure_validation_result_v1" ) assert ( payload["status"] == "accepted_for_wazuh_incident_response_closure_review_only" ) assert payload["accepted_for_incident_response_closure_review_only"] is True assert payload["summary"]["incident_response_packet_review_ready_count"] == 1 assert payload["summary"]["same_run_packet_stage_ready_count"] == 9 assert payload["summary"]["wazuh_incident_response_runtime_closed_count"] == 0 assert payload["summary"]["runtime_gate_count"] == 0 assert payload["boundaries"]["payload_persisted"] is False assert payload["boundaries"]["runtime_execution_authorized"] is False def test_wazuh_incident_response_closure_packet_requests_missing_stage_receipts() -> None: packet = _valid_packet() packet["same_run_stage_receipts"] = _stage_receipts()[:-1] payload = validate_iwooos_wazuh_incident_response_closure_packet( packet, alert_receipt_readback=_alert_receipt(), ) assert payload["status"] == "request_same_run_stage_receipts_fix" assert payload["summary"]["incident_response_packet_supplement_required_count"] == 1 assert any( finding["check_id"] == "WIRC-06" and "km_rag_mcp_playbook_write_ack" in finding["metadata"]["missing_stage_ids"] for finding in payload["validation_findings"] ) def test_wazuh_incident_response_closure_packet_quarantines_sensitive_payload() -> None: packet = _valid_packet() packet["wazuh_event_receipt_ref"] = "ref accidentally included 10.10.10.10" payload = validate_iwooos_wazuh_incident_response_closure_packet( packet, alert_receipt_readback=_alert_receipt(), ) assert payload["status"] == "quarantine_sensitive_payload" assert payload["quarantined"] is True assert payload["summary"]["incident_response_packet_quarantined_count"] == 1 assert "10.10.10.10" not in str(payload) def test_wazuh_incident_response_closure_packet_rejects_runtime_action() -> None: packet = _valid_packet() packet["requested_actions"] = ["wazuh_active_response"] payload = validate_iwooos_wazuh_incident_response_closure_packet( packet, alert_receipt_readback=_alert_receipt(), ) assert payload["status"] == "reject_runtime_action_request" assert payload["runtime_action_rejected"] is True assert payload["summary"]["incident_response_packet_runtime_action_rejected_count"] == 1 assert payload["summary"]["wazuh_active_response_authorized_count"] == 0 def test_wazuh_incident_response_closure_api_is_public_safe(monkeypatch) -> None: async def fake_recent_events(**_: object) -> dict[str, object]: return _alert_receipt() monkeypatch.setattr( "src.api.v1.iwooos.list_recent_channel_events", fake_recent_events, ) client = _client() readback = client.get("/api/v1/iwooos/wazuh-incident-response-closure-readback") validation = client.post( "/api/v1/iwooos/wazuh-incident-response-closure/validate-incident-response-packet", json=_valid_packet(), ) assert readback.status_code == 200 assert validation.status_code == 200 assert readback.json()["summary"]["same_run_closure_candidate_ready_count"] == 0 assert readback.json()["summary"]["same_run_closure_candidate_missing_count"] == 1 assert ( validation.json()["status"] == "accepted_for_wazuh_incident_response_closure_review_only" ) assert "192.168.0." not in readback.text assert "192.168.0." not in validation.text assert "WAZUH_API_PASSWORD" not in validation.text assert "批准!繼續" not in validation.text