sdl-parser 0.21.2

The SDL parser is a Rust tool designed for parsing Scenario Defined Language files.
Documentation
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
            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
            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
            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
            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
            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();
    }
}