fix(ai-loop): validate durable Wazuh closure receipts

This commit is contained in:
Your Name
2026-07-22 20:36:25 +08:00
parent 6b87cf6d7f
commit bb9be8827b
2 changed files with 512 additions and 22 deletions

View File

@@ -3580,13 +3580,24 @@ def test_runtime_telegram_receipt_queries_include_alert_notifications() -> None:
assert "controlled_apply_result" in _RUNTIME_TELEGRAM_LATEST_SQL
assert "PARTITION BY CASE" in _RUNTIME_TELEGRAM_LATEST_SQL
assert "receipt_kind_rank <= :limit" in _RUNTIME_TELEGRAM_LATEST_SQL
for sql in (
_RUNTIME_TELEGRAM_LATEST_SQL,
runtime_control_module._RUNTIME_TELEGRAM_LATEST_DIRECT_SQL,
runtime_control_module._RUNTIME_RETRY_TERMINAL_LATEST_SQL,
):
assert "notification_lifecycle_state" in sql
assert "notification_suppression_reason" in sql
retry_sql = runtime_control_module._RUNTIME_RETRY_TERMINAL_LATEST_SQL
assert "notification_execution_kind" in retry_sql
assert "{callback_reply,apply_op_id}" in retry_sql
assert "{callback_reply,incident_id}" in retry_sql
@pytest.mark.parametrize(
("catalog_id", "shadow_completes"),
[
("ansible:generic-posture-readback", True),
("ansible:wazuh-manager-posture-readback", False),
("ansible:wazuh-manager-posture-readback", True),
],
)
def test_same_run_suppressed_shadow_respects_provider_receipt_policy(
@@ -3658,6 +3669,8 @@ def test_same_run_suppressed_shadow_respects_provider_receipt_policy(
),
"notification_disposition": "suppressed",
"notification_provider_delivery": "state_transition",
"notification_lifecycle_state": "recovered",
"notification_suppression_reason": "duplicate_lifecycle_state",
"notification_provider_send_suppressed": True,
}
],
@@ -3677,6 +3690,235 @@ def test_same_run_suppressed_shadow_respects_provider_receipt_policy(
assert telegram_stage["run_id_matches_expected"] is shadow_completes
@pytest.mark.parametrize(
(
"send_status",
"policy_version",
"provider_delivery",
"lifecycle_state",
"suppression_reason",
"expected",
),
[
(
"shadow",
"telegram_posture_lifecycle_transition_v1",
"state_transition",
"recovered",
"duplicate_lifecycle_state",
True,
),
(
"shadow",
"telegram_posture_state_digest_v1",
"shadow_only",
"recovered",
"historical_projection_backfill",
True,
),
(
"shadow",
"telegram_posture_state_digest_v1",
"digest",
"failed",
"duplicate_failure_fingerprint_window",
False,
),
(
"shadow",
"telegram_posture_lifecycle_transition_v1",
"state_transition",
"recovered",
"cooldown_active",
False,
),
(
"sent",
"telegram_posture_lifecycle_transition_v1",
"state_transition",
"recovered",
"",
True,
),
(
"sent",
"telegram_posture_lifecycle_transition_v1",
"state_transition",
"failed",
"",
False,
),
],
)
def test_wazuh_apply_receipt_requires_exact_recovered_lifecycle_provenance(
send_status: str,
policy_version: str,
provider_delivery: str,
lifecycle_state: str,
suppression_reason: str,
expected: bool,
) -> None:
assert runtime_control_module._durable_controlled_apply_telegram_receipt(
{
"action": "controlled_apply_result",
"send_status": send_status,
"provider_message_id": "42" if send_status == "sent" else None,
"notification_policy_version": policy_version,
"notification_disposition": (
"sent" if send_status == "sent" else "suppressed"
),
"notification_provider_delivery": provider_delivery,
"notification_lifecycle_state": lifecycle_state,
"notification_suppression_reason": suppression_reason,
"notification_provider_send_suppressed": send_status == "shadow",
},
catalog_id="ansible:wazuh-manager-posture-readback",
) is expected
def test_wazuh_duplicate_lifecycle_shadow_closes_strict_same_run_eighteen_stage_loop() -> (
None
):
automation_run_id = "wazuh-candidate-op"
incident_id = "INC-WAZUH-SHADOW-STRICT-CLOSURE"
apply_op_id = "wazuh-apply-op"
catalog_id = "ansible:wazuh-manager-posture-readback"
non_execution_stages = set(AI_AUTOMATION_REQUIRED_LOOP_STAGES) - set(
AI_AUTOMATION_EXECUTION_CORRELATED_STAGES
)
def stage_receipt(stage_id: str) -> dict[str, object]:
receipt: dict[str, object] = {
"schema_version": "ai_automation_stage_receipt_v1",
"stage_id": stage_id,
"automation_run_id": automation_run_id,
"evidence_ref": f"receipt:{stage_id}",
"durable_receipt": True,
}
if stage_id == "rag_writeback":
receipt["detail"] = {
"durable_write_acknowledged": True,
"source_id": f"ansible-learning:{apply_op_id}",
"rag_chunk_count": 1,
"chunk_index_verified": True,
}
elif stage_id == "playbook_trust":
receipt["detail"] = {
"schema_version": "ansible_playbook_trust_writeback_v2",
"identity_schema_version": "ansible_playbook_identity_v1",
"identity_fingerprint": "a" * 64,
"canonical_playbook_id": "PB-WAZUH-MANAGER-POSTURE",
"playbook_row_version": 1,
"playbook_row_updated_at": "2026-07-22T12:00:00+00:00",
"playbook_row_fingerprint": "b" * 64,
"trust_score": 1.0,
"trust_observation_count": 1,
"learning_recorded": True,
"trust_updated": True,
"repository_write_acknowledged": True,
"repository_readback_verified": True,
"operation_receipt_readback_verified": True,
"durable_write_acknowledged": True,
"writer_source_sha": "6b87cf6d7",
"raw_log_payload_stored": False,
"secret_value_stored": False,
}
return receipt
readback = build_runtime_receipt_readback_from_rows(
operation_latest_rows=[
{
"op_id": automation_run_id,
"operation_type": "ansible_candidate_matched",
"status": "dry_run",
"automation_run_id": automation_run_id,
"incident_id": incident_id,
"catalog_id": catalog_id,
},
{
"op_id": "wazuh-check-op",
"parent_op_id": automation_run_id,
"operation_type": "ansible_check_mode_executed",
"status": "success",
"automation_run_id": automation_run_id,
"incident_id": incident_id,
"catalog_id": catalog_id,
"returncode": "0",
},
{
"op_id": apply_op_id,
"parent_op_id": "wazuh-check-op",
"source_candidate_op_id": automation_run_id,
"check_mode_op_id": "wazuh-check-op",
"operation_type": "ansible_apply_executed",
"status": "success",
"automation_run_id": automation_run_id,
"incident_id": incident_id,
"catalog_id": catalog_id,
"returncode": "0",
"runtime_stage_receipts": [
stage_receipt(stage_id) for stage_id in non_execution_stages
],
},
],
auto_repair_latest_rows=[
{
"id": "wazuh-auto-repair",
"incident_id": incident_id,
"catalog_id": catalog_id,
"result_status": "success",
"automation_run_id": automation_run_id,
"executed_steps_text": f'["apply:{apply_op_id}"]',
}
],
verifier_latest_rows=[
{
"id": "wazuh-verifier",
"incident_id": incident_id,
"apply_op_id": apply_op_id,
"automation_run_id": automation_run_id,
"verification_result": "success",
}
],
km_latest_rows=[
{
"id": "wazuh-km",
"related_incident_id": incident_id,
"path_type": f"ansible_apply_receipt:{apply_op_id[:8]}",
"automation_run_id": automation_run_id,
"status": "linked",
}
],
telegram_latest_rows=[
{
"message_id": "wazuh-telegram-shadow",
"automation_run_id": automation_run_id,
"incident_id": incident_id,
"action": "controlled_apply_result",
"send_status": "shadow",
"provider_message_id": None,
"notification_policy_version": (
"telegram_posture_lifecycle_transition_v1"
),
"notification_disposition": "suppressed",
"notification_provider_delivery": "state_transition",
"notification_lifecycle_state": "recovered",
"notification_suppression_reason": "duplicate_lifecycle_state",
"notification_provider_send_suppressed": True,
}
],
)
strict = build_ai_agent_strict_runtime_completion_from_readback(readback)
assert strict["required_stage_count"] == 18
assert strict["present_stage_count"] == 18
assert strict["missing_stage_ids"] == []
assert strict["full_trace_same_run_correlation_proven"] is True
assert strict["completion_percent"] == 100
assert strict["closed"] is True
def test_unclassified_shadow_cannot_satisfy_telegram_receipt() -> None:
assert runtime_control_module._durable_controlled_apply_telegram_receipt(
{
@@ -4173,6 +4415,113 @@ def test_retry_terminal_accepts_policy_complete_suppressed_receipt() -> None:
assert terminal["controls"]["telegram_receipt_same_run"] is True
@pytest.mark.parametrize(
(
"execution_kind",
"send_status",
"policy_version",
"provider_delivery",
"lifecycle_state",
"suppression_reason",
"expected_closed",
),
[
(
"no_write_posture_readback",
"sent",
"telegram_posture_lifecycle_transition_v1",
"state_transition",
"failed",
"",
True,
),
(
"no_write_posture_readback",
"shadow",
"telegram_posture_lifecycle_transition_v1",
"state_transition",
"failed",
"duplicate_lifecycle_state",
True,
),
(
"no_write_replay",
"sent",
"telegram_failure_digest_v2",
"digest",
"failed",
"",
True,
),
(
"no_write_replay",
"shadow",
"telegram_failure_digest_v2",
"digest",
"failed",
"duplicate_failure_fingerprint_window",
True,
),
(
"no_write_replay",
"shadow",
"telegram_failure_digest_v2",
"shadow_only",
"failed",
"historical_projection_backfill",
True,
),
(
"no_write_posture_readback",
"shadow",
"telegram_posture_lifecycle_transition_v1",
"state_transition",
"recovered",
"duplicate_lifecycle_state",
False,
),
],
)
def test_wazuh_retry_terminal_requires_exact_failed_lifecycle_receipt(
execution_kind: str,
send_status: str,
policy_version: str,
provider_delivery: str,
lifecycle_state: str,
suppression_reason: str,
expected_closed: bool,
) -> None:
row = _closed_retry_terminal_row()
row.update(
{
"catalog_id": "ansible:wazuh-manager-posture-readback",
"telegram_send_status": send_status,
"telegram_provider_message_id": (
"wazuh-provider-message" if send_status == "sent" else None
),
"telegram_notification_execution_kind": execution_kind,
"telegram_notification_policy_version": policy_version,
"telegram_notification_disposition": (
"sent" if send_status == "sent" else "suppressed"
),
"telegram_notification_provider_delivery": provider_delivery,
"telegram_notification_lifecycle_state": lifecycle_state,
"telegram_notification_suppression_reason": suppression_reason,
"telegram_provider_send_suppressed": send_status == "shadow",
}
)
terminal = build_runtime_receipt_readback_from_rows(
retry_terminal_latest_rows=[row]
)["autonomous_retry_rollback_terminal"]
assert terminal["closed"] is expected_closed
assert terminal["controls"]["telegram_receipt_same_run"] is expected_closed
assert (
"telegram_receipt_same_run_not_verified" in terminal["active_blockers"]
) is not expected_closed
def test_retry_rollback_terminal_fails_closed_on_run_mismatch_or_missing_proof():
row = _closed_retry_terminal_row()
row["telegram_automation_run_id"] = "different-run"