Skip to content

Refactor getter traits for CSAF 2.0 and CSAF 2.1. #25

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 18, 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
123 changes: 118 additions & 5 deletions csaf-lib/src/csaf/csaf2_0/getter_implementations.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::csaf::csaf2_0::schema::{CategoryOfTheRemediation, CommonSecurityAdvisoryFramework, ProductGroup, ProductTree, Remediation, Vulnerability};
use crate::csaf::csaf2_0::schema::{Branch, CategoryOfTheRemediation, CommonSecurityAdvisoryFramework, FullProductNameT, ProductGroup, ProductStatus, ProductTree, Relationship, Remediation, Threat, Vulnerability};
use crate::csaf::csaf2_1::schema::CategoryOfTheRemediation as Remediation21;
use crate::csaf::getter_traits::{CsafTrait, ProductGroupTrait, ProductTreeTrait, RemediationTrait, VulnerabilityTrait};
use crate::csaf::getter_traits::{BranchTrait, CsafTrait, FullProductNameTrait, MetricTrait, ProductGroupTrait, ProductStatusTrait, ProductTreeTrait, RelationshipTrait, RemediationTrait, ThreatTrait, VulnerabilityTrait};
use std::ops::Deref;

impl RemediationTrait for Remediation {
Expand Down Expand Up @@ -34,12 +34,75 @@ impl RemediationTrait for Remediation {
}
}

impl ProductStatusTrait for ProductStatus {
fn get_first_affected(&self) -> Option<Vec<&String>> {
self.first_affected.as_ref().map(|p| (*p).iter().map(|x| x.deref()).collect())
}

fn get_first_fixed(&self) -> Option<Vec<&String>> {
self.first_fixed.as_ref().map(|p| (*p).iter().map(|x| x.deref()).collect())
}

fn get_fixed(&self) -> Option<Vec<&String>> {
self.fixed.as_ref().map(|p| (*p).iter().map(|x| x.deref()).collect())
}

fn get_known_affected(&self) -> Option<Vec<&String>> {
self.known_affected.as_ref().map(|p| (*p).iter().map(|x| x.deref()).collect())
}

fn get_known_not_affected(&self) -> Option<Vec<&String>> {
self.known_not_affected.as_ref().map(|p| (*p).iter().map(|x| x.deref()).collect())
}

fn get_last_affected(&self) -> Option<Vec<&String>> {
self.last_affected.as_ref().map(|p| (*p).iter().map(|x| x.deref()).collect())
}

fn get_recommended(&self) -> Option<Vec<&String>> {
self.recommended.as_ref().map(|p| (*p).iter().map(|x| x.deref()).collect())
}

fn get_under_investigation(&self) -> Option<Vec<&String>> {
self.under_investigation.as_ref().map(|p| (*p).iter().map(|x| x.deref()).collect())
}
}

impl MetricTrait for () {
fn get_products(&self) -> Vec<&String> {
panic!("Metrics are not implemented in CSAF 2.0")
}
}

impl ThreatTrait for Threat {
fn get_product_ids(&self) -> Option<Vec<&String>> {
self.product_ids.as_ref().map(|p| (*p).iter().map(|x| x.deref()).collect())
}
}

impl VulnerabilityTrait for Vulnerability {
type RemediationType = Remediation;
type ProductStatusType = ProductStatus;
// Metrics are not implemented in CSAF 2.0
type MetricType = ();
type ThreatType = Threat;

fn get_remediations(&self) -> Vec<Self::RemediationType> {
self.remediations.clone()
}

fn get_product_status(&self) -> Option<Self::ProductStatusType> {
self.product_status.clone()
}

fn get_metrics(&self) -> Option<Vec<Self::MetricType>> {
// Metrics are not implemented in CSAF 2.0
None
}

fn get_threats(&self) -> Vec<Self::ThreatType> {
self.threats.clone()
}
}

impl CsafTrait for CommonSecurityAdvisoryFramework {
Expand All @@ -56,10 +119,38 @@ impl CsafTrait for CommonSecurityAdvisoryFramework {
}

impl ProductTreeTrait for ProductTree {
type BranchType = Branch;
type ProductGroupType = ProductGroup;
type RelationshipType = Relationship;
type FullProductNameType = FullProductNameT;

fn get_branches(&self) -> Option<&Vec<Self::BranchType>> {
self.branches.as_ref().map(|branches| branches.deref())
}

fn get_product_groups(&self) -> &Vec<Self::ProductGroupType> {
&self.product_groups
}

fn get_product_groups(&self) -> Vec<Self::ProductGroupType> {
self.product_groups.clone()
fn get_relationships(&self) -> &Vec<Self::RelationshipType> {
&self.relationships
}

fn get_full_product_names(&self) -> &Vec<Self::FullProductNameType> {
&self.full_product_names
}
}

impl BranchTrait for Branch {
type BranchType = Branch;
type FullProductNameType = FullProductNameT;

fn get_branches(&self) -> Option<&Vec<Self::BranchType>> {
self.branches.as_ref().map(|branches| branches.deref())
}

fn get_product(&self) -> Option<&Self::FullProductNameType> {
self.product.as_ref()
}
}

Expand All @@ -71,4 +162,26 @@ impl ProductGroupTrait for ProductGroup {
fn get_product_ids(&self) -> Vec<&String> {
self.product_ids.iter().map(|x| x.deref()).collect()
}
}
}

impl RelationshipTrait for Relationship {
type FullProductNameType = FullProductNameT;

fn get_product_reference(&self) -> &String {
self.product_reference.deref()
}

fn get_relates_to_product_reference(&self) -> &String {
self.relates_to_product_reference.deref()
}

fn get_full_product_name(&self) -> &Self::FullProductNameType {
&self.full_product_name
}
}

impl FullProductNameTrait for FullProductNameT {
fn get_product_id(&self) -> &String {
self.product_id.deref()
}
}
1 change: 0 additions & 1 deletion csaf-lib/src/csaf/csaf2_0/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
pub mod loader;
mod product_helper;
pub mod schema;
pub mod validation;
pub mod getter_implementations;
118 changes: 0 additions & 118 deletions csaf-lib/src/csaf/csaf2_0/product_helper.rs

This file was deleted.

45 changes: 6 additions & 39 deletions csaf-lib/src/csaf/csaf2_0/validation.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use super::product_helper::*;
use super::schema::CommonSecurityAdvisoryFramework;
use crate::csaf::validation::{Test, Validatable, ValidationPreset};
use std::collections::{HashMap, HashSet};
use crate::csaf::helpers::find_duplicates;
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;

impl Validatable<CommonSecurityAdvisoryFramework> for CommonSecurityAdvisoryFramework {
fn presets(&self) -> HashMap<ValidationPreset, Vec<&str>> {
Expand Down Expand Up @@ -32,48 +30,17 @@ impl Validatable<CommonSecurityAdvisoryFramework> for CommonSecurityAdvisoryFram
}
}

pub fn test_6_01_01_missing_definition_of_product_id(
doc: &CommonSecurityAdvisoryFramework,
) -> Result<(), String> {
let definitions = HashSet::from_iter(gather_product_definitions(doc).iter().copied());
let references = gather_product_references(&doc);

let mut missing = references.difference(&definitions).collect::<Vec<_>>();
missing.sort();

if missing.is_empty() {
Ok(())
} else {
Err(format!("Missing definitions: {:?}", missing))
}
}

pub fn test_6_01_02_multiple_definition_of_product_id(
doc: &CommonSecurityAdvisoryFramework,
) -> Result<(), String> {
let definitions = gather_product_definitions(doc);
let duplicates = find_duplicates(definitions);

if duplicates.is_empty() {
Ok(())
} else {
Err(format!("Duplicate definitions: {:?}", duplicates))
}
}

#[cfg(test)]
mod tests {
use crate::csaf::csaf2_0::validation::test_6_01_02_multiple_definition_of_product_id;
use crate::csaf::csaf2_0::{
loader::load_document, validation::test_6_01_01_missing_definition_of_product_id,
};
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: [ProductIdT(\"CSAFPID-9080700\"), ProductIdT(\"CSAFPID-9080701\")]"))
Err(String::from("Missing definitions: [\"CSAFPID-9080700\", \"CSAFPID-9080701\"]"))
)
}

Expand All @@ -83,7 +50,7 @@ mod tests {
assert_eq!(
test_6_01_02_multiple_definition_of_product_id(&doc),
Err(String::from(
"Duplicate definitions: [ProductIdT(\"CSAFPID-9080700\")]"
"Duplicate definitions: [\"CSAFPID-9080700\"]"
))
)
}
Expand Down
Loading