feat(iwooos): add wazuh executor handoff runway
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m43s
CD Pipeline / build-and-deploy (push) Failing after 4m31s
CD Pipeline / post-deploy-checks (push) Has been skipped
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m43s
CD Pipeline / build-and-deploy (push) Failing after 4m31s
CD Pipeline / post-deploy-checks (push) Has been skipped
This commit is contained in:
@@ -43,6 +43,12 @@ from src.services.iwooos_wazuh_allowlisted_check_mode_dry_run import (
|
||||
from src.services.iwooos_wazuh_allowlisted_check_mode_dry_run import (
|
||||
validate_iwooos_wazuh_allowlisted_check_mode_dry_run_packet as validate_wazuh_allowlisted_check_mode_dry_run_packet_payload,
|
||||
)
|
||||
from src.services.iwooos_wazuh_controlled_executor_handoff import (
|
||||
load_latest_iwooos_wazuh_controlled_executor_handoff,
|
||||
)
|
||||
from src.services.iwooos_wazuh_controlled_executor_handoff import (
|
||||
preview_iwooos_wazuh_controlled_executor_handoff as preview_wazuh_controlled_executor_handoff_payload,
|
||||
)
|
||||
from src.services.iwooos_wazuh_fim_vulnerability_alert_verifier import (
|
||||
load_latest_iwooos_wazuh_fim_vulnerability_alert_verifier,
|
||||
)
|
||||
@@ -161,9 +167,9 @@ def _alertmanager_metric_fallback_readback(*, source_error: str) -> dict[str, An
|
||||
"source_status": "source_unavailable",
|
||||
"source_error": source_error,
|
||||
"fallback_source": "alert_chain_last_success_metric",
|
||||
"fallback_age_seconds": round(age_seconds, 3)
|
||||
if last_success_timestamp > 0
|
||||
else None,
|
||||
"fallback_age_seconds": (
|
||||
round(age_seconds, 3) if last_success_timestamp > 0 else None
|
||||
),
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -755,6 +761,73 @@ async def validate_iwooos_wazuh_incident_response_closure_packet(
|
||||
) from exc
|
||||
|
||||
|
||||
@router.get(
|
||||
"/api/v1/iwooos/wazuh-controlled-executor-handoff-readback",
|
||||
response_model=dict[str, Any],
|
||||
summary="取得 Wazuh controlled executor handoff bridge 讀回",
|
||||
description=(
|
||||
"彙整 Wazuh incident response same-run closure contract 與 AI controlled executor "
|
||||
"handoff runway,形成 P0-03 進入受控 executor 前的公開安全 handoff preview。"
|
||||
"此端點不保存 payload、不 dispatch executor、不查 live Wazuh API、不讀主機、不讀或回傳"
|
||||
"機密明文、不啟用主動回應、不改 Nginx / Docker / K8s / firewall。"
|
||||
),
|
||||
)
|
||||
async def get_iwooos_wazuh_controlled_executor_handoff_readback() -> dict[str, Any]:
|
||||
"""回傳 Wazuh controlled executor handoff bridge 公開安全讀回。"""
|
||||
try:
|
||||
alert_receipt_readback = await _alertmanager_receipt_readback()
|
||||
payload = await asyncio.to_thread(
|
||||
load_latest_iwooos_wazuh_controlled_executor_handoff,
|
||||
alert_receipt_readback=alert_receipt_readback,
|
||||
)
|
||||
return redact_public_lan_topology(payload)
|
||||
except FileNotFoundError as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=str(exc),
|
||||
) from exc
|
||||
except (json.JSONDecodeError, ValueError) as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"IwoooS Wazuh controlled executor handoff 讀回無效:{exc}",
|
||||
) from exc
|
||||
|
||||
|
||||
@router.post(
|
||||
"/api/v1/iwooos/wazuh-controlled-executor-handoff/preview",
|
||||
response_model=dict[str, Any],
|
||||
summary="預覽 Wazuh incident packet 的 controlled executor handoff",
|
||||
description=(
|
||||
"針對單次 redacted Wazuh incident response same-run packet 進行 no-persist handoff "
|
||||
"preview,先重用 incident response closure validator,再回傳受控 executor 候選路由、"
|
||||
"必要輸入、blocked actions 與下一個 verifier gate。此端點不保存 payload、不 dispatch executor、"
|
||||
"不查 live Wazuh API、不讀主機、不讀或回傳機密明文、不啟用主動回應、不改 Nginx / Docker / K8s / firewall。"
|
||||
),
|
||||
)
|
||||
async def preview_iwooos_wazuh_controlled_executor_handoff(
|
||||
incident_response_packet: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""回傳單次 Wazuh incident packet 的受控 executor handoff preview。"""
|
||||
try:
|
||||
alert_receipt_readback = await _alertmanager_receipt_readback()
|
||||
payload = await asyncio.to_thread(
|
||||
preview_wazuh_controlled_executor_handoff_payload,
|
||||
incident_response_packet,
|
||||
alert_receipt_readback=alert_receipt_readback,
|
||||
)
|
||||
return redact_public_lan_topology(payload)
|
||||
except FileNotFoundError as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=str(exc),
|
||||
) from exc
|
||||
except (json.JSONDecodeError, ValueError) as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"IwoooS Wazuh controlled executor handoff preview 無效:{exc}",
|
||||
) from exc
|
||||
|
||||
|
||||
@router.get(
|
||||
"/api/v1/iwooos/wazuh-runtime-gate-owner-review-readback",
|
||||
response_model=dict[str, Any],
|
||||
|
||||
@@ -19,6 +19,9 @@ from src.services.iwooos_security_operating_system import (
|
||||
from src.services.iwooos_wazuh_allowlisted_check_mode_dry_run import (
|
||||
load_latest_iwooos_wazuh_allowlisted_check_mode_dry_run,
|
||||
)
|
||||
from src.services.iwooos_wazuh_controlled_executor_handoff import (
|
||||
load_latest_iwooos_wazuh_controlled_executor_handoff,
|
||||
)
|
||||
from src.services.iwooos_wazuh_fim_vulnerability_alert_verifier import (
|
||||
load_latest_iwooos_wazuh_fim_vulnerability_alert_verifier,
|
||||
)
|
||||
@@ -66,6 +69,11 @@ def load_latest_iwooos_security_tool_closure_readback(
|
||||
alert_receipt_readback=alert_receipt_readback
|
||||
)
|
||||
)
|
||||
wazuh_controlled_executor_handoff = (
|
||||
load_latest_iwooos_wazuh_controlled_executor_handoff(
|
||||
alert_receipt_readback=alert_receipt_readback
|
||||
)
|
||||
)
|
||||
|
||||
source_payloads = [
|
||||
coverage,
|
||||
@@ -77,6 +85,7 @@ def load_latest_iwooos_security_tool_closure_readback(
|
||||
dry_run,
|
||||
wazuh_verifier,
|
||||
wazuh_incident_response_closure,
|
||||
wazuh_controlled_executor_handoff,
|
||||
]
|
||||
_require_runtime_boundaries(source_payloads)
|
||||
|
||||
@@ -89,8 +98,9 @@ def load_latest_iwooos_security_tool_closure_readback(
|
||||
"owner_review": _summary(owner_review),
|
||||
"dry_run": _summary(dry_run),
|
||||
"wazuh_verifier": _summary(wazuh_verifier),
|
||||
"wazuh_incident_response_closure": _summary(
|
||||
wazuh_incident_response_closure
|
||||
"wazuh_incident_response_closure": _summary(wazuh_incident_response_closure),
|
||||
"wazuh_controlled_executor_handoff": _summary(
|
||||
wazuh_controlled_executor_handoff
|
||||
),
|
||||
}
|
||||
tracks = _tool_tracks(source_summaries)
|
||||
@@ -145,6 +155,7 @@ def load_latest_iwooos_security_tool_closure_readback(
|
||||
*dry_run.get("source_refs", []),
|
||||
*wazuh_verifier.get("source_refs", []),
|
||||
*wazuh_incident_response_closure.get("source_refs", []),
|
||||
*wazuh_controlled_executor_handoff.get("source_refs", []),
|
||||
],
|
||||
}
|
||||
|
||||
@@ -289,7 +300,9 @@ def _tool_tracks(source_summaries: dict[str, dict[str, Any]]) -> list[dict[str,
|
||||
required_signal_count=4,
|
||||
next_executable_action="stage_rule_dry_run_event_redaction_and_wazuh_correlation",
|
||||
required_verifier="runtime_detection_event_post_verifier",
|
||||
source_refs=["docs/security/monitoring-alerting-observability-inventory.snapshot.json"],
|
||||
source_refs=[
|
||||
"docs/security/monitoring-alerting-observability-inventory.snapshot.json"
|
||||
],
|
||||
),
|
||||
_track(
|
||||
track_id="web_api_dast",
|
||||
@@ -311,7 +324,9 @@ def _tool_tracks(source_summaries: dict[str, dict[str, Any]]) -> list[dict[str,
|
||||
required_signal_count=4,
|
||||
next_executable_action="normalize_wazuh_alertmanager_app_events_into_review_cards",
|
||||
required_verifier="sigma_ocsf_event_mapping_regression_verifier",
|
||||
source_refs=["docs/security/iwooos-security-operating-system.snapshot.json"],
|
||||
source_refs=[
|
||||
"docs/security/iwooos-security-operating-system.snapshot.json"
|
||||
],
|
||||
),
|
||||
_track(
|
||||
track_id="ai_agent_controlled_apply",
|
||||
@@ -351,7 +366,11 @@ def _track(
|
||||
) -> dict[str, Any]:
|
||||
ready_count = max(min(ready_signal_count, required_signal_count), 0)
|
||||
missing_count = max(required_signal_count - ready_count, 0)
|
||||
source_readiness_percent = int(round((ready_count / required_signal_count) * 100)) if required_signal_count else 0
|
||||
source_readiness_percent = (
|
||||
int(round((ready_count / required_signal_count) * 100))
|
||||
if required_signal_count
|
||||
else 0
|
||||
)
|
||||
source_ready = missing_count == 0
|
||||
if runtime_closed:
|
||||
runtime_closure_state = "runtime_closed"
|
||||
@@ -404,6 +423,9 @@ def _summary_rollup(
|
||||
wazuh_incident_response_closure = source_summaries[
|
||||
"wazuh_incident_response_closure"
|
||||
]
|
||||
wazuh_controlled_executor_handoff = source_summaries[
|
||||
"wazuh_controlled_executor_handoff"
|
||||
]
|
||||
|
||||
expected_hosts = max(
|
||||
_int(managed_hosts.get("expected_host_scope_count")),
|
||||
@@ -425,20 +447,18 @@ def _summary_rollup(
|
||||
1 for track in tracks if track.get("runtime_closed") is True
|
||||
)
|
||||
source_readiness_percent = (
|
||||
int(round((total_ready / total_required) * 100))
|
||||
if total_required
|
||||
else 0
|
||||
int(round((total_ready / total_required) * 100)) if total_required else 0
|
||||
)
|
||||
runtime_closure_percent = (
|
||||
int(round((runtime_closed_track_count / len(tracks)) * 100))
|
||||
if tracks
|
||||
else 0
|
||||
int(round((runtime_closed_track_count / len(tracks)) * 100)) if tracks else 0
|
||||
)
|
||||
|
||||
return {
|
||||
"source_readback_count": len(source_summaries),
|
||||
"tool_track_count": len(tracks),
|
||||
"p0_tool_track_count": sum(1 for track in tracks if track.get("priority") == "P0"),
|
||||
"p0_tool_track_count": sum(
|
||||
1 for track in tracks if track.get("priority") == "P0"
|
||||
),
|
||||
"source_ready_tool_track_count": source_ready_track_count,
|
||||
"closed_tool_track_count": runtime_closed_track_count,
|
||||
"partial_tool_track_count": sum(
|
||||
@@ -459,7 +479,9 @@ def _summary_rollup(
|
||||
"tool_closure_percent": runtime_closure_percent,
|
||||
"wazuh_expected_host_scope_count": expected_hosts,
|
||||
"wazuh_manager_registry_accepted_count": accepted_hosts,
|
||||
"wazuh_registry_complete_count": 1 if expected_hosts > 0 and accepted_hosts >= expected_hosts else 0,
|
||||
"wazuh_registry_complete_count": (
|
||||
1 if expected_hosts > 0 and accepted_hosts >= expected_hosts else 0
|
||||
),
|
||||
"wazuh_fim_vulnerability_alert_closed_count": _int(
|
||||
wazuh_verifier.get("wazuh_fim_vulnerability_alert_closed_count")
|
||||
),
|
||||
@@ -469,9 +491,7 @@ def _summary_rollup(
|
||||
)
|
||||
),
|
||||
"wazuh_fim_vulnerability_alert_runtime_closed_count": _int(
|
||||
wazuh_verifier.get(
|
||||
"wazuh_fim_vulnerability_alert_runtime_closed_count"
|
||||
)
|
||||
wazuh_verifier.get("wazuh_fim_vulnerability_alert_runtime_closed_count")
|
||||
),
|
||||
"wazuh_fim_vulnerability_alert_verifier_ready_count": _int(
|
||||
wazuh_verifier.get("wazuh_fim_vulnerability_alert_verifier_ready_count")
|
||||
@@ -500,6 +520,30 @@ def _summary_rollup(
|
||||
"wazuh_incident_response_runtime_closed_count"
|
||||
)
|
||||
),
|
||||
"wazuh_controlled_executor_handoff_preview_ready_count": _int(
|
||||
wazuh_controlled_executor_handoff.get(
|
||||
"controlled_executor_handoff_preview_ready_count"
|
||||
)
|
||||
),
|
||||
"wazuh_controlled_executor_route_ready_count": _int(
|
||||
wazuh_controlled_executor_handoff.get(
|
||||
"controlled_executor_route_ready_count"
|
||||
)
|
||||
),
|
||||
"wazuh_controlled_executor_post_verifier_binding_count": _int(
|
||||
wazuh_controlled_executor_handoff.get("post_action_verifier_binding_count")
|
||||
),
|
||||
"wazuh_controlled_executor_learning_writeback_contract_count": _int(
|
||||
wazuh_controlled_executor_handoff.get("learning_writeback_contract_count")
|
||||
),
|
||||
"wazuh_controlled_executor_dispatch_enabled_count": _int(
|
||||
wazuh_controlled_executor_handoff.get(
|
||||
"bounded_executor_dispatch_enabled_count"
|
||||
)
|
||||
),
|
||||
"wazuh_controlled_executor_dispatch_count": _int(
|
||||
wazuh_controlled_executor_handoff.get("controlled_executor_dispatch_count")
|
||||
),
|
||||
"alert_receipt_observed_count": _int(
|
||||
security_os.get("alert_receipt_observed_count")
|
||||
),
|
||||
@@ -543,6 +587,9 @@ def _next_executable_queue(
|
||||
wazuh_incident_response_closure = source_summaries[
|
||||
"wazuh_incident_response_closure"
|
||||
]
|
||||
wazuh_controlled_executor_handoff = source_summaries[
|
||||
"wazuh_controlled_executor_handoff"
|
||||
]
|
||||
controlled_apply = source_summaries["controlled_apply"]
|
||||
dry_run = source_summaries["dry_run"]
|
||||
expected_hosts = max(
|
||||
@@ -562,11 +609,7 @@ def _next_executable_queue(
|
||||
> 0
|
||||
)
|
||||
runtime_closed = (
|
||||
_int(
|
||||
wazuh_verifier.get(
|
||||
"wazuh_fim_vulnerability_alert_runtime_closed_count"
|
||||
)
|
||||
)
|
||||
_int(wazuh_verifier.get("wazuh_fim_vulnerability_alert_runtime_closed_count"))
|
||||
> 0
|
||||
)
|
||||
same_run_candidate_ready = (
|
||||
@@ -618,9 +661,7 @@ def _next_executable_queue(
|
||||
wazuh_incident_response_closure.get("same_run_required_stage_count")
|
||||
),
|
||||
"same_run_source_stage_ready_count": _int(
|
||||
wazuh_incident_response_closure.get(
|
||||
"same_run_source_stage_ready_count"
|
||||
)
|
||||
wazuh_incident_response_closure.get("same_run_source_stage_ready_count")
|
||||
),
|
||||
"same_run_closure_candidate_ready_count": _int(
|
||||
wazuh_incident_response_closure.get(
|
||||
@@ -631,6 +672,17 @@ def _next_executable_queue(
|
||||
"/api/v1/iwooos/wazuh-incident-response-closure/"
|
||||
"validate-incident-response-packet"
|
||||
),
|
||||
"controlled_executor_handoff_readback_endpoint": (
|
||||
"/api/v1/iwooos/wazuh-controlled-executor-handoff-readback"
|
||||
),
|
||||
"controlled_executor_handoff_preview_endpoint": (
|
||||
"/api/v1/iwooos/wazuh-controlled-executor-handoff/preview"
|
||||
),
|
||||
"controlled_executor_handoff_preview_ready_count": _int(
|
||||
wazuh_controlled_executor_handoff.get(
|
||||
"controlled_executor_handoff_preview_ready_count"
|
||||
)
|
||||
),
|
||||
"next_gate_after_packet_acceptance": (
|
||||
"route_to_iwooos_controlled_executor_for_bounded_execution_and_post_verifier_writeback"
|
||||
),
|
||||
@@ -687,12 +739,12 @@ def _require_runtime_boundaries(payloads: list[dict[str, Any]]) -> None:
|
||||
summary = _summary(payload)
|
||||
for key in _REQUIRED_ZERO_SUMMARY_KEYS:
|
||||
if key in summary and _int(summary.get(key)) != 0:
|
||||
raise ValueError(f"{payload.get('schema_version')}: summary.{key} must remain 0")
|
||||
raise ValueError(
|
||||
f"{payload.get('schema_version')}: summary.{key} must remain 0"
|
||||
)
|
||||
boundaries = payload.get("boundaries")
|
||||
if isinstance(boundaries, dict):
|
||||
for key in (
|
||||
"secret_value_collection_allowed",
|
||||
):
|
||||
for key in ("secret_value_collection_allowed",):
|
||||
if key in boundaries and boundaries.get(key) is not False:
|
||||
raise ValueError(
|
||||
f"{payload.get('schema_version')}: boundaries.{key} must remain false"
|
||||
@@ -711,6 +763,9 @@ def _boundary_markers(summary: dict[str, Any]) -> list[str]:
|
||||
f"iwooos_security_tool_closure_alert_receipt_accepted_count={summary['alert_receipt_accepted_count']}",
|
||||
"iwooos_security_tool_closure_controlled_apply_policy_active=true",
|
||||
f"iwooos_security_tool_closure_controlled_apply_candidate_ready_count={summary['controlled_apply_candidate_ready_count']}",
|
||||
f"iwooos_wazuh_controlled_executor_handoff_preview_ready_count={summary['wazuh_controlled_executor_handoff_preview_ready_count']}",
|
||||
f"iwooos_wazuh_controlled_executor_dispatch_enabled_count={summary['wazuh_controlled_executor_dispatch_enabled_count']}",
|
||||
f"iwooos_wazuh_controlled_executor_dispatch_count={summary['wazuh_controlled_executor_dispatch_count']}",
|
||||
"owner_review_required_for_low_medium_high=false",
|
||||
"runtime_execution_performed=false",
|
||||
"secret_value_collection_allowed=false",
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
"""
|
||||
IwoooS Wazuh controlled executor handoff readback.
|
||||
|
||||
This service bridges the P0-03 Wazuh incident response packet validator to the
|
||||
existing AI controlled-executor runway. It only produces a public-safe handoff
|
||||
preview: no payload persistence, live Wazuh query, active response, host write,
|
||||
secret read, or executor dispatch is performed here.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from src.services.ai_agent_controlled_executor_handoff import (
|
||||
load_latest_ai_agent_controlled_executor_handoff,
|
||||
)
|
||||
from src.services.iwooos_wazuh_incident_response_closure import (
|
||||
load_latest_iwooos_wazuh_incident_response_closure,
|
||||
)
|
||||
from src.services.iwooos_wazuh_incident_response_closure import (
|
||||
validate_iwooos_wazuh_incident_response_closure_packet,
|
||||
)
|
||||
|
||||
_SCHEMA_VERSION = "iwooos_wazuh_controlled_executor_handoff_readback_v1"
|
||||
_PREVIEW_SCHEMA_VERSION = "iwooos_wazuh_controlled_executor_handoff_preview_result_v1"
|
||||
_ROUTE_ID = "iwooos_wazuh_incident_response_controlled_executor"
|
||||
_VALIDATION_ENDPOINT = (
|
||||
"/api/v1/iwooos/wazuh-incident-response-closure/"
|
||||
"validate-incident-response-packet"
|
||||
)
|
||||
_PREVIEW_ENDPOINT = "/api/v1/iwooos/wazuh-controlled-executor-handoff/preview"
|
||||
_READBACK_ENDPOINT = "/api/v1/iwooos/wazuh-controlled-executor-handoff-readback"
|
||||
|
||||
_RUNWAY_STAGES = (
|
||||
"incident_packet_review",
|
||||
"controlled_executor_handoff_preview",
|
||||
"bounded_executor_dispatch",
|
||||
"independent_post_verifier",
|
||||
"km_rag_mcp_playbook_writeback",
|
||||
)
|
||||
|
||||
|
||||
def load_latest_iwooos_wazuh_controlled_executor_handoff(
|
||||
security_dir: Path | None = None,
|
||||
alert_receipt_readback: dict[str, Any] | None = None,
|
||||
executor_handoff_readback: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Return the no-write handoff bridge between Wazuh P0-03 and executor runway."""
|
||||
incident_contract = load_latest_iwooos_wazuh_incident_response_closure(
|
||||
security_dir=security_dir,
|
||||
alert_receipt_readback=alert_receipt_readback,
|
||||
)
|
||||
executor_handoff = (
|
||||
executor_handoff_readback or load_latest_ai_agent_controlled_executor_handoff()
|
||||
)
|
||||
incident_summary = _summary(incident_contract)
|
||||
executor_rollups = _rollups(executor_handoff)
|
||||
executor_truth = _truth(executor_handoff)
|
||||
|
||||
handoff_preview_ready = (
|
||||
_int(incident_summary.get("closure_packet_validator_available_count")) > 0
|
||||
and _int(executor_rollups.get("ready_for_controlled_executor_count")) > 0
|
||||
and _int(executor_rollups.get("post_action_verifier_binding_count")) > 0
|
||||
and _int(executor_rollups.get("learning_writeback_contract_count")) > 0
|
||||
and executor_truth.get("controlled_executor_dispatch_enabled") is False
|
||||
)
|
||||
runtime_closed = (
|
||||
_int(incident_summary.get("wazuh_incident_response_runtime_closed_count")) > 0
|
||||
)
|
||||
|
||||
summary = {
|
||||
"incident_response_contract_ready_count": 1,
|
||||
"incident_response_packet_validator_available_count": _int(
|
||||
incident_summary.get("closure_packet_validator_available_count")
|
||||
),
|
||||
"same_run_source_stage_ready_count": _int(
|
||||
incident_summary.get("same_run_source_stage_ready_count")
|
||||
),
|
||||
"same_run_required_stage_count": _int(
|
||||
incident_summary.get("same_run_required_stage_count")
|
||||
),
|
||||
"same_run_closure_candidate_ready_count": _int(
|
||||
incident_summary.get("same_run_closure_candidate_ready_count")
|
||||
),
|
||||
"controlled_executor_handoff_preview_ready_count": (
|
||||
1 if handoff_preview_ready else 0
|
||||
),
|
||||
"controlled_executor_route_ready_count": _int(
|
||||
executor_rollups.get("executor_route_count")
|
||||
),
|
||||
"ready_for_controlled_executor_packet_count": _int(
|
||||
executor_rollups.get("ready_for_controlled_executor_count")
|
||||
),
|
||||
"post_action_verifier_binding_count": _int(
|
||||
executor_rollups.get("post_action_verifier_binding_count")
|
||||
),
|
||||
"learning_writeback_contract_count": _int(
|
||||
executor_rollups.get("learning_writeback_contract_count")
|
||||
),
|
||||
"critical_break_glass_count": _int(
|
||||
executor_rollups.get("critical_break_glass_count")
|
||||
),
|
||||
"bounded_executor_dispatch_enabled_count": 0,
|
||||
"controlled_executor_dispatch_count": 0,
|
||||
"runtime_execution_performed_count": 1 if runtime_closed else 0,
|
||||
"wazuh_incident_response_runtime_closed_count": 1 if runtime_closed else 0,
|
||||
"runtime_gate_count": 0,
|
||||
"wazuh_api_live_query_authorized_count": 0,
|
||||
"wazuh_active_response_authorized_count": 0,
|
||||
"host_write_authorized_count": 0,
|
||||
"secret_value_collection_allowed_count": 0,
|
||||
}
|
||||
|
||||
return {
|
||||
"schema_version": _SCHEMA_VERSION,
|
||||
"status": (
|
||||
"wazuh_controlled_executor_handoff_preview_ready_runtime_open"
|
||||
if handoff_preview_ready and not runtime_closed
|
||||
else "wazuh_controlled_executor_handoff_preview_unavailable"
|
||||
),
|
||||
"mode": "handoff_preview_only_no_dispatch_no_live_apply",
|
||||
"summary": summary,
|
||||
"runway": _runway(summary),
|
||||
"controlled_executor_candidate": _candidate(summary),
|
||||
"incident_response_packet_validation_endpoint": _VALIDATION_ENDPOINT,
|
||||
"controlled_executor_handoff_preview_endpoint": _PREVIEW_ENDPOINT,
|
||||
"controlled_executor_handoff_readback_endpoint": _READBACK_ENDPOINT,
|
||||
"next_executable_action": (
|
||||
"preview_redacted_wazuh_incident_packet_for_controlled_executor_handoff"
|
||||
),
|
||||
"next_gate_after_preview": (
|
||||
"bounded_executor_dispatch_requires_runtime_executor_receipt_and_independent_post_verifier"
|
||||
),
|
||||
"boundary_markers": _boundary_markers(summary),
|
||||
"boundaries": _boundaries(),
|
||||
"no_false_green_rules": [
|
||||
"handoff preview readiness is not executor dispatch",
|
||||
"runtime closure remains zero until bounded execution and post-verifier receipts are read back in production",
|
||||
"this endpoint never enables Wazuh active response or host writes",
|
||||
"critical break-glass packets remain excluded from automated dispatch",
|
||||
],
|
||||
"source_refs": [
|
||||
*incident_contract.get("source_refs", []),
|
||||
"apps/api/src/services/ai_agent_controlled_executor_handoff.py",
|
||||
"apps/api/src/services/iwooos_wazuh_controlled_executor_handoff.py",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def preview_iwooos_wazuh_controlled_executor_handoff(
|
||||
packet: dict[str, Any],
|
||||
security_dir: Path | None = None,
|
||||
alert_receipt_readback: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Validate a redacted packet and return a no-dispatch handoff preview."""
|
||||
readback = load_latest_iwooos_wazuh_controlled_executor_handoff(
|
||||
security_dir=security_dir,
|
||||
alert_receipt_readback=alert_receipt_readback,
|
||||
)
|
||||
validation = validate_iwooos_wazuh_incident_response_closure_packet(
|
||||
packet,
|
||||
security_dir=security_dir,
|
||||
alert_receipt_readback=alert_receipt_readback,
|
||||
)
|
||||
accepted = (
|
||||
validation.get("accepted_for_incident_response_closure_review_only") is True
|
||||
)
|
||||
runtime_rejected = validation.get("runtime_action_rejected") is True
|
||||
quarantined = validation.get("quarantined") is True
|
||||
preview_ready = (
|
||||
accepted
|
||||
and _int(
|
||||
readback["summary"].get("controlled_executor_handoff_preview_ready_count")
|
||||
)
|
||||
> 0
|
||||
)
|
||||
|
||||
summary = {
|
||||
"incident_response_packet_received_count": 1,
|
||||
"incident_response_packet_review_ready_count": 1 if accepted else 0,
|
||||
"controlled_executor_handoff_preview_ready_count": 1 if preview_ready else 0,
|
||||
"same_run_required_stage_count": _int(
|
||||
validation["summary"].get("same_run_required_stage_count")
|
||||
),
|
||||
"same_run_packet_stage_ready_count": _int(
|
||||
validation["summary"].get("same_run_packet_stage_ready_count")
|
||||
),
|
||||
"bounded_executor_dispatch_enabled_count": 0,
|
||||
"controlled_executor_dispatch_count": 0,
|
||||
"runtime_execution_performed_count": 0,
|
||||
"wazuh_incident_response_runtime_closed_count": 0,
|
||||
"runtime_gate_count": 0,
|
||||
"wazuh_api_live_query_authorized_count": 0,
|
||||
"wazuh_active_response_authorized_count": 0,
|
||||
"host_write_authorized_count": 0,
|
||||
"secret_value_collection_allowed_count": 0,
|
||||
}
|
||||
|
||||
return {
|
||||
"schema_version": _PREVIEW_SCHEMA_VERSION,
|
||||
"contract_schema_version": readback["schema_version"],
|
||||
"packet_validation_schema_version": validation["schema_version"],
|
||||
"status": (
|
||||
"ready_for_iwooos_wazuh_controlled_executor_handoff_preview_only"
|
||||
if preview_ready
|
||||
else str(validation.get("status") or "handoff_preview_blocked")
|
||||
),
|
||||
"mode": "preview_only_no_persist_no_dispatch_no_live_apply",
|
||||
"accepted_for_controlled_executor_handoff_preview_only": preview_ready,
|
||||
"quarantined": quarantined,
|
||||
"runtime_action_rejected": runtime_rejected,
|
||||
"summary": summary,
|
||||
"validation_status": validation.get("status"),
|
||||
"validation_findings": validation.get("validation_findings", []),
|
||||
"controlled_executor_candidate": _candidate(summary),
|
||||
"packet_field_bindings": (
|
||||
_packet_field_bindings(packet) if preview_ready else []
|
||||
),
|
||||
"next_gate": (
|
||||
"bounded_executor_dispatch_requires_runtime_executor_receipt_and_independent_post_verifier"
|
||||
if preview_ready
|
||||
else "fix_wazuh_incident_response_packet_before_handoff_preview"
|
||||
),
|
||||
"boundary_markers": _boundary_markers(summary),
|
||||
"boundaries": _boundaries(),
|
||||
}
|
||||
|
||||
|
||||
def _summary(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
summary = payload.get("summary")
|
||||
return summary if isinstance(summary, dict) else {}
|
||||
|
||||
|
||||
def _rollups(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
rollups = payload.get("rollups")
|
||||
return rollups if isinstance(rollups, dict) else {}
|
||||
|
||||
|
||||
def _truth(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
truth = payload.get("handoff_truth")
|
||||
return truth if isinstance(truth, dict) else {}
|
||||
|
||||
|
||||
def _int(value: Any) -> int:
|
||||
return value if isinstance(value, int) else 0
|
||||
|
||||
|
||||
def _runway(summary: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
"stage_id": "incident_packet_review",
|
||||
"label": "Incident packet",
|
||||
"ready_count": _int(
|
||||
summary.get("incident_response_packet_validator_available_count")
|
||||
),
|
||||
"required_count": 1,
|
||||
"status": "ready",
|
||||
},
|
||||
{
|
||||
"stage_id": "controlled_executor_handoff_preview",
|
||||
"label": "Executor handoff preview",
|
||||
"ready_count": _int(
|
||||
summary.get("controlled_executor_handoff_preview_ready_count")
|
||||
),
|
||||
"required_count": 1,
|
||||
"status": (
|
||||
"ready"
|
||||
if _int(summary.get("controlled_executor_handoff_preview_ready_count"))
|
||||
else "waiting"
|
||||
),
|
||||
},
|
||||
{
|
||||
"stage_id": "bounded_executor_dispatch",
|
||||
"label": "Bounded dispatch",
|
||||
"ready_count": 0,
|
||||
"required_count": 1,
|
||||
"status": "runtime_receipt_required",
|
||||
},
|
||||
{
|
||||
"stage_id": "independent_post_verifier",
|
||||
"label": "Post verifier",
|
||||
"ready_count": 0,
|
||||
"required_count": 1,
|
||||
"status": "runtime_receipt_required",
|
||||
},
|
||||
{
|
||||
"stage_id": "km_rag_mcp_playbook_writeback",
|
||||
"label": "Learning writeback",
|
||||
"ready_count": 0,
|
||||
"required_count": 1,
|
||||
"status": "runtime_receipt_required",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def _candidate(summary: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
"route_id": _ROUTE_ID,
|
||||
"risk_tier": "high",
|
||||
"handoff_status": (
|
||||
"ready_for_controlled_executor_handoff_preview"
|
||||
if _int(summary.get("controlled_executor_handoff_preview_ready_count"))
|
||||
else "waiting_for_validated_incident_packet"
|
||||
),
|
||||
"controlled_executor_handoff_allowed": True,
|
||||
"bounded_executor_dispatch_enabled": False,
|
||||
"runtime_write_performed": False,
|
||||
"side_effect_count": 0,
|
||||
"required_inputs": [
|
||||
"redacted_wazuh_event_receipt_ref",
|
||||
"redacted_forensics_evidence_ref",
|
||||
"incident_case_ref",
|
||||
"candidate_controlled_response_ref",
|
||||
"source_truth_diff_ref",
|
||||
"risk_policy_decision_ref",
|
||||
"check_mode_dry_run_ref",
|
||||
"rollback_plan_ref",
|
||||
"post_verifier_ref",
|
||||
"km_rag_mcp_playbook_writeback_ref",
|
||||
],
|
||||
"blocked_actions": [
|
||||
"live_wazuh_query",
|
||||
"wazuh_active_response",
|
||||
"host_write",
|
||||
"firewall_change",
|
||||
"secret_value_read",
|
||||
"executor_dispatch_by_readback_endpoint",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def _packet_field_bindings(packet: dict[str, Any]) -> list[dict[str, str]]:
|
||||
allowed_fields = (
|
||||
"trace_id",
|
||||
"run_id",
|
||||
"wazuh_event_receipt_ref",
|
||||
"forensics_evidence_ref",
|
||||
"incident_case_ref",
|
||||
"candidate_controlled_response_ref",
|
||||
"check_mode_dry_run_ref",
|
||||
"rollback_plan_ref",
|
||||
"post_verifier_ref",
|
||||
"km_rag_mcp_playbook_writeback_ref",
|
||||
)
|
||||
return [
|
||||
{"field": field, "binding_status": "present"}
|
||||
for field in allowed_fields
|
||||
if packet.get(field)
|
||||
]
|
||||
|
||||
|
||||
def _boundary_markers(summary: dict[str, Any]) -> list[str]:
|
||||
return [
|
||||
"iwooos_wazuh_controlled_executor_handoff_preview_available=true",
|
||||
(
|
||||
"iwooos_wazuh_controlled_executor_handoff_preview_ready_count="
|
||||
f"{_int(summary.get('controlled_executor_handoff_preview_ready_count'))}"
|
||||
),
|
||||
"iwooos_wazuh_controlled_executor_dispatch_enabled_count=0",
|
||||
"iwooos_wazuh_controlled_executor_dispatch_count=0",
|
||||
"iwooos_wazuh_controlled_executor_runtime_closed_count=0",
|
||||
"wazuh_api_live_query_authorized=false",
|
||||
"wazuh_active_response_authorized=false",
|
||||
"host_write_authorized=false",
|
||||
"secret_value_collection_allowed=false",
|
||||
"not_authorization=true",
|
||||
]
|
||||
|
||||
|
||||
def _boundaries() -> dict[str, Any]:
|
||||
return {
|
||||
"payload_persisted": False,
|
||||
"live_host_query_performed": False,
|
||||
"live_wazuh_query_performed": False,
|
||||
"scanner_execution_performed": False,
|
||||
"bounded_executor_dispatch_performed": False,
|
||||
"runtime_execution_performed": False,
|
||||
"runtime_execution_authorized": False,
|
||||
"runtime_gate_open": False,
|
||||
"wazuh_api_live_query_authorized": False,
|
||||
"wazuh_active_response_authorized": False,
|
||||
"host_write_authorized": False,
|
||||
"firewall_change_authorized": False,
|
||||
"secret_value_collection_allowed": False,
|
||||
"readback_endpoint_is_executor": False,
|
||||
"not_authorization": True,
|
||||
}
|
||||
Reference in New Issue
Block a user