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 9503669d3..18f9db704 100644 --- a/apps/api/src/services/awooop_ansible_check_mode_service.py +++ b/apps/api/src/services/awooop_ansible_check_mode_service.py @@ -8934,6 +8934,9 @@ def _build_wazuh_break_glass_capability_packet( "source_candidate_op_id": str(source_candidate_op_id), "source_check_mode_op_id": str(check_op_id), "catalog_id": str(catalog_id), + "semantic_operation_type": ( + _WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE + ), "capability_type": "bounded_privileged_convergence", "risk_level": "critical", "policy_route": "critical_break_glass_queue", @@ -8999,7 +9002,17 @@ async def _insert_wazuh_break_glass_capability_packet( input, output, dry_run_result, parent_op_id, tags ) SELECT - '{_WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE}', + CASE + WHEN EXISTS ( + SELECT 1 + FROM pg_constraint + WHERE conname = 'automation_operation_log_type_valid' + AND pg_get_constraintdef(oid) LIKE + '%{_WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE}%' + ) + THEN '{_WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE}' + ELSE '{_EXECUTION_CAPABILITY_FALLBACK_OPERATION_TYPE}' + END, 'ansible_check_mode_worker', 'pending', :incident_db_id, @@ -9014,8 +9027,16 @@ async def _insert_wazuh_break_glass_capability_packet( WHERE NOT EXISTS ( SELECT 1 FROM automation_operation_log existing - WHERE existing.operation_type = - '{_WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE}' + WHERE ( + existing.operation_type = + '{_WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE}' + OR ( + existing.operation_type = + '{_EXECUTION_CAPABILITY_FALLBACK_OPERATION_TYPE}' + AND existing.input ->> 'semantic_operation_type' = + '{_WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE}' + ) + ) AND existing.input ->> 'capability_packet_id' = :capability_packet_id ) @@ -9175,8 +9196,16 @@ async def backfill_missing_wazuh_break_glass_capability_packets_once( AND NOT EXISTS ( SELECT 1 FROM automation_operation_log packet - WHERE packet.operation_type = - '{_WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE}' + WHERE ( + packet.operation_type = + '{_WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE}' + OR ( + packet.operation_type = + '{_EXECUTION_CAPABILITY_FALLBACK_OPERATION_TYPE}' + AND packet.input ->> 'semantic_operation_type' = + '{_WAZUH_BREAK_GLASS_CAPABILITY_PACKET_OPERATION_TYPE}' + ) + ) AND packet.parent_op_id = check_mode.op_id ) ORDER BY check_mode.created_at DESC 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 a067bf7d6..3a764aa66 100644 --- a/apps/api/src/services/iwooos_wazuh_controlled_executor_runtime.py +++ b/apps/api/src/services/iwooos_wazuh_controlled_executor_runtime.py @@ -166,8 +166,15 @@ _LIVE_RUNTIME_SQL = """ FROM automation_operation_log packet JOIN latest_check check_mode ON packet.parent_op_id::text = check_mode.check_op_id - WHERE packet.operation_type = - 'ansible_break_glass_capability_work_item_queued' + WHERE ( + packet.operation_type = + 'ansible_break_glass_capability_work_item_queued' + OR ( + packet.operation_type = 'remediation_executed' + AND packet.input ->> 'semantic_operation_type' = + 'ansible_break_glass_capability_work_item_queued' + ) + ) ORDER BY packet.created_at DESC LIMIT 1 ), runtime_stages AS ( 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 6e7cd1eb5..d13102bfe 100644 --- a/apps/api/tests/test_iwooos_wazuh_controlled_executor_runtime.py +++ b/apps/api/tests/test_iwooos_wazuh_controlled_executor_runtime.py @@ -29,6 +29,7 @@ from src.services.awooop_ansible_check_mode_service import ( ) from src.services.awooop_ansible_post_verifier import postconditions_for_catalog from src.services.iwooos_wazuh_controlled_executor_runtime import ( + _LIVE_RUNTIME_SQL, build_iwooos_wazuh_controlled_executor_runtime_readback, ) @@ -46,6 +47,12 @@ def _current_wazuh_source_recurrence(observed_at: str) -> dict[str, object]: } +def test_wazuh_runtime_sql_reads_schema_safe_packet_fallback() -> None: + assert "ansible_break_glass_capability_work_item_queued" in _LIVE_RUNTIME_SQL + assert "remediation_executed" in _LIVE_RUNTIME_SQL + assert "semantic_operation_type" in _LIVE_RUNTIME_SQL + + def _durable_scheduled_wazuh_source_recurrence( observed_at: str, identity_anchor: str = ( @@ -600,9 +607,14 @@ async def test_failed_wazuh_check_atomically_queues_deduplicated_packet( assert len(calls) == 2 insert_sql, insert_params = calls[1] assert "ansible_break_glass_capability_work_item_queued" in insert_sql + assert "remediation_executed" in insert_sql + assert "pg_get_constraintdef" in insert_sql assert "WHERE NOT EXISTS" in insert_sql packet_input = json.loads(str(insert_params["input"])) assert packet_input["work_item_id"] == "P0-03-WAZUH-ALERT-INGRESS" + assert packet_input["semantic_operation_type"] == ( + "ansible_break_glass_capability_work_item_queued" + ) assert packet_input["secret_value_exposed"] is False