51 lines
1.8 KiB
Python
51 lines
1.8 KiB
Python
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
"""EVE-style event envelope: one typed wrapper for every emitted record.
|
|
|
|
Every envelope carries a stable ``schema`` id, an ``event_type`` discriminator,
|
|
a ``timestamp`` and ``host``, and the type-specific payload under a key named by
|
|
the event type (mirroring Suricata's EVE JSON, where an ``alert`` record holds
|
|
its detail under ``"alert"``). This is the reference contract a future Go agent
|
|
must emit byte-for-byte; the Python side is the oracle.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from datetime import datetime
|
|
|
|
from .schemas import EVENT_V1
|
|
|
|
# Closed set of v1 discriminators. New types are added additively in later
|
|
# phases (e.g. "dns", "tls", "http", "flow", "anomaly", "capture"); removing or
|
|
# renaming a value is a breaking change.
|
|
EVENT_TYPES = frozenset({"alert", "incident", "status"})
|
|
|
|
|
|
def build_event(
|
|
event_type: str,
|
|
payload: dict,
|
|
*,
|
|
host: str | None = None,
|
|
timestamp: str | None = None,
|
|
) -> dict:
|
|
"""Wrap ``payload`` in an ``enodia.event.v1`` envelope.
|
|
|
|
Raises ``ValueError`` if ``event_type`` is not a known v1 discriminator.
|
|
"""
|
|
if event_type not in EVENT_TYPES:
|
|
raise ValueError(f"unknown event_type: {event_type!r}")
|
|
if host is None:
|
|
host = os.uname().nodename
|
|
if timestamp is None:
|
|
timestamp = datetime.now().astimezone().isoformat()
|
|
return {
|
|
"schema": EVENT_V1,
|
|
"event_type": event_type,
|
|
"timestamp": timestamp,
|
|
"host": host,
|
|
event_type: payload,
|
|
}
|
|
|
|
|
|
def from_alert(alert, *, host: str | None = None, timestamp: str | None = None) -> dict:
|
|
"""Wrap an ``Alert`` (via its ``to_dict()``) in an ``alert`` event envelope."""
|
|
return build_event("alert", alert.to_dict(), host=host, timestamp=timestamp)
|