use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u16)]
pub enum ClassUid {
FileActivity = 1001,
ProcessActivity = 1007,
DetectionFinding = 2004,
NetworkActivity = 4001,
}
impl ClassUid {
#[must_use]
pub const fn as_u16(self) -> u16 {
self as u16
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum CategoryUid {
SystemActivity = 1,
Findings = 2,
NetworkActivity = 4,
}
impl CategoryUid {
#[must_use]
pub const fn as_u8(self) -> u8 {
self as u8
}
}
#[must_use]
pub const fn category_for_class(class: ClassUid) -> CategoryUid {
match class {
ClassUid::FileActivity | ClassUid::ProcessActivity => CategoryUid::SystemActivity,
ClassUid::DetectionFinding => CategoryUid::Findings,
ClassUid::NetworkActivity => CategoryUid::NetworkActivity,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum SeverityId {
Unknown = 0,
Informational = 1,
Low = 2,
Medium = 3,
High = 4,
Critical = 5,
Fatal = 6,
Other = 99,
}
impl SeverityId {
#[must_use]
pub const fn as_u8(self) -> u8 {
self as u8
}
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::Unknown => "Unknown",
Self::Informational => "Informational",
Self::Low => "Low",
Self::Medium => "Medium",
Self::High => "High",
Self::Critical => "Critical",
Self::Fatal => "Fatal",
Self::Other => "Other",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum ActionId {
Unknown = 0,
Allowed = 1,
Denied = 2,
Other = 99,
}
impl ActionId {
#[must_use]
pub const fn as_u8(self) -> u8 {
self as u8
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum DispositionId {
Unknown = 0,
Allowed = 1,
Blocked = 2,
Logged = 17,
Other = 99,
}
impl DispositionId {
#[must_use]
pub const fn as_u8(self) -> u8 {
self as u8
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum StatusId {
Unknown = 0,
Success = 1,
Failure = 2,
Other = 99,
}
impl StatusId {
#[must_use]
pub const fn as_u8(self) -> u8 {
self as u8
}
}
#[must_use]
pub const fn compute_type_uid(class_uid: u16, activity_id: u8) -> u32 {
(class_uid as u32) * 100 + (activity_id as u32)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn class_uid_values() {
assert_eq!(ClassUid::FileActivity.as_u16(), 1001);
assert_eq!(ClassUid::ProcessActivity.as_u16(), 1007);
assert_eq!(ClassUid::DetectionFinding.as_u16(), 2004);
assert_eq!(ClassUid::NetworkActivity.as_u16(), 4001);
}
#[test]
fn category_mapping() {
assert_eq!(
category_for_class(ClassUid::FileActivity),
CategoryUid::SystemActivity
);
assert_eq!(
category_for_class(ClassUid::ProcessActivity),
CategoryUid::SystemActivity
);
assert_eq!(
category_for_class(ClassUid::DetectionFinding),
CategoryUid::Findings
);
assert_eq!(
category_for_class(ClassUid::NetworkActivity),
CategoryUid::NetworkActivity
);
}
#[test]
fn severity_critical_is_five_not_six() {
assert_eq!(SeverityId::Critical.as_u8(), 5);
assert_eq!(SeverityId::Fatal.as_u8(), 6);
}
#[test]
fn type_uid_formula() {
assert_eq!(compute_type_uid(2004, 1), 200401);
assert_eq!(compute_type_uid(1007, 1), 100701);
assert_eq!(compute_type_uid(1001, 2), 100102);
assert_eq!(compute_type_uid(4001, 6), 400106);
}
#[test]
fn action_id_values() {
assert_eq!(ActionId::Allowed.as_u8(), 1);
assert_eq!(ActionId::Denied.as_u8(), 2);
}
#[test]
fn disposition_id_values() {
assert_eq!(DispositionId::Allowed.as_u8(), 1);
assert_eq!(DispositionId::Blocked.as_u8(), 2);
assert_eq!(DispositionId::Logged.as_u8(), 17);
}
#[test]
fn status_id_values() {
assert_eq!(StatusId::Unknown.as_u8(), 0);
assert_eq!(StatusId::Success.as_u8(), 1);
assert_eq!(StatusId::Failure.as_u8(), 2);
}
#[test]
fn severity_labels() {
assert_eq!(SeverityId::Informational.label(), "Informational");
assert_eq!(SeverityId::Critical.label(), "Critical");
assert_eq!(SeverityId::Fatal.label(), "Fatal");
}
}