clawdstrike_ocsf/objects/
attack.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(deny_unknown_fields)]
8pub struct Attack {
9 #[serde(skip_serializing_if = "Option::is_none")]
11 pub tactic: Option<AttackTactic>,
12 #[serde(skip_serializing_if = "Option::is_none")]
14 pub technique: Option<AttackTechnique>,
15 #[serde(skip_serializing_if = "Option::is_none")]
17 pub version: Option<String>,
18}
19
20#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
22#[serde(deny_unknown_fields)]
23pub struct AttackTactic {
24 pub name: String,
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub uid: Option<String>,
29}
30
31#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
33#[serde(deny_unknown_fields)]
34pub struct AttackTechnique {
35 pub name: String,
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub uid: Option<String>,
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn attack_roundtrip() {
48 let a = Attack {
49 tactic: Some(AttackTactic {
50 name: "Credential Access".to_string(),
51 uid: Some("TA0006".to_string()),
52 }),
53 technique: Some(AttackTechnique {
54 name: "OS Credential Dumping".to_string(),
55 uid: Some("T1003".to_string()),
56 }),
57 version: Some("14.1".to_string()),
58 };
59 let json = serde_json::to_string(&a).unwrap();
60 let a2: Attack = serde_json::from_str(&json).unwrap();
61 assert_eq!(a, a2);
62 }
63}