use crate::kind::EventKind;
use security_core::classification::DataClassification;
use security_core::severity::SecuritySeverity;
use security_core::types::{RequestId, TenantId, TraceId};
use serde::Serialize;
use std::collections::BTreeMap;
use std::net::IpAddr;
use time::OffsetDateTime;
use uuid::Uuid;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum EventOutcome {
Success,
Failure,
Blocked,
Unknown,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum EventValue {
Classified {
value: String,
classification: DataClassification,
},
}
#[derive(Clone, Debug, Serialize)]
pub struct SecurityEvent {
pub timestamp: OffsetDateTime,
pub event_id: Uuid,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_event_id: Option<Uuid>,
pub kind: EventKind,
pub severity: SecuritySeverity,
pub outcome: EventOutcome,
#[serde(skip_serializing_if = "Option::is_none")]
pub actor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tenant: Option<TenantId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_ip: Option<IpAddr>,
#[serde(skip_serializing_if = "Option::is_none")]
pub request_id: Option<RequestId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trace_id: Option<TraceId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resource: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason_code: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hmac: Option<String>,
pub labels: BTreeMap<String, EventValue>,
}
impl SecurityEvent {
#[must_use]
pub fn new(kind: EventKind, severity: SecuritySeverity, outcome: EventOutcome) -> Self {
Self {
timestamp: OffsetDateTime::now_utc(),
event_id: Uuid::new_v4(),
parent_event_id: None,
kind,
severity,
outcome,
actor: None,
tenant: None,
source_ip: None,
request_id: None,
trace_id: None,
session_id: None,
resource: None,
reason_code: None,
hmac: None,
labels: BTreeMap::new(),
}
}
#[must_use]
pub fn with_parent_event_id(mut self, parent_event_id: Uuid) -> Self {
self.parent_event_id = Some(parent_event_id);
self
}
}