use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::{constants::CWE_REGEX, Formalize};
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
pub struct Vulnerability {
#[serde(alias = "Name", alias = "NAME")]
pub name: String,
#[serde(alias = "Description", alias = "DESCRIPTION")]
pub description: String,
#[serde(default, alias = "Technical", alias = "TECHNICAL")]
pub technical: bool,
#[serde(alias = "Class", alias = "CLASS")]
pub class: String,
}
impl Formalize for Vulnerability {
fn formalize(&mut self) -> Result<()> {
if !CWE_REGEX.is_match(&self.class) {
return Err(anyhow!("Vulnerability class must match /CWE-\\d+/"));
}
Ok(())
}
}
pub type Vulnerabilities = HashMap<String, Vulnerability>;
#[cfg(test)]
mod tests {
use super::*;
use crate::parse_sdl;
#[test]
fn vulnerability_is_parsed() {
let sdl = r#"
name: Some vulnerability
description: some-description
class: CWE-123
"#;
serde_yaml::from_str::<Vulnerability>(sdl).unwrap();
}
#[test]
fn default_technical_field_is_false() {
let sdl = r#"
name: Some vulnerability
description: some-description
class: CWE-123
"#;
let vulnerability = serde_yaml::from_str::<Vulnerability>(sdl).unwrap();
assert!(!vulnerability.technical);
}
#[test]
fn vulnerability_is_parsed_in_scenario() {
let sdl = r#"
name: test-scenario
description: some-description
start: 2022-01-20T13:00:00Z
end: 2022-01-20T23:00:00Z
vulnerabilities:
vuln-1:
name: Some vulnerability
description: some-description
class: CWE-1341
vuln-2:
name: Some other vulnerability
description: some-description
technical: false
class: CWE-1343
"#;
let vulnerabilities = parse_sdl(sdl).unwrap().vulnerabilities;
insta::with_settings!({sort_maps => true}, {
insta::assert_yaml_snapshot!(vulnerabilities);
});
}
#[test]
fn parses_scenario_with_vulnerability_in_node() {
let sdl = r#"
name: test-scenario
description: some-description
start: 2022-01-20T13:00:00Z
end: 2022-01-20T23:00:00Z
vulnerabilities:
vuln-1:
name: Some vulnerability
description: some-description
technical: true
class: CWE-1341
vuln-2:
name: Some other vulnerability
description: some-description
technical: false
class: CWE-1343
nodes:
win-10:
type: VM
resources:
ram: 2 gib
cpu: 2
source: windows10
vulnerabilities:
- vuln-2
- vuln-1
"#;
parse_sdl(sdl).unwrap();
}
#[test]
#[should_panic(expected = "Vulnerability \"vuln-4\" not found under Scenario Vulnerabilities")]
fn missing_vulnerability_for_node() {
let sdl = r#"
name: test-scenario
description: some-description
start: 2022-01-20T13:00:00Z
end: 2022-01-20T23:00:00Z
vulnerabilities:
vuln-1:
name: Some vulnerability
description: some-description
technical: true
class: CWE-1343
vuln-2:
name: Some other vulnerability
description: some-description
technical: false
class: CWE-1343
nodes:
win-10:
type: VM
resources:
ram: 2 gib
cpu: 2
source: windows10
vulnerabilities:
- vuln-4
"#;
parse_sdl(sdl).unwrap();
}
#[test]
fn parses_vulnerability_for_feature() {
let sdl = r#"
name: test-scenario
description: some-description
start: 2022-01-20T13:00:00Z
end: 2022-01-20T23:00:00Z
features:
my-less-cool-feature:
type: Configuration
source:
name: cool-config
version: 1.0.0
vulnerabilities:
- vuln-1
- vuln-2
vulnerabilities:
vuln-1:
name: Some vulnerability
description: some-description
technical: true
class: CWE-1341
vuln-2:
name: Some other vulnerability
description: some-description
technical: false
class: CWE-1343
"#;
parse_sdl(sdl).unwrap();
}
#[test]
#[should_panic(expected = "Vulnerability \"vuln-4\" not found under Scenario Vulnerabilities")]
fn missing_vulnerability_for_feature() {
let sdl = r#"
name: test-scenario
description: some-description
start: 2022-01-20T13:00:00Z
end: 2022-01-20T23:00:00Z
features:
my-less-cool-feature:
type: configuration
source:
name: cool-config
version: 1.0.0
vulnerabilities:
- vuln-4
vulnerabilities:
vuln-1:
name: Some vulnerability
description: some-description
technical: true
class: CWE-1341
vuln-2:
name: Some other vulnerability
description: some-description
technical: false
class: CWE-1343
nodes:
win-10:
type: VM
resources:
ram: 2 gib
cpu: 2
source: windows10
vulnerabilities:
- vuln-4
"#;
parse_sdl(sdl).unwrap();
}
}