The asset sync fetched active agents only, and the sync-driven reconcile
inactivates every agent id the sync does not report. Since INACTIVE assets are
hidden from every CVE view, a host that was merely switched off lost all its
findings at the next sync — while Wazuh itself kept listing the agent and its
vulnerabilities. Holiday, sick leave or a spare laptop in a drawer looked
exactly like a decommissioned machine.
Root cause confirmed: not the 30-day soft-inactive window (which never got a
chance to apply here), but the connection-state filter feeding seen_ids.
- sync fetches ALL agents, paginated; disconnected ones stay in seen_ids
- last_seen now carries Wazuh's lastKeepAlive instead of "when we synced",
so there is a real stamp to measure against
- per-agent status comes from status_for_last_seen(): ACTIVE inside the
window, INACTIVE outside — replaces the binary connected/disconnected test
- reconcile_asset_lifecycle uses max(last_scan, last_seen): a host that keeps
checking in but cannot be scanned while offline no longer ages out early
- window default 30 -> 42 days, one setting for both paths; migration 044
rewrites only rows still holding the old default
- agents registered but never connected are skipped instead of imported
tests/test_asset_grace_window.py covers the window edges, UTC keepalive
parsing, the newest-stamp reconcile, and guards the sync against a
status filter being reintroduced.