use crate::csaf_traits::{CsafTrait, ProductStatusGroup, ProductStatusGroupMap, RemediationTrait, VulnerabilityTrait};
use crate::schema::csaf2_1::schema::CategoryOfTheRemediation;
use crate::validation::ValidationError;
const NOT_AFFECTED_CONFLICTS: &[CategoryOfTheRemediation] = &[
CategoryOfTheRemediation::Workaround,
CategoryOfTheRemediation::Mitigation,
CategoryOfTheRemediation::VendorFix,
CategoryOfTheRemediation::NoneAvailable,
];
const FIXED_CONFLICTS: &[CategoryOfTheRemediation] = &[
CategoryOfTheRemediation::NoneAvailable,
CategoryOfTheRemediation::FixPlanned,
CategoryOfTheRemediation::NoFixPlanned,
CategoryOfTheRemediation::VendorFix,
CategoryOfTheRemediation::Mitigation,
CategoryOfTheRemediation::Workaround,
];
fn create_affected_conflict_error(
product_id: &str,
category: &CategoryOfTheRemediation,
v_i: usize,
r_i: usize,
) -> ValidationError {
ValidationError {
message: format!(
"Product {product_id} is listed as affected but has conflicting remediation category {category}"
),
instance_path: format!("/vulnerabilities/{v_i}/remediations/{r_i}"),
}
}
fn create_not_affected_conflict_error(
product_id: &str,
category: &CategoryOfTheRemediation,
v_i: usize,
r_i: usize,
) -> ValidationError {
ValidationError {
message: format!(
"Product {product_id} is listed as not affected but has conflicting remediation category {category}"
),
instance_path: format!("/vulnerabilities/{v_i}/remediations/{r_i}"),
}
}
fn create_fixed_conflict_error(
product_id: &str,
category: &CategoryOfTheRemediation,
v_i: usize,
r_i: usize,
) -> ValidationError {
ValidationError {
message: format!("Product {product_id} is listed as fixed but has conflicting remediation category {category}"),
instance_path: format!("/vulnerabilities/{v_i}/remediations/{r_i}"),
}
}
pub fn test_6_1_36_status_group_contradicting_remediation_categories(
doc: &impl CsafTrait,
) -> Result<(), Vec<ValidationError>> {
for (v_i, v) in doc.get_vulnerabilities().iter().enumerate() {
if let Some(product_status) = v.get_product_status() {
let status_map = ProductStatusGroupMap::from(product_status);
for (r_i, r) in v.get_remediations().iter().enumerate() {
if let Some(product_ids) = r.get_all_product_ids(doc) {
let cat = r.get_category();
for p in product_ids {
if status_map.contains(&ProductStatusGroup::Affected, &p)
&& cat == CategoryOfTheRemediation::OptionalPatch
{
return Err(vec![create_affected_conflict_error(&p, &cat, v_i, r_i)]);
}
if status_map.contains(&ProductStatusGroup::NotAffected, &p)
&& NOT_AFFECTED_CONFLICTS.contains(&cat)
{
return Err(vec![create_not_affected_conflict_error(&p, &cat, v_i, r_i)]);
}
if status_map.contains(&ProductStatusGroup::Fixed, &p) && FIXED_CONFLICTS.contains(&cat) {
return Err(vec![create_fixed_conflict_error(&p, &cat, v_i, r_i)]);
}
}
}
}
}
}
Ok(())
}
crate::test_validation::impl_validator!(
csaf2_1,
ValidatorForTest6_1_36,
test_6_1_36_status_group_contradicting_remediation_categories
);
#[cfg(test)]
mod tests {
use super::*;
use crate::csaf2_1::testcases::TESTS_2_1;
#[test]
fn test_test_6_1_36() {
TESTS_2_1.test_6_1_36.expect(
Err(vec![create_not_affected_conflict_error(
"CSAFPID-9080700",
&CategoryOfTheRemediation::VendorFix,
0,
0,
)]),
Err(vec![create_fixed_conflict_error(
"CSAFPID-9080703",
&CategoryOfTheRemediation::NoneAvailable,
0,
0,
)]),
Err(vec![create_affected_conflict_error(
"CSAFPID-9080700",
&CategoryOfTheRemediation::OptionalPatch,
0,
0,
)]),
Err(vec![create_fixed_conflict_error(
"CSAFPID-9080700",
&CategoryOfTheRemediation::NoFixPlanned,
0,
0,
)]),
Ok(()),
Ok(()),
Ok(()),
Ok(()),
);
}
}