From f682baf0d00ecffffd74f82ed1f7a3a18ad7ead2 Mon Sep 17 00:00:00 2001 From: ogt Date: Fri, 17 Jul 2026 12:30:24 +0800 Subject: [PATCH] fix(iwooos): close Wazuh critical execution gate --- .../awooop_ansible_candidate_backfill_job.py | 29 ++++- .../awooop_ansible_check_mode_service.py | 107 ++++++++++++++---- ...wooos_wazuh_controlled_executor_runtime.py | 77 +++++++++---- ...wooos_wazuh_controlled_executor_runtime.py | 86 ++++++++++++-- .../test_wazuh_alertmanager_integration.py | 38 ++++++- apps/web/messages/en.json | 5 +- apps/web/messages/zh-TW.json | 5 +- apps/web/src/app/[locale]/iwooos/page.tsx | 19 +++- apps/web/src/lib/api-client.ts | 12 +- 9 files changed, 300 insertions(+), 78 deletions(-) diff --git a/apps/api/src/jobs/awooop_ansible_candidate_backfill_job.py b/apps/api/src/jobs/awooop_ansible_candidate_backfill_job.py index 96579996d..3b9bbc302 100644 --- a/apps/api/src/jobs/awooop_ansible_candidate_backfill_job.py +++ b/apps/api/src/jobs/awooop_ansible_candidate_backfill_job.py @@ -69,6 +69,9 @@ _WAZUH_INGRESS_WORK_ITEM_ID = "P0-03-WAZUH-ALERT-INGRESS" _WAZUH_CONTROLLED_CAPABILITY_PACKET_OPERATION_TYPE = ( "ansible_controlled_capability_repair_queued" ) +_WAZUH_PRIVILEGED_CONVERGENCE_SECRET_REFERENCE_MISSING = ( + "wazuh_privileged_convergence_secret_reference_missing" +) _EXECUTION_CAPABILITY_FALLBACK_OPERATION_TYPE = "remediation_executed" _WAZUH_SOURCE_RECURRENCE_DRIFT_WORK_ITEM_ID = ( "DRIFT-WAZUH-SOURCE-RECURRENCE" @@ -1175,6 +1178,8 @@ async def enqueue_iwooos_wazuh_manager_posture_candidate_once( AS latest_controlled_capability_packet_status, capability_packet.output ->> 'queue_status' AS latest_controlled_capability_queue_status, + capability_packet.output ->> 'failure_class' + AS latest_controlled_capability_failure_class, capability_packet.input #>> '{gate_lifecycle,expires_at}' AS latest_controlled_capability_packet_expires_at, @@ -1296,13 +1301,25 @@ async def enqueue_iwooos_wazuh_manager_posture_candidate_once( existing_row, observed_now=observed_now, ) + capability_failure_class = str( + existing_row.get("latest_controlled_capability_failure_class") + or "" + ) if existing_row else "" + critical_secret_reference_pending = bool( + capability_failure_class + == _WAZUH_PRIVILEGED_CONVERGENCE_SECRET_REFERENCE_MISSING + ) if ( _catalog_id == _WAZUH_INGRESS_CATALOG_ID and retry_reason == "check_mode_failed" and capability_packet_pending ): return { - "status": "controlled_privilege_capability_repair_already_queued", + "status": ( + "critical_secret_reference_break_glass_already_queued" + if critical_secret_reference_pending + else "controlled_privilege_capability_repair_already_queued" + ), "queued": 0, "existing": 1, "evidence_ready": 1 if existing_evidence_ready else 0, @@ -1312,11 +1329,17 @@ async def enqueue_iwooos_wazuh_manager_posture_candidate_once( or "" ), "work_item_id": _work_item_id, - "controlled_apply_allowed": True, + "controlled_apply_allowed": ( + not critical_secret_reference_pending + ), "retry_reason": retry_reason, "retry_of_failed_check_mode": True, "active_blockers": [ - "wazuh_controlled_privilege_capability_repair_pending" + ( + "wazuh_critical_secret_reference_provisioning_pending" + if critical_secret_reference_pending + else "wazuh_controlled_privilege_capability_repair_pending" + ) ], } if ( diff --git a/apps/api/src/services/awooop_ansible_check_mode_service.py b/apps/api/src/services/awooop_ansible_check_mode_service.py index baf2fae01..762cf8e2a 100644 --- a/apps/api/src/services/awooop_ansible_check_mode_service.py +++ b/apps/api/src/services/awooop_ansible_check_mode_service.py @@ -100,6 +100,9 @@ _WAZUH_PRIVILEGED_CONVERGENCE_FAILURE_MARKERS = frozenset( _WAZUH_CONTROLLED_CAPABILITY_PACKET_OPERATION_TYPE = ( "ansible_controlled_capability_repair_queued" ) +_WAZUH_CONTROLLED_CAPABILITY_PACKET_SCHEMA_VERSION = ( + "wazuh_controlled_privileged_capability_repair_v3" +) _EXECUTION_CAPABILITY_OPERATION_TYPES = frozenset( { "ansible_executor_capability_issued", @@ -8974,15 +8977,49 @@ def _build_wazuh_controlled_capability_packet( source_recurrence = {} packet_uuid = uuid5( NAMESPACE_URL, - f"awoooi:wazuh-controlled-capability:{automation_run_id}:{check_op_id}", + ( + "awoooi:wazuh-controlled-capability:v3:" + f"{automation_run_id}:{check_op_id}" + ), ) capability_packet_id = f"IWZ-CC-{packet_uuid.hex[:16].upper()}" secret_reference_missing = ( failure_class == _WAZUH_PRIVILEGED_CONVERGENCE_SECRET_REFERENCE_MISSING ) + risk_level = "critical" if secret_reference_missing else "high" + policy_route = ( + "critical_secret_reference_break_glass" + if secret_reference_missing + else "high_risk_controlled_apply_capability_repair" + ) + queue_owner = ( + "ai_critical_secret_reference_controller" + if secret_reference_missing + else "ansible_capability_repair_agent" + ) + controlled_apply_allowed = not secret_reference_missing + required_receipts = ( + [ + "critical_secret_reference_provisioning_receipt", + "windows99_dispatch", + "opaque_secret_projection_presence", + "bounded_same_run_check_mode_retry", + "independent_post_verifier", + "capability_revocation", + ] + if secret_reference_missing + else [ + "windows99_dispatch", + "capability_reference_presence", + "no_secret_privilege_preflight", + "bounded_same_run_check_mode_retry", + "independent_post_verifier", + "capability_revocation", + ] + ) packet_input = { - "schema_version": "wazuh_controlled_privileged_capability_repair_v2", + "schema_version": _WAZUH_CONTROLLED_CAPABILITY_PACKET_SCHEMA_VERSION, "capability_packet_id": capability_packet_id, "automation_run_id": automation_run_id, "trace_id": trace_id, @@ -9005,13 +9042,18 @@ def _build_wazuh_controlled_capability_packet( "catalog_id": str(catalog_id), "semantic_operation_type": _WAZUH_CONTROLLED_CAPABILITY_PACKET_OPERATION_TYPE, "capability_type": "bounded_privileged_convergence", - "risk_level": "high", - "policy_route": "high_risk_controlled_apply_capability_repair", - "queue_owner": "ansible_capability_repair_agent", - "controlled_apply_allowed": True, + "risk_level": risk_level, + "policy_route": policy_route, + "queue_owner": queue_owner, + "controlled_apply_allowed": controlled_apply_allowed, "windows99_dispatch_required": True, "same_run_correlation_required": True, - "execution_allowed": True, + "execution_allowed": False, + "execution_gate_reason": ( + "critical_secret_reference_required" + if secret_reference_missing + else "capability_verifier_pending" + ), "capability_verified": False, "capability_granted": False, "critical_secret_reference_required": secret_reference_missing, @@ -9024,19 +9066,26 @@ def _build_wazuh_controlled_capability_packet( "secret_value_read_back": False, "gate_lifecycle": { "policy_version": "global_product_governance_v2", - "risk_class": "high", + "risk_class": risk_level, "scope": "service:wazuh-manager", - "owner_lane": "ansible_capability_repair_agent", + "owner_lane": queue_owner, "created_at": packet_created_at.isoformat(), "expires_at": ( packet_created_at + timedelta(minutes=30) ).isoformat(), "exit_condition": ( - "windows99_no_secret_privilege_preflight_and_same_run_" + "critical_secret_reference_provisioned_without_exposure_and_" + "same_run_independent_post_verifier_pass" + if secret_reference_missing + else "windows99_no_secret_privilege_preflight_and_same_run_" "independent_post_verifier_pass" ), "replacement_action": ( - "expire_then_reconcile_capability_reference_without_host_write" + "expire_then_reissue_critical_secret_reference_packet_" + "without_execution" + if secret_reference_missing + else "expire_then_reconcile_capability_reference_without_" + "host_write" ), "rollback_ref": "same_run_no_write_terminal_or_capability_revocation", "post_verifier": "wazuh_alert_ingress_controlled_post_verifier", @@ -9045,16 +9094,12 @@ def _build_wazuh_controlled_capability_packet( packet_output = { "queue_status": "queued", "failure_class": failure_class, - "required_receipts": [ - "windows99_dispatch", - "capability_reference_presence", - "no_secret_privilege_preflight", - "bounded_same_run_check_mode_retry", - "independent_post_verifier", - "capability_revocation", - ], + "required_receipts": required_receipts, "next_controlled_action": ( - "windows99_verify_controlled_privilege_capability_then_" + "provision_opaque_secret_reference_via_break_glass_then_" + "windows99_verify_and_requeue_same_run_check_mode" + if secret_reference_missing + else "windows99_verify_controlled_privilege_capability_then_" "requeue_same_run_check_mode" ), "telegram_notification_emitted": False, @@ -9120,7 +9165,17 @@ async def _insert_wazuh_controlled_capability_packet( CAST(:dry_run_result AS jsonb), CAST(:parent_op_id AS uuid), ARRAY[ - 'ansible', 'wazuh', 'controlled_apply', 'high_risk', + 'ansible', 'wazuh', + CASE + WHEN :critical_secret_reference_required + THEN 'break_glass' + ELSE 'controlled_apply' + END, + CASE + WHEN :critical_secret_reference_required + THEN 'critical_risk' + ELSE 'high_risk' + END, 'capability_repair', 'windows99_dispatch', 'no_host_write', 'no_secret' ]::varchar[] @@ -9154,6 +9209,9 @@ async def _insert_wazuh_controlled_capability_packet( ), "parent_op_id": check_op_id, "capability_packet_id": packet_input["capability_packet_id"], + "critical_secret_reference_required": bool( + packet_input["critical_secret_reference_required"] + ), }, ) return inserted.scalar_one_or_none() is not None @@ -9239,7 +9297,7 @@ async def backfill_missing_wazuh_controlled_capability_packets_once( window_hours: int = 24, limit: int = 5, ) -> dict[str, Any]: - """Persist controlled high-risk repair packets for failed Wazuh checks.""" + """Persist policy-correct repair packets for failed Wazuh checks.""" stats: dict[str, Any] = {"scanned": 0, "written": 0, "error": None} try: @@ -9328,6 +9386,8 @@ async def backfill_missing_wazuh_controlled_capability_packets_once( ) ) AND packet.parent_op_id = check_mode.op_id + AND packet.input ->> 'schema_version' = + :capability_packet_schema_version ) ORDER BY check_mode.created_at DESC LIMIT :limit @@ -9348,6 +9408,9 @@ async def backfill_missing_wazuh_controlled_capability_packets_once( "secret_failure_marker": ( _WAZUH_PRIVILEGED_CONVERGENCE_SECRET_REFERENCE_MISSING ), + "capability_packet_schema_version": ( + _WAZUH_CONTROLLED_CAPABILITY_PACKET_SCHEMA_VERSION + ), }, ) rows = [dict(row) for row in result.mappings().all()] diff --git a/apps/api/src/services/iwooos_wazuh_controlled_executor_runtime.py b/apps/api/src/services/iwooos_wazuh_controlled_executor_runtime.py index a27cee135..d09bb0c4c 100644 --- a/apps/api/src/services/iwooos_wazuh_controlled_executor_runtime.py +++ b/apps/api/src/services/iwooos_wazuh_controlled_executor_runtime.py @@ -22,7 +22,7 @@ from src.services.ai_automation_runtime_contract import ( ) from src.services.awooop_ansible_audit_service import get_ansible_catalog_item -SCHEMA_VERSION = "iwooos_wazuh_controlled_executor_runtime_readback_v2" +SCHEMA_VERSION = "iwooos_wazuh_controlled_executor_runtime_readback_v3" CATALOG_ID = "ansible:wazuh-manager-posture-readback" INGRESS_CATALOG_ID = "ansible:wazuh-alertmanager-integration" WORK_ITEM_ID = "P0-03-WAZUH-MANAGER-POSTURE" @@ -38,6 +38,9 @@ _PRIVILEGED_CONVERGENCE_CAPABILITY_MISSING = ( _PRIVILEGED_CONVERGENCE_SECRET_REFERENCE_MISSING = ( "wazuh_privileged_convergence_secret_reference_missing" ) +_CONTROLLED_CAPABILITY_PACKET_SCHEMA_VERSION = ( + "wazuh_controlled_privileged_capability_repair_v3" +) _PUBLIC_SAFE_CHECK_FAILURE_MARKERS = frozenset( { _PRIVILEGED_CONVERGENCE_CAPABILITY_MISSING, @@ -150,6 +153,7 @@ _LIVE_RUNTIME_SQL = """ SELECT packet.op_id::text AS controlled_capability_packet_receipt_id, packet.status AS controlled_capability_packet_status, + packet.input ->> 'schema_version' AS capability_schema_version, packet.input ->> 'capability_packet_id' AS capability_packet_id, packet.input ->> 'automation_run_id' AS capability_automation_run_id, @@ -515,6 +519,21 @@ def build_iwooos_wazuh_controlled_executor_runtime_readback( ) check_failed = data.get("check_status") == "failed" check_failure_class = _check_failure_class(data) + critical_secret_reference_required = bool( + check_failure_class + == _PRIVILEGED_CONVERGENCE_SECRET_REFERENCE_MISSING + ) + expected_capability_risk_level = ( + "critical" if critical_secret_reference_required else "high" + ) + expected_capability_policy_route = ( + "critical_secret_reference_break_glass" + if critical_secret_reference_required + else "high_risk_controlled_apply_capability_repair" + ) + expected_controlled_apply_allowed = ( + not critical_secret_reference_required + ) controlled_capability_packet_receipt_present = bool( data.get("controlled_capability_packet_receipt_id") ) @@ -549,21 +568,22 @@ def build_iwooos_wazuh_controlled_executor_runtime_readback( controlled_capability_packet_identity_verified, controlled_capability_packet_active, data.get("controlled_capability_packet_status") == "pending", + data.get("capability_schema_version") + == _CONTROLLED_CAPABILITY_PACKET_SCHEMA_VERSION, capability_packet_id.startswith("IWZ-CC-"), len(capability_packet_id) == 23, data.get("capability_type") == "bounded_privileged_convergence", - data.get("capability_risk_level") == "high", + data.get("capability_risk_level") + == expected_capability_risk_level, data.get("capability_policy_route") - == "high_risk_controlled_apply_capability_repair", + == expected_capability_policy_route, data.get("capability_queue_status") == "queued", - data.get("capability_controlled_apply_allowed") is True, + data.get("capability_controlled_apply_allowed") + is expected_controlled_apply_allowed, data.get("capability_windows99_dispatch_required") is True, bool(data.get("capability_critical_secret_reference_required")) - == ( - check_failure_class - == _PRIVILEGED_CONVERGENCE_SECRET_REFERENCE_MISSING - ), - data.get("capability_execution_allowed") is True, + == critical_secret_reference_required, + data.get("capability_execution_allowed") is False, data.get("capability_granted") is False, data.get("capability_packet_host_write_performed") is False, ) @@ -649,7 +669,11 @@ def build_iwooos_wazuh_controlled_executor_runtime_readback( active_blockers.append(check_failure_class) if check_failure_class in _PUBLIC_SAFE_CHECK_FAILURE_MARKERS: active_blockers.append( - "controlled_capability_repair_packet_pending" + ( + "wazuh_critical_secret_reference_provisioning_pending" + if critical_secret_reference_required + else "controlled_capability_repair_packet_pending" + ) if controlled_capability_packet_present else ( "controlled_capability_repair_packet_expired" @@ -759,16 +783,18 @@ def build_iwooos_wazuh_controlled_executor_runtime_readback( "status": "pending", "queue_status": "queued", "capability_type": "bounded_privileged_convergence", - "risk_level": "high", - "policy_route": "high_risk_controlled_apply_capability_repair", - "controlled_apply_allowed": True, + "risk_level": expected_capability_risk_level, + "policy_route": expected_capability_policy_route, + "controlled_apply_allowed": ( + expected_controlled_apply_allowed + ), "windows99_dispatch_required": True, "critical_secret_reference_required": bool( data.get("capability_critical_secret_reference_required") is True ), "expires_at": capability_expires_at.isoformat(), - "execution_allowed": True, + "execution_allowed": False, "capability_granted": False, "host_write_performed": False, "secret_value_exposed": False, @@ -811,9 +837,12 @@ def build_iwooos_wazuh_controlled_executor_runtime_readback( "inventory_identity_returned": False, "secret_value_collection_allowed": False, "critical_break_glass_required": ( - check_failure_class - == _PRIVILEGED_CONVERGENCE_SECRET_REFERENCE_MISSING + critical_secret_reference_required ), + "critical_secret_reference_provisioning_required": ( + critical_secret_reference_required + ), + "controlled_capability_execution_allowed": False, "controlled_capability_repair_packet_persisted": ( controlled_capability_packet_present ), @@ -899,18 +928,20 @@ def _next_action( ) if check_failed: if check_failure_class in _PUBLIC_SAFE_CHECK_FAILURE_MARKERS: - if controlled_capability_packet_present: - return ( - "windows99_verify_controlled_privilege_capability_then_" - "requeue_same_run" - ) if ( check_failure_class == _PRIVILEGED_CONVERGENCE_SECRET_REFERENCE_MISSING ): + if controlled_capability_packet_present: + return ( + "provision_opaque_host112_secret_reference_then_" + "windows99_verify_and_requeue_same_run" + ) + return "queue_critical_secret_reference_break_glass_packet" + if controlled_capability_packet_present: return ( - "queue_high_risk_capability_repair_with_critical_secret_" - "reference_boundary" + "windows99_verify_controlled_privilege_capability_then_" + "requeue_same_run" ) return ( "queue_high_risk_controlled_privilege_capability_repair_then_retry" diff --git a/apps/api/tests/test_iwooos_wazuh_controlled_executor_runtime.py b/apps/api/tests/test_iwooos_wazuh_controlled_executor_runtime.py index 280c4433f..3eb060dc8 100644 --- a/apps/api/tests/test_iwooos_wazuh_controlled_executor_runtime.py +++ b/apps/api/tests/test_iwooos_wazuh_controlled_executor_runtime.py @@ -146,7 +146,7 @@ def test_wazuh_runtime_readback_closes_only_with_complete_same_run_receipts() -> assert ( payload["schema_version"] - == "iwooos_wazuh_controlled_executor_runtime_readback_v2" + == "iwooos_wazuh_controlled_executor_runtime_readback_v3" ) assert payload["status"] == "wazuh_manager_posture_same_run_runtime_closed" assert payload["summary"]["runtime_execution_performed_count"] == 1 @@ -430,8 +430,7 @@ def test_wazuh_runtime_readback_keeps_only_secret_reference_as_critical() -> Non assert payload["boundaries"]["critical_break_glass_required"] is True assert payload["boundaries"]["secret_value_collection_allowed"] is False assert payload["next_safe_action"] == ( - "queue_high_risk_capability_repair_with_critical_secret_" - "reference_boundary" + "queue_critical_secret_reference_break_glass_packet" ) @@ -480,6 +479,9 @@ def test_wazuh_runtime_readback_projects_controlled_capability_packet() -> None: "iwooos_wazuh_alert_ingress_scheduler" ), "capability_source_recurrence": recurrence, + "capability_schema_version": ( + "wazuh_controlled_privileged_capability_repair_v3" + ), "capability_type": "bounded_privileged_convergence", "capability_risk_level": "high", "capability_policy_route": ( @@ -490,7 +492,7 @@ def test_wazuh_runtime_readback_projects_controlled_capability_packet() -> None: "capability_windows99_dispatch_required": True, "capability_critical_secret_reference_required": False, "capability_expires_at": "2030-07-17T02:30:00+00:00", - "capability_execution_allowed": True, + "capability_execution_allowed": False, "capability_granted": False, "capability_packet_host_write_performed": False, "stage_ids": [], @@ -510,7 +512,7 @@ def test_wazuh_runtime_readback_projects_controlled_capability_packet() -> None: ) packet = payload["controlled_capability_repair_packet"] assert packet["queue_status"] == "queued" - assert packet["execution_allowed"] is True + assert packet["execution_allowed"] is False assert packet["controlled_apply_allowed"] is True assert packet["windows99_dispatch_required"] is True assert packet["capability_granted"] is False @@ -523,6 +525,37 @@ def test_wazuh_runtime_readback_projects_controlled_capability_packet() -> None: "controlled_capability_repair_packet_persisted" ] is True + critical_row = { + **row, + "check_failure_marker": ( + "wazuh_privileged_convergence_secret_reference_missing" + ), + "capability_risk_level": "critical", + "capability_policy_route": ( + "critical_secret_reference_break_glass" + ), + "capability_controlled_apply_allowed": False, + "capability_critical_secret_reference_required": True, + } + critical = build_iwooos_wazuh_controlled_executor_runtime_readback( + critical_row, + executor_enabled=True, + ) + critical_packet = critical["controlled_capability_repair_packet"] + assert critical_packet["risk_level"] == "critical" + assert critical_packet["policy_route"] == ( + "critical_secret_reference_break_glass" + ) + assert critical_packet["controlled_apply_allowed"] is False + assert critical_packet["execution_allowed"] is False + assert critical["next_safe_action"] == ( + "provision_opaque_host112_secret_reference_then_" + "windows99_verify_and_requeue_same_run" + ) + assert "wazuh_critical_secret_reference_provisioning_pending" in ( + critical["active_blockers"] + ) + row["capability_expires_at"] = "2020-07-17T02:30:00+00:00" expired = build_iwooos_wazuh_controlled_executor_runtime_readback( row, @@ -595,7 +628,7 @@ def test_wazuh_controlled_capability_packet_is_deterministic_and_public_safe() - "capability_packet_id" ] assert packet_input["risk_level"] == "high" - assert packet_input["execution_allowed"] is True + assert packet_input["execution_allowed"] is False assert packet_input["controlled_apply_allowed"] is True assert packet_input["windows99_dispatch_required"] is True assert packet_input["critical_secret_reference_required"] is False @@ -610,6 +643,28 @@ def test_wazuh_controlled_capability_packet_is_deterministic_and_public_safe() - assert "must-not-be-projected" not in serialized assert "command_output" not in serialized + critical_input, critical_output, _ = ( + _build_wazuh_controlled_capability_packet( + **{ + **kwargs, + "failure_class": ( + "wazuh_privileged_convergence_secret_reference_missing" + ), + } + ) + ) + assert critical_input["risk_level"] == "critical" + assert critical_input["policy_route"] == ( + "critical_secret_reference_break_glass" + ) + assert critical_input["controlled_apply_allowed"] is False + assert critical_input["execution_allowed"] is False + assert critical_input["critical_secret_reference_required"] is True + assert critical_input["gate_lifecycle"]["risk_class"] == "critical" + assert "critical_secret_reference_provisioning_receipt" in ( + critical_output["required_receipts"] + ) + @pytest.mark.asyncio async def test_failed_wazuh_check_atomically_queues_deduplicated_packet( @@ -691,7 +746,7 @@ async def test_failed_wazuh_check_atomically_queues_deduplicated_packet( "ansible_controlled_capability_repair_queued" ) assert packet_input["risk_level"] == "high" - assert packet_input["execution_allowed"] is True + assert packet_input["execution_allowed"] is False assert packet_input["secret_value_exposed"] is False @@ -735,10 +790,20 @@ async def test_wazuh_controlled_capability_packet_backfill_closes_existing_gap( return "00000000-0000-0000-0000-000000000323" return None + inserted_packets: list[dict[str, object]] = [] + class _Db: - async def execute(self, statement, _params=None): + async def execute(self, statement, params=None): sql = str(statement) - return _Result(selected="SELECT" in sql and "JOIN" in sql) + selected = "SELECT" in sql and "JOIN" in sql + if selected: + assert "packet.input ->> 'schema_version'" in sql + assert params["capability_packet_schema_version"] == ( + "wazuh_controlled_privileged_capability_repair_v3" + ) + if "INSERT INTO automation_operation_log" in sql: + inserted_packets.append(json.loads(str(params["input"]))) + return _Result(selected=selected) @asynccontextmanager async def fake_db_context(project_id: str): @@ -750,6 +815,9 @@ async def test_wazuh_controlled_capability_packet_backfill_closes_existing_gap( result = await backfill_missing_wazuh_controlled_capability_packets_once() assert result == {"scanned": 1, "written": 1, "error": None} + assert inserted_packets[0]["schema_version"] == ( + "wazuh_controlled_privileged_capability_repair_v3" + ) def test_wazuh_posture_catalog_and_playbook_are_bounded_no_write() -> None: diff --git a/apps/api/tests/test_wazuh_alertmanager_integration.py b/apps/api/tests/test_wazuh_alertmanager_integration.py index d66c91614..b17cf95d8 100644 --- a/apps/api/tests/test_wazuh_alertmanager_integration.py +++ b/apps/api/tests/test_wazuh_alertmanager_integration.py @@ -544,8 +544,34 @@ async def test_wazuh_ingress_scheduler_records_one_high_risk_controlled_candidat @pytest.mark.asyncio +@pytest.mark.parametrize( + ( + "failure_class", + "expected_status", + "expected_controlled_apply_allowed", + "expected_blocker", + ), + [ + ( + "wazuh_privileged_convergence_capability_missing", + "controlled_privilege_capability_repair_already_queued", + True, + "wazuh_controlled_privilege_capability_repair_pending", + ), + ( + "wazuh_privileged_convergence_secret_reference_missing", + "critical_secret_reference_break_glass_already_queued", + False, + "wazuh_critical_secret_reference_provisioning_pending", + ), + ], +) async def test_wazuh_ingress_scheduler_does_not_repeat_failed_check_while_capability_repair_is_open( monkeypatch: pytest.MonkeyPatch, + failure_class: str, + expected_status: str, + expected_controlled_apply_allowed: bool, + expected_blocker: str, ) -> None: from src.jobs import awooop_ansible_candidate_backfill_job as job @@ -565,6 +591,7 @@ async def test_wazuh_ingress_scheduler_does_not_repeat_failed_check_while_capabi "latest_controlled_capability_packet_expires_at": ( "2026-07-15T06:29:59+08:00" ), + "latest_controlled_capability_failure_class": failure_class, "predecision_evidence_ready": True, } @@ -611,14 +638,13 @@ async def test_wazuh_ingress_scheduler_does_not_repeat_failed_check_while_capabi ), ) - assert result["status"] == ( - "controlled_privilege_capability_repair_already_queued" - ) + assert result["status"] == expected_status assert result["queued"] == 0 assert result["retry_of_failed_check_mode"] is True - assert result["active_blockers"] == [ - "wazuh_controlled_privilege_capability_repair_pending" - ] + assert result["controlled_apply_allowed"] is ( + expected_controlled_apply_allowed + ) + assert result["active_blockers"] == [expected_blocker] recorder.assert_not_awaited() collector.assert_not_awaited() verifier.assert_not_awaited() diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index f02772c5e..26afdec3f 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -14242,6 +14242,7 @@ "source": "Source", "packet": "Packet", "capabilityPacket": "Controlled capability", + "criticalPacket": "Critical boundary", "handoff": "Handoff", "ingress": "Alertmanager integration", "runtime": "Manager posture", @@ -14256,8 +14257,8 @@ "title": "Wazuh execution chain", "privilegedCapabilityMissing": "Controlled privilege is unverified. AI will run a high-risk repair through Windows99 and retry the same run.", "privilegedCapabilityPacketQueued": "The controlled repair is queued; Windows99 will verify it and retry the same run.", - "privilegedSecretReferenceMissing": "Host 112's opaque credential reference is missing; its value is never read back or logged.", - "privilegedSecretReferencePacketQueued": "Repair is queued for the credential reference and verifier, without a human terminal.", + "privilegedSecretReferenceMissing": "Host 112's opaque credential reference is missing; the critical execution boundary stays closed and its value is never read back or logged.", + "privilegedSecretReferencePacketQueued": "The critical credential-reference packet is queued; execution stays blocked until opaque projection and Windows99 verification pass.", "targetUnreachable": "Target trust failed; waiting for this release's bounded retry", "timeout": "Check mode timed out; waiting for this release's bounded retry", "checkFailed": "Check mode failed; waiting for this release's bounded retry", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 340e57367..8ca1303f3 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -14242,6 +14242,7 @@ "source": "來源", "packet": "Packet", "capabilityPacket": "受控能力包", + "criticalPacket": "critical 邊界包", "handoff": "Handoff", "ingress": "Alertmanager 整合", "runtime": "Manager posture", @@ -14256,8 +14257,8 @@ "title": "Wazuh 執行鏈", "privilegedCapabilityMissing": "受控提權能力未驗證。AI 將由 Windows99 執行 high-risk 修復並重試同一 run。", "privilegedCapabilityPacketQueued": "受控能力修復已排隊;Windows99 驗證後自動重試同一 run。", - "privilegedSecretReferenceMissing": "主機 112 的不透明憑證引用未投影;敏感值不讀回、不記錄。", - "privilegedSecretReferencePacketQueued": "修復包已排隊;等待憑證引用與 verifier,不轉成人工終局。", + "privilegedSecretReferenceMissing": "主機 112 的不透明憑證引用未投影;critical 執行邊界保持關閉,敏感值不讀回、不記錄。", + "privilegedSecretReferencePacketQueued": "critical 憑證引用處置包已排隊;完成不透明引用投影與 Windows99 驗證前禁止執行。", "targetUnreachable": "目標連線信任未通過,等待本版受控重試", "timeout": "check-mode 逾時,等待本版受控重試", "checkFailed": "check-mode 未通過,等待本版受控重試", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 90736e693..4c196ff4b 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -16701,6 +16701,7 @@ function IwoooSSecurityToolClosureBoard() { const dispatchCandidate = runtimeSummary?.dispatch_candidate_count ?? 0 const checkModeFailed = runtimeSummary?.check_mode_failed_count ?? 0 const controlledCapabilityPacket = runtimeSummary?.controlled_capability_repair_packet_count ?? 0 + const criticalSecretReferenceBoundary = runtimeData?.check_failure_class === 'wazuh_privileged_convergence_secret_reference_missing' const runtimeFailureKey = runtimeData?.check_failure_class === 'wazuh_privileged_convergence_secret_reference_missing' ? controlledCapabilityPacket > 0 ? 'privilegedSecretReferencePacketQueued' @@ -16729,15 +16730,21 @@ function IwoooSSecurityToolClosureBoard() { }, { key: 'packet', - labelKey: runtimeFailureKey?.startsWith('privileged') ? 'capabilityPacket' : 'packet', + labelKey: criticalSecretReferenceBoundary + ? 'criticalPacket' + : runtimeFailureKey?.startsWith('privileged') ? 'capabilityPacket' : 'packet', icon: FileCheck2, value: runtimeFailureKey?.startsWith('privileged') ? `${controlledCapabilityPacket}/1` : `${summary.wazuh_incident_response_closure_validator_available_count ?? 0}/1`, - tone: runtimeFailureKey?.startsWith('privileged') + tone: criticalSecretReferenceBoundary + ? 'locked' as const + : runtimeFailureKey?.startsWith('privileged') ? controlledCapabilityPacket > 0 ? 'warn' as const : 'locked' as const : (summary.wazuh_incident_response_closure_validator_available_count ?? 0) > 0 ? 'warn' as const : 'locked' as const, - state: runtimeFailureKey?.startsWith('privileged') + state: criticalSecretReferenceBoundary + ? 'blocked' + : runtimeFailureKey?.startsWith('privileged') ? controlledCapabilityPacket > 0 ? 'queued' : 'waiting' : (summary.wazuh_incident_response_closure_validator_available_count ?? 0) > 0 ? 'ready' : 'waiting', }, @@ -16954,10 +16961,10 @@ function IwoooSSecurityToolClosureBoard() { data-testid="iwooos-wazuh-runtime-failure" role="status" style={{ - border: '0.5px solid #d8a96f', + border: criticalSecretReferenceBoundary ? '0.5px solid #d68b8b' : '0.5px solid #d8a96f', borderRadius: 8, - background: '#fff8ef', - color: '#7c4618', + background: criticalSecretReferenceBoundary ? '#fff4f3' : '#fff8ef', + color: criticalSecretReferenceBoundary ? '#8b2525' : '#7c4618', padding: '9px 11px', display: 'flex', alignItems: 'center', diff --git a/apps/web/src/lib/api-client.ts b/apps/web/src/lib/api-client.ts index 6bce36e8f..8f1633626 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -885,7 +885,7 @@ export interface IwoooSSecurityToolClosureReadbackResponse { } export interface IwoooSWazuhControlledExecutorRuntimeReadbackResponse { - schema_version: 'iwooos_wazuh_controlled_executor_runtime_readback_v2' + schema_version: 'iwooos_wazuh_controlled_executor_runtime_readback_v3' status: string mode: string work_item_id: string @@ -935,13 +935,15 @@ export interface IwoooSWazuhControlledExecutorRuntimeReadbackResponse { status: string queue_status: 'queued' capability_type: 'bounded_privileged_convergence' - risk_level: 'high' - policy_route: 'high_risk_controlled_apply_capability_repair' - controlled_apply_allowed: true + risk_level: 'high' | 'critical' + policy_route: + | 'high_risk_controlled_apply_capability_repair' + | 'critical_secret_reference_break_glass' + controlled_apply_allowed: boolean windows99_dispatch_required: true critical_secret_reference_required: boolean expires_at: string - execution_allowed: true + execution_allowed: false capability_granted: false host_write_performed: false secret_value_exposed: false