use crate::csaf_traits::{ContentTrait, CsafTrait, MetricTrait, VulnerabilityTrait};
use crate::validation::ValidationError;
use ssvc::selection_list::SelectionList;
use ssvc::validation::SsvcError;
fn create_invalid_ssvc_error(error: impl std::fmt::Display, i_v: usize, i_m: usize) -> ValidationError {
ValidationError {
message: format!("Invalid SSVC object: {error}"),
instance_path: format!("/vulnerabilities/{i_v}/metrics/{i_m}/content/ssvc_v2"),
}
}
pub fn test_6_1_48_ssvc_decision_points(doc: &impl CsafTrait) -> Result<(), Vec<ValidationError>> {
test_6_1_48_ssvc_decision_points_internal(doc, ssvc::validation::validate_selection_list)
}
fn test_6_1_48_ssvc_decision_points_internal(
doc: &impl CsafTrait,
validation_fn: fn(&SelectionList) -> Result<(), Vec<SsvcError>>,
) -> Result<(), Vec<ValidationError>> {
let vulnerabilities = doc.get_vulnerabilities();
for (i_v, v) in vulnerabilities.iter().enumerate() {
if let Some(metrics) = v.get_metrics() {
for (i_m, m) in metrics.iter().enumerate() {
let content = m.get_content();
if content.has_ssvc_v2() {
match content.get_ssvc_v2() {
Ok(ssvc) => {
if let Err(ssvc_errors) = validation_fn(&ssvc) {
let validation_errors: Vec<ValidationError> = ssvc_errors
.into_iter()
.map(|ssvc_error| {
let path_suffix = ssvc_error.instance_path.join("/");
ValidationError {
message: ssvc_error.message,
instance_path: format!(
"/vulnerabilities/{i_v}/metrics/{i_m}/content/ssvc_v2/{path_suffix}"
),
}
})
.collect();
return Err(validation_errors);
}
},
Err(err) => {
return Err(vec![create_invalid_ssvc_error(err, i_v, i_m)]);
},
}
}
}
}
}
Ok(())
}
impl crate::test_validation::TestValidator<crate::schema::csaf2_1::schema::CommonSecurityAdvisoryFramework>
for crate::csaf2_1::testcases::ValidatorForTest6_1_48
{
fn validate(
&self,
doc: &crate::schema::csaf2_1::schema::CommonSecurityAdvisoryFramework,
) -> Result<(), Vec<ValidationError>> {
test_6_1_48_ssvc_decision_points_internal(doc, ssvc::validation::validate_selection_list_allow_test)
}
}
#[cfg(test)]
mod tests {
use crate::csaf2_1::testcases::TESTS_2_1;
use crate::validation::ValidationError;
#[test]
fn test_test_6_1_48() {
let case_01 = Err(vec![ValidationError {
message: "The SSVC decision point 'ssvc::Mission Impact' (version 1.0.0) doesn't have a value with key 'D'"
.to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0/values/1".to_string(),
}]);
let case_02 = Err(vec![ValidationError {
message: "Unknown SSVC decision point 'ssvc::SIs' with version '2.0.0'".to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0".to_string(),
}]);
let case_03 = Err(vec![ValidationError {
message:
"The values for SSVC decision point 'ssvc::Safety Impact' (version 2.0.0) are not in correct order"
.to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0/values/1".to_string(),
}]);
let case_04 = Err(vec![ValidationError {
message: "Unknown SSVC decision point 'ssvc::SI' with version '1.9.7'".to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0".to_string(),
}]);
let case_05 = Err(vec![ValidationError {
message:
"The SSVC decision point 'cvss::Attack Complexity' (version 3.0.1) doesn't have a value with key 'E'"
.to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0/values/0".to_string(),
}]);
let case_06 = Err(vec![ValidationError {
message: "Unknown SSVC decision point 'cvss::E' with version '3.0.1'".to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0".to_string(),
}]);
let case_07 = Err(vec![ValidationError {
message: "The SSVC decision point 'ssvc//.example.test#some-private-decision-point-collection::Safety Impact' (version 2.0.0) doesn't have a value with key 'S'".to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0/values/0".to_string(),
}]);
let case_08 = Err(vec![ValidationError {
message: "The values for SSVC decision point 'ssvc//.example.test$en-GB::Safety Impact' (version 2.0.0) are not in correct order".to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0/values/2".to_string(),
}]);
let case_09 = Err(vec![ValidationError {
message: "The values for SSVC decision point 'ssvc//.example.test$en-CA::Safety Impact' (version 2.0.0) are not in correct order".to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0/values/2".to_string(),
}]);
let case_21 = Err(vec![ValidationError {
message: "Invalid SSVC namespace: Reserved namespace 'invalid' must not be used".to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0/namespace".to_string(),
}]);
let case_16 = case_06.clone();
let case_19 = Err(vec![ValidationError {
message: "The values for SSVC decision point 'ssvc//.example.test$de-DE::Safety Impact' (version 2.0.0) are not in correct order".to_string(),
instance_path: "/vulnerabilities/0/metrics/0/content/ssvc_v2/selections/0/values/2".to_string(),
}]);
TESTS_2_1.test_6_1_48.expect(
case_01,
case_02,
case_03,
case_04,
case_05,
case_06,
case_07,
case_08,
case_09,
case_21,
Ok(()),
Ok(()),
Ok(()),
Ok(()),
Ok(()),
case_16, Ok(()),
Ok(()),
case_19, Ok(()),
);
}
}