Skip to content

Refactor validations and improve error reporting #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 5 additions & 28 deletions csaf-lib/src/csaf/csaf2_0/validation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use super::schema::CommonSecurityAdvisoryFramework;
use crate::csaf::validation::{test_6_01_01_missing_definition_of_product_id, test_6_01_02_multiple_definition_of_product_id, Test, Validatable, ValidationPreset};
use std::collections::HashMap;
use crate::csaf::validation::{Test, Validatable, ValidationPreset};
use crate::csaf::validations::test_6_1_01::test_6_1_01_missing_definition_of_product_id;
use crate::csaf::validations::test_6_1_02::test_6_1_02_multiple_definition_of_product_id;

impl Validatable<CommonSecurityAdvisoryFramework> for CommonSecurityAdvisoryFramework {
fn presets(&self) -> HashMap<ValidationPreset, Vec<&str>> {
Expand All @@ -20,8 +22,8 @@ impl Validatable<CommonSecurityAdvisoryFramework> for CommonSecurityAdvisoryFram
fn tests(&self) -> HashMap<&str, Test<CommonSecurityAdvisoryFramework>> {
type CsafTest = Test<CommonSecurityAdvisoryFramework>;
HashMap::from([
("6.1.1", test_6_01_01_missing_definition_of_product_id as CsafTest),
("6.1.2", test_6_01_02_multiple_definition_of_product_id as CsafTest),
("6.1.1", test_6_1_01_missing_definition_of_product_id as CsafTest),
("6.1.2", test_6_1_02_multiple_definition_of_product_id as CsafTest),
])
}

Expand All @@ -30,28 +32,3 @@ impl Validatable<CommonSecurityAdvisoryFramework> for CommonSecurityAdvisoryFram
}
}

#[cfg(test)]
mod tests {
use crate::csaf::csaf2_0::loader::load_document;
use crate::csaf::validation::{test_6_01_01_missing_definition_of_product_id, test_6_01_02_multiple_definition_of_product_id};

#[test]
fn test_test_6_01_01() {
let doc = load_document("../csaf/csaf_2.0/test/validator/data/mandatory/oasis_csaf_tc-csaf_2_0-2021-6-1-01-01.json").unwrap();
assert_eq!(
test_6_01_01_missing_definition_of_product_id(&doc),
Err(String::from("Missing definitions: [\"CSAFPID-9080700\", \"CSAFPID-9080701\"]"))
)
}

#[test]
fn test_test_6_01_02() {
let doc = load_document("../csaf/csaf_2.0/test/validator/data/mandatory/oasis_csaf_tc-csaf_2_0-2021-6-1-02-01.json").unwrap();
assert_eq!(
test_6_01_02_multiple_definition_of_product_id(&doc),
Err(String::from(
"Duplicate definitions: [\"CSAFPID-9080700\"]"
))
)
}
}
84 changes: 9 additions & 75 deletions csaf-lib/src/csaf/csaf2_1/validation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use super::schema::CommonSecurityAdvisoryFramework;
use crate::csaf::validation::{test_6_01_01_missing_definition_of_product_id, test_6_01_02_multiple_definition_of_product_id, test_6_01_34_branches_recursion_depth, test_6_01_35_contradicting_remediations, Test, Validatable, ValidationPreset};
use crate::csaf::validation::{Test, Validatable, ValidationPreset};
use crate::csaf::validations::test_6_1_01::test_6_1_01_missing_definition_of_product_id;
use crate::csaf::validations::test_6_1_02::test_6_1_02_multiple_definition_of_product_id;
use crate::csaf::validations::test_6_1_34::test_6_1_34_branches_recursion_depth;
use crate::csaf::validations::test_6_1_35::test_6_1_35_contradicting_remediations;
use std::collections::HashMap;

impl Validatable<CommonSecurityAdvisoryFramework> for CommonSecurityAdvisoryFramework {
Expand All @@ -20,84 +24,14 @@ impl Validatable<CommonSecurityAdvisoryFramework> for CommonSecurityAdvisoryFram
fn tests(&self) -> HashMap<&str, Test<CommonSecurityAdvisoryFramework>> {
type CsafTest = Test<CommonSecurityAdvisoryFramework>;
HashMap::from([
("6.1.1", test_6_01_01_missing_definition_of_product_id as CsafTest),
("6.1.2", test_6_01_02_multiple_definition_of_product_id as CsafTest),
("6.1.34", test_6_01_34_branches_recursion_depth as CsafTest),
("6.1.35", test_6_01_35_contradicting_remediations as CsafTest),
("6.1.1", test_6_1_01_missing_definition_of_product_id as CsafTest),
("6.1.2", test_6_1_02_multiple_definition_of_product_id as CsafTest),
("6.1.34", test_6_1_34_branches_recursion_depth as CsafTest),
("6.1.35", test_6_1_35_contradicting_remediations as CsafTest),
])
}

fn doc(&self) -> &CommonSecurityAdvisoryFramework {
self
}
}

#[cfg(test)]
mod tests {
use crate::csaf::csaf2_1::loader::load_document;
use crate::csaf::validation::{test_6_01_01_missing_definition_of_product_id, test_6_01_02_multiple_definition_of_product_id, test_6_01_34_branches_recursion_depth, test_6_01_35_contradicting_remediations};

#[test]
fn test_test_6_01_01() {
let doc = load_document("../csaf/csaf_2.1/test/validator/data/mandatory/oasis_csaf_tc-csaf_2_1-2024-6-1-01-01.json").unwrap();
assert_eq!(
test_6_01_01_missing_definition_of_product_id(&doc),
Err(String::from("Missing definitions: [\"CSAFPID-9080700\", \"CSAFPID-9080701\"]"))
)
}

#[test]
fn test_test_6_01_02() {
let doc = load_document("../csaf/csaf_2.1/test/validator/data/mandatory/oasis_csaf_tc-csaf_2_1-2024-6-1-02-01.json").unwrap();
assert_eq!(
test_6_01_02_multiple_definition_of_product_id(&doc),
Err(String::from(
"Duplicate definitions: [\"CSAFPID-9080700\"]"
))
)
}

#[test]
fn test_test_6_01_34() {
for x in ["11"].iter() {
let doc = load_document(format!("../csaf/csaf_2.1/test/validator/data/mandatory/oasis_csaf_tc-csaf_2_1-2024-6-1-34-{}.json", x).as_str()).unwrap();
assert_eq!(
Ok(()),
test_6_01_35_contradicting_remediations(&doc)
)
}
for (x, err) in [
("01", "Branches recursion depth too big (> 30)"),
("02", "Branches recursion depth too big (> 30)"),
].iter() {
let doc = load_document(format!("../csaf/csaf_2.1/test/validator/data/mandatory/oasis_csaf_tc-csaf_2_1-2024-6-1-34-{}.json", x).as_str()).unwrap();
assert_eq!(
Err(format!("{}", err)),
test_6_01_34_branches_recursion_depth(&doc)
)
}
}

#[test]
fn test_test_6_01_35() {
for x in ["11", "12", "13", "14"].iter() {
let doc = load_document(format!("../csaf/csaf_2.1/test/validator/data/mandatory/oasis_csaf_tc-csaf_2_1-2024-6-1-35-{}.json", x).as_str()).unwrap();
assert_eq!(
Ok(()),
test_6_01_35_contradicting_remediations(&doc)
)
}
for (x, err) in [
("01", "Product CSAFPID-9080700 has contradicting remediations: no_fix_planned and vendor_fix"),
("02", "Product CSAFPID-9080700 has contradicting remediations: none_available and mitigation"),
("03", "Product CSAFPID-9080702 has contradicting remediations: workaround, fix_planned and optional_patch"),
("04", "Product CSAFPID-9080701 has contradicting remediations: mitigation, fix_planned and optional_patch"),
].iter() {
let doc = load_document(format!("../csaf/csaf_2.1/test/validator/data/mandatory/oasis_csaf_tc-csaf_2_1-2024-6-1-35-{}.json", x).as_str()).unwrap();
assert_eq!(
Err(format!("{}", err)),
test_6_01_35_contradicting_remediations(&doc)
)
}
}
}
4 changes: 2 additions & 2 deletions csaf-lib/src/csaf/getter_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ pub trait RemediationTrait {
None
} else {
let mut product_set: BTreeSet<String> = match self.get_product_ids() {
Some(product_ids) => product_ids.iter().map(|p| p.to_string()).collect(),
Some(product_ids) => product_ids.iter().map(|id| (*id).to_owned()).collect(),
None => BTreeSet::new(),
};
if let Some(product_groups) = self.get_group_ids() {
if let Some(product_ids) = resolve_product_groups(doc, product_groups) {
product_set.extend(product_ids.iter().map(|p| p.to_string()));
product_set.extend(product_ids.iter().map(|id| id.to_owned()));
}
}
Some(product_set)
Expand Down
20 changes: 1 addition & 19 deletions csaf-lib/src/csaf/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
use crate::csaf::getter_traits::{CsafTrait, ProductGroupTrait, ProductTreeTrait};
use std::collections::{BTreeSet, HashMap};

pub fn find_duplicates<T: std::hash::Hash + Eq + Clone>(vec: Vec<T>) -> Vec<T> {
let mut occurrences = HashMap::new();
let mut duplicates = Vec::new();

for item in vec.iter() {
let count = occurrences.entry(item.clone()).or_insert(0);
*count += 1;
}

for (item, count) in occurrences {
if count > 1 {
duplicates.push(item);
}
}

duplicates
}
use std::collections::BTreeSet;

pub fn resolve_product_groups(doc: &impl CsafTrait, product_groups: Vec<&String>) -> Option<BTreeSet<String>> {
doc.get_product_tree().map(|product_tree| {
Expand Down
1 change: 1 addition & 0 deletions csaf-lib/src/csaf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ mod helpers;
pub mod product_helpers;
pub mod validation;
pub mod getter_traits;
pub mod validations;
Loading