Security event schema v1
rullst-security::LiveSecurityEvent is the bounded event contract rendered by
Studio/Nexus and accepted by the process-local security store. Its current
schema version is exported as SECURITY_EVENT_SCHEMA_VERSION = 1.
The package also embeds and exports the JSON Schema 2020-12 document as
LIVE_SECURITY_EVENT_V1_JSON_SCHEMA; its packaged source is
security-event-v1.schema.json.
This is an application telemetry envelope, not a remote SIEM transport. The optional local spools provide bounded persistence and one explicit authenticated-journal mode, but the schema itself does not provide delivery, retention, correlation, acknowledgement, retry, dead-letter handling, source identity, or regulatory evidence.
JSON fields
| Field | v1 contract |
|---|---|
schema_version | Integer 1. Legacy JSON without the field deserializes as v1; locally stored events are normalized to v1. |
event_type | Non-empty uppercase ASCII letters, digits, and underscores; maximum 64 bytes. Invalid values become SECURITY_EVENT. |
details | Unstructured human-readable UTF-8 text; maximum 2 KiB and truncated only at a valid character boundary. It must not be parsed as authorization data. |
client_ip | Canonical IPv4/IPv6 string or unknown. Forwarded headers are not implicitly trusted. |
timestamp_str | Absolute RFC 3339 timestamp. Invalid local timestamps are replaced at ingestion. |
verified_hmac | true only when a connected verifier validated an HMAC for that exact event. It does not prove the event’s semantic claim or source identity. push_local_event always forces it to false. |
Example:
{
"schema_version": 1,
"event_type": "RBAC_DENIAL",
"details": "Authenticated principal denied access to the resource",
"client_ip": "192.0.2.4",
"timestamp_str": "2026-08-27T15:30:00.000Z",
"verified_hmac": false
}
Producer rules
New local producers should use LiveSecurityEvent::local(...) and
SecurityStore::push_local_event(...). This path:
- assigns schema v1 and an RFC 3339 timestamp;
- validates/bounds the type and detail text;
- canonicalizes the IP address;
- removes any caller-provided local HMAC claim; and
- stores the event in the bounded 50-entry process-local buffer.
The buffer is deliberately a dashboard snapshot. Loss on restart, eviction at capacity, and absence of a consumer are expected properties, not successful external delivery.
Compatibility rule
Within the stable v12 line:
- fields cannot be removed, renamed, or change meaning;
- a new required field or incompatible type requires a new schema version;
- additive optional fields require tolerant consumers and a changelog entry;
- event-type additions are compatible, so consumers need an unknown fallback;
- consumers must not infer trust from
verified_hmacalone; and - all compatibility claims apply to JSON, not field order in serialized text.
The version-one contract has source-controlled serialization, legacy-input,
normalization, size, UTF-8, and CEF-injection tests. DurableSiemSpool can
persist normalized unsigned v1 values in a local single-process file with exact
byte/record quotas, versioned length/digest frames and restart validation.
AuthenticatedSiemSpool is a distinct opt-in file format that authenticates
sequence, named rotation key, predecessor and exact payload before JSON decode;
verified reads set verified_hmac=true only after the complete chain passes.
Release evidence still belongs to the exact RC tag SHA.
CEF boundary
format_cef_event is a serializer only. It escapes backslashes, equals signs,
and CR/LF in extension values so event details cannot inject fields or records.
Calling dispatch_siem_alert records a local SIEM-candidate event; it does not
send or acknowledge an external alert.
Durable local spool boundary
DurableSiemSpool serializes one local event per bounded frame, calls
sync_data before returning a receipt, validates every frame on reopen and
rejects truncation, digest mismatch, invalid event JSON and external length
changes. The SHA-256 digest detects corruption; it is not an authentication tag.
The spool deliberately supplies no directory creation, multi-process lock,
rotation, retention, backup, retry, dead-letter handling or remote adapter.
Operators must provide a trusted, permissioned directory and one writer process
per file.
Authenticated local journal boundary
AuthenticatedSiemSpool uses domain-separated HMAC-SHA256 frames and a
SiemKeyRing containing one active write key plus at most seven historical
verification keys. Key material is held in zeroizing storage and omitted from
Debug. Reopen fails closed for an absent/wrong key, forged payload,
non-canonical sequence, broken predecessor chain, removed/reordered interior
frame, symlink target, quota violation or external file-length change.
The chain does not identify whether the local producer’s semantic assertion was true. Removal of a whole valid tail also needs a checkpoint retained in a separately trusted system. The journal does not rotate/compact itself or supply multi-process locking, remote delivery, retry, acknowledgement or dead-letter handling.
A future operational sink should consume the versioned JSON envelope and define redaction, backpressure, authentication, durable spool/retry/dead-letter, delivery acknowledgement, retention, and multi-tenant access separately.