From 4ecbb3ba1210c564f9048cfa5aaad9471e305ccb Mon Sep 17 00:00:00 2001 From: ogt Date: Fri, 17 Jul 2026 10:00:32 +0800 Subject: [PATCH] fix(sre): carry executor correlation into Ansible claims --- .../services/awooop_ansible_audit_service.py | 70 +++++++++++++++++-- ...claw_callback_forwarder_ansible_catalog.py | 51 +++++++++++++- 2 files changed, 115 insertions(+), 6 deletions(-) diff --git a/apps/api/src/services/awooop_ansible_audit_service.py b/apps/api/src/services/awooop_ansible_audit_service.py index 6f4efcd46..95942a7ec 100644 --- a/apps/api/src/services/awooop_ansible_audit_service.py +++ b/apps/api/src/services/awooop_ansible_audit_service.py @@ -34,6 +34,60 @@ _RECURRENCE_REQUIRED_PROPOSAL_SOURCES = frozenset( "iwooos_wazuh_alert_ingress_scheduler", } ) +_CONTROLLED_CORRELATION_RE = re.compile( + r"^[A-Za-z0-9](?:[A-Za-z0-9_.:-]{0,158}[A-Za-z0-9])?$" +) + + +def _controlled_correlation( + incident: dict[str, Any], + proposal: dict[str, Any], + *, + project_id: str, + incident_id: str, +) -> dict[str, str]: + """Preserve safe source correlation or generate one bounded run identity.""" + + signal_labels = [ + signal.get("labels") + for signal in incident.get("signals") or [] + if isinstance(signal, dict) and isinstance(signal.get("labels"), dict) + ] + + def first_safe(key: str) -> str: + for source in (proposal, incident, *signal_labels): + value = str(source.get(key) or "").strip() + if ( + value + and value not in {".", ".."} + and _CONTROLLED_CORRELATION_RE.fullmatch(value) + ): + return value + return "" + + safe_project = re.sub(r"[^A-Za-z0-9_.:-]", "-", project_id).strip("-.") + safe_incident = re.sub(r"[^A-Za-z0-9_.:-]", "-", incident_id).strip("-.") + generated_run = f"ansible:{safe_project or 'awoooi'}:{safe_incident or 'incident'}" + generated_run = generated_run[:160].rstrip("_.:-") + trace_id = first_safe("trace_id") + run_id = first_safe("run_id") + if not trace_id and not run_id: + trace_id = run_id = generated_run + elif not trace_id: + trace_id = run_id + elif not run_id: + run_id = trace_id + work_item_id = first_safe("work_item_id") or ( + f"ansible-controlled:{safe_project or 'awoooi'}:" + f"{safe_incident or 'incident'}" + )[:160].rstrip("_.:-") + return { + "trace_id": trace_id, + "run_id": run_id, + "work_item_id": work_item_id, + "run_namespace": first_safe("run_namespace") or safe_project or "awoooi", + "source_receipt_ref": first_safe("source_receipt_ref"), + } def _source_fingerprint(incident: dict[str, Any], proposal: dict[str, Any]) -> str: @@ -1684,6 +1738,12 @@ def build_ansible_decision_audit_payload( incident_id = str(incident_payload.get("incident_id") or "") project_id = str(incident_payload.get("project_id") or "awoooi") + correlation = _controlled_correlation( + incident_payload, + proposal_data, + project_id=project_id, + incident_id=incident_id, + ) affected_services = [ str(value) for value in incident_payload.get("affected_services") or [] @@ -1746,11 +1806,11 @@ def build_ansible_decision_audit_payload( input_payload = { "incident_id": incident_id, "project_id": project_id, - "trace_id": str(incident_payload.get("trace_id") or ""), - "run_id": str(incident_payload.get("run_id") or ""), - "work_item_id": str(incident_payload.get("work_item_id") or ""), - "run_namespace": str(incident_payload.get("run_namespace") or ""), - "source_receipt_ref": str(incident_payload.get("source_receipt_ref") or ""), + "trace_id": correlation["trace_id"], + "run_id": correlation["run_id"], + "work_item_id": correlation["work_item_id"], + "run_namespace": correlation["run_namespace"], + "source_receipt_ref": correlation["source_receipt_ref"], "asset_scope_aliases": [ str(alias) for alias in incident_payload.get("asset_scope_aliases") or [] diff --git a/apps/api/tests/test_host188_openclaw_callback_forwarder_ansible_catalog.py b/apps/api/tests/test_host188_openclaw_callback_forwarder_ansible_catalog.py index 8aac8605b..c36150730 100644 --- a/apps/api/tests/test_host188_openclaw_callback_forwarder_ansible_catalog.py +++ b/apps/api/tests/test_host188_openclaw_callback_forwarder_ansible_catalog.py @@ -8,6 +8,7 @@ import yaml from src.services.awooop_ansible_audit_service import ( _catalog_hints, + build_ansible_decision_audit_payload, get_ansible_catalog_item, ) from src.services.awooop_ansible_check_mode_service import ( @@ -72,7 +73,13 @@ def _incident() -> dict: "signals": [ { "alert_name": "TelegramCallbackIngressUnverified", - "labels": {"component": "openclaw", "host": "188"}, + "labels": { + "component": "openclaw", + "host": "188", + "trace_id": "aia-sre-017-callback-002", + "run_id": "aia-sre-017-callback-002", + "work_item_id": "AIA-SRE-017", + }, } ], } @@ -134,6 +141,48 @@ def test_openclaw_incident_selects_one_exact_bounded_catalog() -> None: assert hints["cross_domain_fallback_allowed"] is False +def test_openclaw_candidate_preserves_same_run_correlation() -> None: + payload = build_ansible_decision_audit_payload( + incident=_incident(), + proposal_data={ + "source": "alert_webhook_controlled_router", + "risk_level": "medium", + "source_fingerprint": "callback-fingerprint", + "source_occurrence_id": "alert-callback-002", + "source_recurrence_verified": True, + }, + decision_path="repair_candidate_controlled_queue", + not_used_reason="test", + ) + + assert payload is not None + assert payload["input"]["trace_id"] == "aia-sre-017-callback-002" + assert payload["input"]["run_id"] == "aia-sre-017-callback-002" + assert payload["input"]["work_item_id"] == "AIA-SRE-017" + assert payload["input"]["run_namespace"] == "awoooi" + + +def test_openclaw_candidate_generates_safe_correlation_when_source_omits_it() -> None: + incident = _incident() + incident["signals"][0]["labels"] = { + "component": "openclaw", + "host": "188", + } + payload = build_ansible_decision_audit_payload( + incident=incident, + proposal_data={"source": "test", "risk_level": "medium"}, + decision_path="repair_candidate_controlled_queue", + not_used_reason="test", + ) + + assert payload is not None + assert payload["input"]["trace_id"] == payload["input"]["run_id"] + assert payload["input"]["trace_id"].startswith("ansible:awoooi:") + assert payload["input"]["work_item_id"].startswith( + "ansible-controlled:awoooi:" + ) + + def test_openclaw_catalog_and_independent_verifier_are_exact() -> None: catalog = get_ansible_catalog_item(CATALOG_ID) conditions = postconditions_for_catalog(CATALOG_ID)