use clap::ValueEnum;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(
Debug, Clone, Copy, Default, PartialEq, Eq, ValueEnum, Serialize, Deserialize, JsonSchema,
)]
#[non_exhaustive]
pub enum ReportFormat {
#[default]
Auto,
Tui,
#[value(alias = "side-by-side")]
SideBySide,
Json,
Sarif,
Markdown,
Html,
Summary,
Table,
Csv,
}
impl std::fmt::Display for ReportFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Auto => write!(f, "auto"),
Self::Tui => write!(f, "tui"),
Self::SideBySide => write!(f, "side-by-side"),
Self::Json => write!(f, "json"),
Self::Sarif => write!(f, "sarif"),
Self::Markdown => write!(f, "markdown"),
Self::Html => write!(f, "html"),
Self::Summary => write!(f, "summary"),
Self::Table => write!(f, "table"),
Self::Csv => write!(f, "csv"),
}
}
}
#[derive(
Debug, Clone, Copy, Default, PartialEq, Eq, ValueEnum, Serialize, Deserialize, JsonSchema,
)]
pub enum ReportType {
#[default]
All,
Components,
Dependencies,
OssDependencies,
Licenses,
Vulnerabilities,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum MinSeverity {
Low,
Medium,
High,
Critical,
}
impl MinSeverity {
#[must_use]
pub fn parse(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"low" => Some(Self::Low),
"medium" => Some(Self::Medium),
"high" => Some(Self::High),
"critical" => Some(Self::Critical),
_ => None,
}
}
#[must_use]
pub fn meets_threshold(&self, severity: &str) -> bool {
let sev = match severity.to_lowercase().as_str() {
"critical" => Self::Critical,
"high" => Self::High,
"medium" => Self::Medium,
"low" => Self::Low,
_ => return true, };
sev >= *self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportConfig {
pub report_types: Vec<ReportType>,
pub include_unchanged: bool,
pub max_items: Option<usize>,
pub include_field_changes: bool,
pub title: Option<String>,
pub metadata: ReportMetadata,
pub only_changes: bool,
pub min_severity: Option<MinSeverity>,
#[serde(skip)]
pub old_cra_compliance: Option<crate::quality::ComplianceResult>,
#[serde(skip)]
pub new_cra_compliance: Option<crate::quality::ComplianceResult>,
#[serde(skip)]
pub view_cra_compliance: Option<crate::quality::ComplianceResult>,
}
impl Default for ReportConfig {
fn default() -> Self {
Self {
report_types: vec![ReportType::All],
include_unchanged: false,
max_items: None,
include_field_changes: true,
title: None,
metadata: ReportMetadata::default(),
only_changes: false,
min_severity: None,
old_cra_compliance: None,
new_cra_compliance: None,
view_cra_compliance: None,
}
}
}
impl ReportConfig {
#[must_use]
pub fn all() -> Self {
Self::default()
}
#[must_use]
pub fn with_types(types: Vec<ReportType>) -> Self {
Self {
report_types: types,
..Default::default()
}
}
#[must_use]
pub fn includes(&self, report_type: ReportType) -> bool {
self.report_types.contains(&ReportType::All) || self.report_types.contains(&report_type)
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ReportMetadata {
pub old_sbom_path: Option<String>,
pub new_sbom_path: Option<String>,
pub tool_version: String,
pub generated_at: Option<String>,
pub custom: std::collections::HashMap<String, String>,
}
impl ReportMetadata {
#[must_use]
pub fn new() -> Self {
Self {
tool_version: env!("CARGO_PKG_VERSION").to_string(),
..Default::default()
}
}
}