use super::{ComplianceChecker, ComplianceLevel, NormalizedSbom, Violation};
pub(crate) struct ComplianceContext<'a> {
pub(crate) checker: &'a ComplianceChecker,
pub(crate) sbom: &'a NormalizedSbom,
}
impl<'a> ComplianceContext<'a> {
pub(crate) const fn new(checker: &'a ComplianceChecker, sbom: &'a NormalizedSbom) -> Self {
Self { checker, sbom }
}
}
pub(crate) trait StandardChecker {
fn level(&self) -> ComplianceLevel;
fn check(&self, ctx: &ComplianceContext) -> Vec<Violation>;
}
pub(crate) struct GenericChecker {
level: ComplianceLevel,
}
impl GenericChecker {
pub(crate) const fn new(level: ComplianceLevel) -> Self {
Self { level }
}
}
impl StandardChecker for GenericChecker {
fn level(&self) -> ComplianceLevel {
self.level
}
fn check(&self, ctx: &ComplianceContext) -> Vec<Violation> {
let checker = ctx.checker;
let sbom = ctx.sbom;
let mut violations = Vec::new();
checker.check_document_metadata(sbom, &mut violations);
checker.check_components(sbom, &mut violations);
checker.check_dependencies(sbom, &mut violations);
checker.check_vulnerability_metadata(sbom, &mut violations);
checker.check_format_specific(sbom, &mut violations);
if checker.level.is_cra() {
checker.check_cra_gaps(sbom, &mut violations);
checker.check_hardware_components(sbom, &mut violations);
}
violations
}
}
macro_rules! dedicated_checker {
($name:ident, $level:expr, $method:ident) => {
pub(crate) struct $name;
impl StandardChecker for $name {
fn level(&self) -> ComplianceLevel {
$level
}
fn check(&self, ctx: &ComplianceContext) -> Vec<Violation> {
let mut violations = Vec::new();
ctx.checker.$method(ctx.sbom, &mut violations);
violations
}
}
};
}
dedicated_checker!(NistSsdfChecker, ComplianceLevel::NistSsdf, check_nist_ssdf);
dedicated_checker!(Eo14028Checker, ComplianceLevel::Eo14028, check_eo14028);
dedicated_checker!(Cnsa2Checker, ComplianceLevel::Cnsa2, check_cnsa2);
dedicated_checker!(NistPqcChecker, ComplianceLevel::NistPqc, check_nist_pqc);
dedicated_checker!(
BsiTr03183Checker,
ComplianceLevel::BsiTr03183_2,
check_bsi_tr_03183_2
);
dedicated_checker!(
CraOssStewardChecker,
ComplianceLevel::CraOssSteward,
check_cra_oss_steward
);
dedicated_checker!(
EuccSubstantialChecker,
ComplianceLevel::EuccSubstantial,
check_eucc_substantial
);
dedicated_checker!(EuAiActChecker, ComplianceLevel::EuAiAct, check_eu_ai_act);
dedicated_checker!(
BsiSbomForAiChecker,
ComplianceLevel::BsiSbomForAi,
check_bsi_sbom_for_ai
);
pub(crate) fn checker_for(level: ComplianceLevel) -> Box<dyn StandardChecker> {
match level {
ComplianceLevel::NistSsdf => Box::new(NistSsdfChecker),
ComplianceLevel::Eo14028 => Box::new(Eo14028Checker),
ComplianceLevel::Cnsa2 => Box::new(Cnsa2Checker),
ComplianceLevel::NistPqc => Box::new(NistPqcChecker),
ComplianceLevel::BsiTr03183_2 => Box::new(BsiTr03183Checker),
ComplianceLevel::CraOssSteward => Box::new(CraOssStewardChecker),
ComplianceLevel::EuccSubstantial => Box::new(EuccSubstantialChecker),
ComplianceLevel::EuAiAct => Box::new(EuAiActChecker),
ComplianceLevel::BsiSbomForAi => Box::new(BsiSbomForAiChecker),
other => Box::new(GenericChecker::new(other)),
}
}