Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ This is work-in-progress.
If you want to build `csaf-validator` on your own, please install Rust (see https://rustup.rs) and then run

```bash
# make sure, submodules are up-to-date
# make sure submodules are up-to-date
git submodule init
git submodule update --remote

# run the tests
Expand All @@ -35,7 +36,7 @@ Arguments:

Options:
-c, --csaf-version <CSAF_VERSION> Version of CSAF to use [default: 2.0]
-p, --profile <PROFILE> The profile to use [default: basic]
-p, --preset <PRESET> The validation preset (formerly known as "profile") to use [default: basic]
-o, --only-test <ONLY_TEST> Run only the selected test
-h, --help Print help
-V, --version Print version
Expand All @@ -48,7 +49,7 @@ Some examples to use are included below. Please note that the validation is not
csaf-validator --csaf-version 2.0 my-csaf-2-0-document.json

# validate a CSAF 2.0 document with profile full
csaf-validator --csaf-version 2.0 --profile full my-csaf-2-0-document.json
csaf-validator --csaf-version 2.0 --preset full my-csaf-2-0-document.json

# validate a CSAF 2.1 document with a specific test
csaf-validator --csaf-version 2.1 --only-test 6.1.34 my-csaf-2-1-document.json
Expand Down
2 changes: 1 addition & 1 deletion csaf
Submodule csaf updated 128 files
10 changes: 5 additions & 5 deletions csaf-lib/src/csaf/csaf2_0/validation.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use super::product_helper::*;
use super::schema::CommonSecurityAdvisoryFramework;
use crate::csaf::validation::{Test, Validatable, ValidationProfile};
use crate::csaf::validation::{Test, Validatable, ValidationPreset};
use std::collections::{HashMap, HashSet};
use crate::csaf::helpers::find_duplicates;

impl Validatable<CommonSecurityAdvisoryFramework> for CommonSecurityAdvisoryFramework {
fn profiles(&self) -> HashMap<ValidationProfile, Vec<&str>> {
fn presets(&self) -> HashMap<ValidationPreset, Vec<&str>> {
HashMap::from([
(ValidationProfile::Basic, Vec::from(["6.1.1", "6.1.2"])),
(ValidationProfile::Extended, Vec::from(["6.1.1", "6.1.2"])),
(ValidationProfile::Full, Vec::from(["6.1.1", "6.1.2"])),
(ValidationPreset::Basic, Vec::from(["6.1.1", "6.1.2"])),
(ValidationPreset::Extended, Vec::from(["6.1.1", "6.1.2"])),
(ValidationPreset::Full, Vec::from(["6.1.1", "6.1.2"])),
])
}

Expand Down
10 changes: 5 additions & 5 deletions csaf-lib/src/csaf/csaf2_1/validation.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use super::product_helper::*;
use super::schema::CommonSecurityAdvisoryFramework;
use crate::csaf::helpers::find_duplicates;
use crate::csaf::validation::{Test, Validatable, ValidationProfile};
use crate::csaf::validation::{Test, Validatable, ValidationPreset};
use std::collections::{HashMap, HashSet};

impl Validatable<CommonSecurityAdvisoryFramework> for CommonSecurityAdvisoryFramework {
fn profiles(&self) -> HashMap<ValidationProfile, Vec<&str>> {
fn presets(&self) -> HashMap<ValidationPreset, Vec<&str>> {
HashMap::from([
(
ValidationProfile::Basic,
ValidationPreset::Basic,
Vec::from(["6.1.1", "6.1.2", "6.1.34"]),
),
(ValidationProfile::Extended, Vec::from(["6.1.1", "6.1.2"])),
(ValidationProfile::Full, Vec::from(["6.1.1", "6.1.2"])),
(ValidationPreset::Extended, Vec::from(["6.1.1", "6.1.2"])),
(ValidationPreset::Full, Vec::from(["6.1.1", "6.1.2"])),
])
}

Expand Down
34 changes: 17 additions & 17 deletions csaf-lib/src/csaf/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@ use std::str::FromStr;
pub enum ValidationError {}

#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum ValidationProfile {
pub enum ValidationPreset {
Basic,
Extended,
Full,
}

impl FromStr for ValidationProfile {
impl FromStr for ValidationPreset {
type Err = ();

fn from_str(input: &str) -> Result<ValidationProfile, Self::Err> {
fn from_str(input: &str) -> Result<ValidationPreset, Self::Err> {
match input {
"basic" => Ok(ValidationProfile::Basic),
"extended" => Ok(ValidationProfile::Extended),
"full" => Ok(ValidationProfile::Full),
"basic" => Ok(ValidationPreset::Basic),
"extended" => Ok(ValidationPreset::Extended),
"full" => Ok(ValidationPreset::Full),
_ => Err(()),
}
}
}

pub trait Validate {
/// Validates this object according to a validation profile
fn validate_profile(&'static self, profile: ValidationProfile);
/// Validates this object according to a validation preset
fn validate_preset(&'static self, preset: ValidationPreset);

/// Validates this object according to a specific test ID.
fn validate_by_test(&self, version: &str);
Expand All @@ -38,35 +38,35 @@ pub type Test<VersionedDocument> =
/// This trait MUST be implemented by the struct that represents a CSAF document
/// in the respective version.
///
/// It can then be used to validate documents with either [validate_by_profile] or [validate_by_test].
/// It can then be used to validate documents with either [validate_by_preset] or [validate_by_test].
pub trait Validatable<VersionedDocument> {
/// Returns a hashmap containing the test ID per profile
fn profiles(&self) -> HashMap<ValidationProfile, Vec<&str>>;
/// Returns a hashmap containing the test ID per preset
fn presets(&self) -> HashMap<ValidationPreset, Vec<&str>>;

/// Returns a hashmap containing the test function per test ID
fn tests(&self) -> HashMap<&str, Test<VersionedDocument>>;

fn doc(&self) -> &VersionedDocument;
}

/// Executes all tests of the specified [profile] against the [target]
/// Executes all tests of the specified [preset] against the [target]
/// (which is of type [VersionedDocument], e.g. a CSAF 2.0 document).
pub fn validate_by_profile<VersionedDocument>(
pub fn validate_by_preset<VersionedDocument>(
target: &impl Validatable<VersionedDocument>,
profile: ValidationProfile,
preset: ValidationPreset,
) {
println!("Validating document with {:?} profile... \n", profile);
println!("Validating document with {:?} preset... \n", preset);

// Loop through tests
if let Some(tests) = target.profiles().get(&profile) {
if let Some(tests) = target.presets().get(&preset) {
for test_id in tests {
println!("Executing Test {}... ", test_id);
validate_by_test(target, test_id);

println!()
}
} else {
println!("No tests found for profile")
println!("No tests found for preset")
}
}

Expand Down
16 changes: 10 additions & 6 deletions csaf-validator/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::str::FromStr;
use anyhow::{bail, Result};
use csaf_lib::csaf::csaf2_0::loader::load_document as load_document_2_0;
use csaf_lib::csaf::csaf2_1::loader::load_document as load_document_2_1;
use csaf_lib::csaf::validation::{validate_by_profile, validate_by_test, ValidationProfile};
use csaf_lib::csaf::validation::{validate_by_preset, validate_by_test, ValidationPreset};
use clap::Parser;

/// A validator for CSAF documents
Expand All @@ -15,9 +16,9 @@ struct Args {
#[arg(short, long, default_value = "2.0")]
csaf_version: String,

/// The profile to use
/// The validation preset (formerly known as "profile") to use
#[arg(short, long, default_value = "basic")]
profile: String,
preset: String,

/// Run only the selected test
#[arg(short, long)]
Expand All @@ -26,7 +27,10 @@ struct Args {

fn main() -> Result<()> {
let args = Args::parse();
let profile = ValidationProfile::Basic;
let preset = match ValidationPreset::from_str(args.preset.as_str()) {
Ok(preset) => preset,
Err(_) => bail!(format!("Invalid validation preset: {}", args.preset)),
};

// TODO: it would be nice to return the validatable from this match, but this is beyond my
// rust generics knowledge, so a little bit of duplicate code here
Expand All @@ -45,10 +49,10 @@ fn main() -> Result<()> {
} else {
let result = match args.csaf_version.as_str() {
"2.0" => {
validate_by_profile(&load_document_2_0(args.path.as_str())?, profile)
validate_by_preset(&load_document_2_0(args.path.as_str())?, preset)
}
"2.1" => {
validate_by_profile(&load_document_2_1(args.path.as_str())?, profile)
validate_by_preset(&load_document_2_1(args.path.as_str())?, preset)
}
_ => bail!("invalid version"),
};
Expand Down