sdl_parser/
vulnerability.rs

1use anyhow::{anyhow, Result};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5use crate::{constants::CWE_REGEX, Formalize};
6
7#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
8pub struct Vulnerability {
9    #[serde(alias = "Name", alias = "NAME")]
10    pub name: String,
11    #[serde(alias = "Description", alias = "DESCRIPTION")]
12    pub description: String,
13    #[serde(default, alias = "Technical", alias = "TECHNICAL")]
14    pub technical: bool,
15    #[serde(alias = "Class", alias = "CLASS")]
16    pub class: String,
17}
18
19impl Formalize for Vulnerability {
20    fn formalize(&mut self) -> Result<()> {
21        if !CWE_REGEX.is_match(&self.class) {
22            return Err(anyhow!("Vulnerability class must match /CWE-\\d+/"));
23        }
24
25        Ok(())
26    }
27}
28
29pub type Vulnerabilities = HashMap<String, Vulnerability>;
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34    use crate::parse_sdl;
35
36    #[test]
37    fn vulnerability_is_parsed() {
38        let sdl = r#"
39            name: Some vulnerability
40            description: some-description
41            class: CWE-123
42        "#;
43        serde_yaml::from_str::<Vulnerability>(sdl).unwrap();
44    }
45
46    #[test]
47    fn default_technical_field_is_false() {
48        let sdl = r#"
49            name: Some vulnerability
50            description: some-description
51            class: CWE-123
52        "#;
53        let vulnerability = serde_yaml::from_str::<Vulnerability>(sdl).unwrap();
54        assert!(!vulnerability.technical);
55    }
56
57    #[test]
58    fn vulnerability_is_parsed_in_scenario() {
59        let sdl = r#"
60            name: test-scenario
61            description: some-description
62            vulnerabilities:
63                vuln-1:
64                    name: Some vulnerability
65                    description: some-description
66                    class: CWE-1341
67                vuln-2:
68                    name: Some other vulnerability
69                    description: some-description
70                    technical: false
71                    class: CWE-1343
72        "#;
73        let vulnerabilities = parse_sdl(sdl).unwrap().vulnerabilities;
74        insta::with_settings!({sort_maps => true}, {
75                insta::assert_yaml_snapshot!(vulnerabilities);
76        });
77    }
78
79    #[test]
80    fn parses_scenario_with_vulnerability_in_node() {
81        let sdl = r#"
82            name: test-scenario
83            description: some-description
84            vulnerabilities:
85                vuln-1:
86                    name: Some vulnerability
87                    description: some-description
88                    technical: true
89                    class: CWE-1341
90                vuln-2:
91                    name: Some other vulnerability
92                    description: some-description
93                    technical: false
94                    class: CWE-1343
95            nodes:
96                win-10:
97                    type: VM
98                    resources:
99                        ram: 2 gib
100                        cpu: 2
101                    source: windows10
102                    vulnerabilities:
103                        - vuln-2
104                        - vuln-1
105        "#;
106        parse_sdl(sdl).unwrap();
107    }
108
109    #[test]
110    #[should_panic(expected = "Vulnerability \"vuln-4\" not found under Scenario Vulnerabilities")]
111    fn missing_vulnerability_for_node() {
112        let sdl = r#"
113            name: test-scenario
114            description: some-description
115            vulnerabilities:
116                vuln-1:
117                    name: Some vulnerability
118                    description: some-description
119                    technical: true
120                    class: CWE-1343
121                vuln-2:
122                    name: Some other vulnerability
123                    description: some-description
124                    technical: false
125                    class: CWE-1343
126            nodes:
127                win-10:
128                    type: VM
129                    resources:
130                        ram: 2 gib
131                        cpu: 2
132                    source: windows10
133                    vulnerabilities:
134                        - vuln-4
135        "#;
136        parse_sdl(sdl).unwrap();
137    }
138
139    #[test]
140    fn parses_vulnerability_for_feature() {
141        let sdl = r#"
142            name: test-scenario
143            description: some-description
144            features:
145                my-less-cool-feature:
146                    type: Configuration
147                    source:
148                        name: cool-config
149                        version: 1.0.0
150                    vulnerabilities:
151                        - vuln-1
152                        - vuln-2
153            vulnerabilities:
154                vuln-1:
155                    name: Some vulnerability
156                    description: some-description
157                    technical: true
158                    class: CWE-1341
159                vuln-2:
160                    name: Some other vulnerability
161                    description: some-description
162                    technical: false
163                    class: CWE-1343
164        "#;
165        parse_sdl(sdl).unwrap();
166    }
167
168    #[test]
169    #[should_panic(expected = "Vulnerability \"vuln-4\" not found under Scenario Vulnerabilities")]
170    fn missing_vulnerability_for_feature() {
171        let sdl = r#"
172            name: test-scenario
173            description: some-description
174            features:
175                my-less-cool-feature:
176                    type: configuration
177                    source:
178                        name: cool-config
179                        version: 1.0.0
180                    vulnerabilities:
181                        - vuln-4
182            vulnerabilities:
183                vuln-1:
184                    name: Some vulnerability
185                    description: some-description
186                    technical: true
187                    class: CWE-1341
188                vuln-2:
189                    name: Some other vulnerability
190                    description: some-description
191                    technical: false
192                    class: CWE-1343
193            nodes:
194                win-10:
195                    type: VM
196                    resources:
197                        ram: 2 gib
198                        cpu: 2
199                    source: windows10
200                    vulnerabilities:
201                        - vuln-4
202        "#;
203        parse_sdl(sdl).unwrap();
204    }
205}