fix(iwooos): normalize wazuh receipt timestamps
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m27s
CD Pipeline / build-and-deploy (push) Successful in 6m55s
CD Pipeline / post-deploy-checks (push) Successful in 1m55s
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m27s
CD Pipeline / build-and-deploy (push) Successful in 6m55s
CD Pipeline / post-deploy-checks (push) Successful in 1m55s
This commit is contained in:
@@ -10,7 +10,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
from collections.abc import Mapping
|
||||
from datetime import datetime
|
||||
from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import text
|
||||
@@ -484,5 +484,26 @@ def _latest_receipt_at(data: Mapping[str, Any]) -> str | None:
|
||||
]
|
||||
if not values:
|
||||
return None
|
||||
latest = max(values)
|
||||
return latest.isoformat() if isinstance(latest, datetime) else str(latest)
|
||||
normalized = [
|
||||
parsed
|
||||
for value in values
|
||||
if (parsed := _utc_receipt_datetime(value)) is not None
|
||||
]
|
||||
if normalized:
|
||||
return max(normalized).isoformat()
|
||||
return max(str(value) for value in values)
|
||||
|
||||
|
||||
def _utc_receipt_datetime(value: Any) -> datetime | None:
|
||||
if isinstance(value, datetime):
|
||||
parsed = value
|
||||
elif isinstance(value, str):
|
||||
try:
|
||||
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
|
||||
except ValueError:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
if parsed.tzinfo is None:
|
||||
parsed = parsed.replace(tzinfo=UTC)
|
||||
return parsed.astimezone(UTC)
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import datetime
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
@@ -208,6 +208,26 @@ def test_wazuh_posture_catalog_and_playbook_are_bounded_no_write() -> None:
|
||||
assert wazuh_manager["criticality"] == "P0"
|
||||
|
||||
|
||||
def test_wazuh_runtime_readback_normalizes_mixed_receipt_timezones() -> None:
|
||||
row = _complete_row()
|
||||
row["candidate_created_at"] = datetime(2026, 7, 11, 3, 36)
|
||||
row["check_created_at"] = datetime(
|
||||
2026,
|
||||
7,
|
||||
11,
|
||||
3,
|
||||
37,
|
||||
tzinfo=UTC,
|
||||
)
|
||||
|
||||
payload = build_iwooos_wazuh_controlled_executor_runtime_readback(
|
||||
row,
|
||||
executor_enabled=True,
|
||||
)
|
||||
|
||||
assert payload["latest_receipt_at"] == "2026-07-11T03:37:00+00:00"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wazuh_posture_scheduler_enqueues_after_mcp_and_log_evidence(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
|
||||
Reference in New Issue
Block a user