Skip to main content

attack/domain/
analytic.rs

1use serde::{Deserialize, Serialize};
2use stix_rs::{CommonProperties, StixObject};
3use crate::domain::AttackObject;
4
5/// Represents a MITRE ATT&CK Analytic (x-mitre-analytic).
6///
7/// Analytics describe detection logic that can be used to identify
8/// adversary behavior described by ATT&CK techniques.
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub struct Analytic {
11    #[serde(flatten)]
12    pub common: CommonProperties,
13
14    pub name: String,
15    pub description: Option<String>,
16
17    /// The detection logic or query
18    #[serde(rename = "x_mitre_analytic")]
19    pub analytic: Option<String>,
20
21    /// Data sources required for this analytic
22    #[serde(default, rename = "x_mitre_data_sources")]
23    pub data_sources: Vec<String>,
24
25    // Extended ATT&CK fields
26    #[serde(default, rename = "x_mitre_version")]
27    pub version: Option<String>,
28
29    #[serde(default, rename = "x_mitre_domains")]
30    pub domains: Vec<String>,
31}
32
33impl StixObject for Analytic {
34    fn id(&self) -> &str {
35        &self.common.id
36    }
37
38    fn type_(&self) -> &str {
39        &self.common.r#type
40    }
41
42    fn created(&self) -> chrono::DateTime<chrono::Utc> {
43        self.common.created
44    }
45}
46
47impl AttackObject for Analytic {
48    fn name(&self) -> &str {
49        &self.name
50    }
51
52    fn description(&self) -> Option<&str> {
53        self.description.as_deref()
54    }
55
56    fn revoked(&self) -> bool {
57        self.common.revoked.unwrap_or(false)
58    }
59
60    fn deprecated(&self) -> bool {
61        self.common.custom_properties.get("x_mitre_deprecated").and_then(|v| v.as_bool()).unwrap_or(false)
62    }
63}