Merge remote-tracking branch 'origin/main' into codex/ai-automation-codebase-review-20260710
This commit is contained in:
@@ -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 []
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -157,12 +157,12 @@ spec:
|
||||
- name: AWOOOI_BUILD_COMMIT_SHA
|
||||
# 2026-06-29 Codex: CD rewrites this to the deployed image tag so
|
||||
# production deploy readback does not rely on a stale static snapshot.
|
||||
value: "29e09afcc36b8c44d434356e93e8e43d69a945e9"
|
||||
value: "a789c5c99b7c05a745f709852fc19196d237b98d"
|
||||
- name: AWOOOI_DESIRED_API_IMAGE_TAG
|
||||
# 2026-06-30 Codex: CD rewrites this alongside AWOOOI_BUILD_COMMIT_SHA.
|
||||
# Production readback compares runtime image truth against this
|
||||
# GitOps desired tag instead of doing a slow Gitea raw fetch.
|
||||
value: "29e09afcc36b8c44d434356e93e8e43d69a945e9"
|
||||
value: "a789c5c99b7c05a745f709852fc19196d237b98d"
|
||||
- name: DATABASE_POOL_SIZE
|
||||
# 2026-07-01 Codex: production role `awoooi` currently has a low
|
||||
# connection limit. Keep API pool conservative until DB role
|
||||
|
||||
@@ -66,7 +66,7 @@ spec:
|
||||
- name: DATABASE_NULL_POOL
|
||||
value: "true"
|
||||
- name: AWOOOI_BUILD_COMMIT_SHA
|
||||
value: "29e09afcc36b8c44d434356e93e8e43d69a945e9"
|
||||
value: "a789c5c99b7c05a745f709852fc19196d237b98d"
|
||||
- name: ENABLE_AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_WORKER
|
||||
value: "false"
|
||||
- name: ENABLE_AWOOOP_ANSIBLE_CHECK_MODE_WORKER
|
||||
|
||||
@@ -178,7 +178,7 @@ spec:
|
||||
- name: DATABASE_BOOTSTRAP_DDL_ENABLED
|
||||
value: "false"
|
||||
- name: AWOOOI_BUILD_COMMIT_SHA
|
||||
value: "29e09afcc36b8c44d434356e93e8e43d69a945e9"
|
||||
value: "a789c5c99b7c05a745f709852fc19196d237b98d"
|
||||
- name: ENABLE_AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_WORKER
|
||||
value: "true"
|
||||
- name: ENABLE_SECURITY_CONTROL_PLANE_MAINTENANCE_WORKER
|
||||
|
||||
@@ -40,9 +40,9 @@ resources:
|
||||
# ⚠️ 重要: name 必須與 deployment YAML 中的 image 完全匹配 (含 tag)
|
||||
# newName + newTag 由 CI 透過 kustomize edit set image 注入
|
||||
images:
|
||||
- digest: sha256:b4bac7a281c61b1b51448a6189c9c5b806948e16f21879c90d113c678e299779
|
||||
- digest: sha256:c6d591f673cb36fbcb52b8a84f89e10fb7358d3e37c40b31451aff7e4d324fcf
|
||||
name: 192.168.0.110:5000/library/api:IMAGE_TAG_PLACEHOLDER
|
||||
newName: 192.168.0.110:5000/awoooi/api
|
||||
- digest: sha256:db8807dc230db1130b87fab86e8a016ec6b9f11bfc746282afa44e236bbaa159
|
||||
- digest: sha256:e61e593ea860383775a6bf89f51bb91985dd627fe8b14b806d0efffdf6b0c518
|
||||
name: 192.168.0.110:5000/library/web:IMAGE_TAG_PLACEHOLDER
|
||||
newName: 192.168.0.110:5000/awoooi/web
|
||||
|
||||
Reference in New Issue
Block a user