1use clap::ValueEnum;
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, ValueEnum, Serialize, Deserialize, JsonSchema)]
9#[non_exhaustive]
10pub enum ReportFormat {
11 #[default]
13 Auto,
14 Tui,
16 #[value(alias = "side-by-side")]
18 SideBySide,
19 Json,
21 Sarif,
23 Markdown,
25 Html,
27 Summary,
29 Table,
31 Csv,
33}
34
35impl std::fmt::Display for ReportFormat {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 Self::Auto => write!(f, "auto"),
39 Self::Tui => write!(f, "tui"),
40 Self::SideBySide => write!(f, "side-by-side"),
41 Self::Json => write!(f, "json"),
42 Self::Sarif => write!(f, "sarif"),
43 Self::Markdown => write!(f, "markdown"),
44 Self::Html => write!(f, "html"),
45 Self::Summary => write!(f, "summary"),
46 Self::Table => write!(f, "table"),
47 Self::Csv => write!(f, "csv"),
48 }
49 }
50}
51
52#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, ValueEnum, Serialize, Deserialize, JsonSchema)]
54pub enum ReportType {
55 #[default]
57 All,
58 Components,
60 Dependencies,
62 OssDependencies,
64 Licenses,
66 Vulnerabilities,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
72pub enum MinSeverity {
73 Low,
74 Medium,
75 High,
76 Critical,
77}
78
79impl MinSeverity {
80 #[must_use]
82 pub fn parse(s: &str) -> Option<Self> {
83 match s.to_lowercase().as_str() {
84 "low" => Some(Self::Low),
85 "medium" => Some(Self::Medium),
86 "high" => Some(Self::High),
87 "critical" => Some(Self::Critical),
88 _ => None,
89 }
90 }
91
92 #[must_use]
94 pub fn meets_threshold(&self, severity: &str) -> bool {
95 let sev = match severity.to_lowercase().as_str() {
96 "critical" => Self::Critical,
97 "high" => Self::High,
98 "medium" => Self::Medium,
99 "low" => Self::Low,
100 _ => return true, };
102 sev >= *self
103 }
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct ReportConfig {
109 pub report_types: Vec<ReportType>,
111 pub include_unchanged: bool,
113 pub max_items: Option<usize>,
115 pub include_field_changes: bool,
117 pub title: Option<String>,
119 pub metadata: ReportMetadata,
121 pub only_changes: bool,
123 pub min_severity: Option<MinSeverity>,
125 #[serde(skip)]
127 pub old_cra_compliance: Option<crate::quality::ComplianceResult>,
128 #[serde(skip)]
130 pub new_cra_compliance: Option<crate::quality::ComplianceResult>,
131 #[serde(skip)]
133 pub view_cra_compliance: Option<crate::quality::ComplianceResult>,
134}
135
136impl Default for ReportConfig {
137 fn default() -> Self {
138 Self {
139 report_types: vec![ReportType::All],
140 include_unchanged: false,
141 max_items: None,
142 include_field_changes: true,
143 title: None,
144 metadata: ReportMetadata::default(),
145 only_changes: false,
146 min_severity: None,
147 old_cra_compliance: None,
148 new_cra_compliance: None,
149 view_cra_compliance: None,
150 }
151 }
152}
153
154impl ReportConfig {
155 #[must_use]
157 pub fn all() -> Self {
158 Self::default()
159 }
160
161 #[must_use]
163 pub fn with_types(types: Vec<ReportType>) -> Self {
164 Self {
165 report_types: types,
166 ..Default::default()
167 }
168 }
169
170 #[must_use]
172 pub fn includes(&self, report_type: ReportType) -> bool {
173 self.report_types.contains(&ReportType::All) || self.report_types.contains(&report_type)
174 }
175}
176
177#[derive(Debug, Clone, Default, Serialize, Deserialize)]
179pub struct ReportMetadata {
180 pub old_sbom_path: Option<String>,
182 pub new_sbom_path: Option<String>,
184 pub tool_version: String,
186 pub generated_at: Option<String>,
188 pub custom: std::collections::HashMap<String, String>,
190}
191
192impl ReportMetadata {
193 #[must_use]
194 pub fn new() -> Self {
195 Self {
196 tool_version: env!("CARGO_PKG_VERSION").to_string(),
197 ..Default::default()
198 }
199 }
200}