feat: host inventory (agent.inventory), host detail page, UI columns

Store hardware/software snapshots on hosts; warn on hardware changes. Host card from Hosts list. Add agent version column to Events/Overview; rename Hosts table columns and sort by status.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-05 09:53:00 +10:00
parent 5d3cda2ab6
commit 54337a5917
23 changed files with 826 additions and 17 deletions
+22 -3
View File
@@ -7,6 +7,7 @@ from sqlalchemy.orm import Session
from app.models import Event, Host
from app.services.daily_report_format import normalize_daily_report_details
from app.services.event_severity_overrides import apply_severity_override
from app.services.host_inventory import INVENTORY_EVENT_TYPE, process_inventory_ingest
DAILY_REPORT_TYPES = frozenset({"report.daily.ssh", "report.daily.rdp"})
@@ -80,15 +81,33 @@ def ingest_event(db: Session, payload: dict) -> tuple[Event, bool]:
details = payload.get("details")
if payload.get("type") in DAILY_REPORT_TYPES:
details = normalize_daily_report_details(details, host, payload["type"])
severity = payload["severity"]
title = payload["title"]
summary = payload["summary"]
if payload.get("type") == INVENTORY_EVENT_TYPE:
inv_severity, hw_changes, inv_patch = process_inventory_ingest(host, details)
severity = inv_severity
if inv_patch:
merged = dict(details) if isinstance(details, dict) else {}
merged.update(inv_patch)
details = merged
if hw_changes:
change_fields = ", ".join(c["field"] for c in hw_changes)
title = f"Hardware inventory changed on {host.hostname}"
summary = (
f"Изменилось железо на {host.display_name or host.hostname}: {change_fields}"
)
event = Event(
event_id=event_id,
host_id=host.id,
occurred_at=_parse_dt(payload["occurred_at"]),
category=payload["category"],
type=payload["type"],
severity=payload["severity"],
title=payload["title"],
summary=payload["summary"],
severity=severity,
title=title,
summary=summary,
details=details,
raw=payload.get("raw"),
dedup_key=payload.get("dedup_key"),