sbom_tools/tui/app_states/
compliance.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
5pub enum PolicyPreset {
6 #[default]
7 Enterprise,
8 Strict,
9 Permissive,
10 Cra,
12 Ntia,
14 Fda,
16 NistSsdf,
18 Eo14028,
20 Cnsa2,
22 NistPqc,
24 BsiTr03183_2,
26 CraOssSteward,
28 EuccSubstantial,
30 EuAiAct,
32 BsiSbomForAi,
34}
35
36impl PolicyPreset {
37 pub const fn next(self) -> Self {
38 match self {
39 Self::Enterprise => Self::Strict,
40 Self::Strict => Self::Permissive,
41 Self::Permissive => Self::Cra,
42 Self::Cra => Self::Ntia,
43 Self::Ntia => Self::Fda,
44 Self::Fda => Self::NistSsdf,
45 Self::NistSsdf => Self::Eo14028,
46 Self::Eo14028 => Self::Cnsa2,
47 Self::Cnsa2 => Self::NistPqc,
48 Self::NistPqc => Self::BsiTr03183_2,
49 Self::BsiTr03183_2 => Self::CraOssSteward,
50 Self::CraOssSteward => Self::EuccSubstantial,
51 Self::EuccSubstantial => Self::EuAiAct,
52 Self::EuAiAct => Self::BsiSbomForAi,
53 Self::BsiSbomForAi => Self::Enterprise,
54 }
55 }
56
57 pub const fn label(self) -> &'static str {
58 match self {
59 Self::Enterprise => "Enterprise",
60 Self::Strict => "Strict",
61 Self::Permissive => "Permissive",
62 Self::Cra => "EU CRA",
63 Self::Ntia => "NTIA",
64 Self::Fda => "FDA",
65 Self::NistSsdf => "NIST SSDF",
66 Self::Eo14028 => "EO 14028",
67 Self::Cnsa2 => "CNSA 2.0",
68 Self::NistPqc => "NIST PQC",
69 Self::BsiTr03183_2 => "BSI TR-03183-2",
70 Self::CraOssSteward => "CRA OSS Steward",
71 Self::EuccSubstantial => "EUCC",
72 Self::EuAiAct => "EU AI Act",
73 Self::BsiSbomForAi => "BSI/G7 SBOM-for-AI",
74 }
75 }
76
77 pub const fn is_standards_based(self) -> bool {
79 matches!(
80 self,
81 Self::Cra
82 | Self::Ntia
83 | Self::Fda
84 | Self::NistSsdf
85 | Self::Eo14028
86 | Self::Cnsa2
87 | Self::NistPqc
88 | Self::BsiTr03183_2
89 | Self::CraOssSteward
90 | Self::EuccSubstantial
91 | Self::EuAiAct
92 | Self::BsiSbomForAi
93 )
94 }
95
96 pub const fn compliance_level(self) -> Option<crate::quality::ComplianceLevel> {
98 match self {
99 Self::Cra => Some(crate::quality::ComplianceLevel::CraPhase2),
100 Self::Ntia => Some(crate::quality::ComplianceLevel::NtiaMinimum),
101 Self::Fda => Some(crate::quality::ComplianceLevel::FdaMedicalDevice),
102 Self::NistSsdf => Some(crate::quality::ComplianceLevel::NistSsdf),
103 Self::Eo14028 => Some(crate::quality::ComplianceLevel::Eo14028),
104 Self::Cnsa2 => Some(crate::quality::ComplianceLevel::Cnsa2),
105 Self::NistPqc => Some(crate::quality::ComplianceLevel::NistPqc),
106 Self::BsiTr03183_2 => Some(crate::quality::ComplianceLevel::BsiTr03183_2),
107 Self::CraOssSteward => Some(crate::quality::ComplianceLevel::CraOssSteward),
108 Self::EuccSubstantial => Some(crate::quality::ComplianceLevel::EuccSubstantial),
109 Self::EuAiAct => Some(crate::quality::ComplianceLevel::EuAiAct),
110 Self::BsiSbomForAi => Some(crate::quality::ComplianceLevel::BsiSbomForAi),
111 _ => None,
112 }
113 }
114}
115
116#[derive(Debug, Clone, Default)]
118pub struct PolicyComplianceState {
119 pub policy_preset: PolicyPreset,
121 pub result: Option<crate::tui::security::ComplianceResult>,
123 pub selected_violation: usize,
125 pub checked: bool,
127 pub show_details: bool,
129}
130
131impl PolicyComplianceState {
132 pub fn new() -> Self {
133 Self::default()
134 }
135
136 pub fn toggle_policy(&mut self) {
137 self.policy_preset = self.policy_preset.next();
138 self.result = None; self.checked = false;
140 }
141
142 pub const fn toggle_details(&mut self) {
143 self.show_details = !self.show_details;
144 }
145
146 pub fn passes(&self) -> bool {
147 self.result.as_ref().is_none_or(|r| r.passes)
148 }
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
153pub enum ComplianceSeverityFilter {
154 #[default]
156 All,
157 ErrorsOnly,
159 WarningsAndAbove,
161}
162
163impl ComplianceSeverityFilter {
164 pub const fn next(self) -> Self {
166 match self {
167 Self::All => Self::ErrorsOnly,
168 Self::ErrorsOnly => Self::WarningsAndAbove,
169 Self::WarningsAndAbove => Self::All,
170 }
171 }
172
173 pub const fn label(self) -> &'static str {
175 match self {
176 Self::All => "All",
177 Self::ErrorsOnly => "Errors",
178 Self::WarningsAndAbove => "Warn+",
179 }
180 }
181
182 pub fn matches(self, severity: crate::quality::ViolationSeverity) -> bool {
184 match self {
185 Self::All => true,
186 Self::ErrorsOnly => {
187 matches!(severity, crate::quality::ViolationSeverity::Error)
188 }
189 Self::WarningsAndAbove => {
190 matches!(
191 severity,
192 crate::quality::ViolationSeverity::Error
193 | crate::quality::ViolationSeverity::Warning
194 )
195 }
196 }
197 }
198}
199
200#[derive(Debug, Clone)]
202pub struct DiffComplianceState {
203 pub selected_standard: usize,
205 pub selected_violation: usize,
207 pub scroll_offset: usize,
209 pub view_mode: DiffComplianceViewMode,
211 pub show_detail: bool,
213 pub severity_filter: ComplianceSeverityFilter,
215 pub group_by_element: bool,
217 pub expanded_groups: std::collections::HashSet<String>,
219}
220
221#[derive(Debug, Clone, Copy, PartialEq, Eq)]
223pub enum DiffComplianceViewMode {
224 Overview,
226 NewViolations,
228 ResolvedViolations,
230 OldViolations,
232 NewSbomViolations,
234}
235
236impl Default for DiffComplianceState {
237 fn default() -> Self {
238 Self {
239 selected_standard: 3,
240 selected_violation: 0,
241 scroll_offset: 0,
242 show_detail: false,
243 view_mode: DiffComplianceViewMode::Overview,
244 severity_filter: ComplianceSeverityFilter::default(),
245 group_by_element: false,
246 expanded_groups: std::collections::HashSet::new(),
247 }
248 }
249}
250
251impl DiffComplianceState {
252 pub fn new() -> Self {
253 Self::default()
254 }
255
256 pub const fn next_standard(&mut self) {
257 let count = crate::quality::ComplianceLevel::all().len();
258 self.selected_standard = (self.selected_standard + 1) % count;
259 self.selected_violation = 0;
260 self.scroll_offset = 0;
261 }
262
263 pub const fn prev_standard(&mut self) {
264 let count = crate::quality::ComplianceLevel::all().len();
265 self.selected_standard = if self.selected_standard == 0 {
266 count - 1
267 } else {
268 self.selected_standard - 1
269 };
270 self.selected_violation = 0;
271 self.scroll_offset = 0;
272 }
273
274 pub const fn next_view_mode(&mut self) {
275 self.view_mode = match self.view_mode {
276 DiffComplianceViewMode::Overview => DiffComplianceViewMode::NewViolations,
277 DiffComplianceViewMode::NewViolations => DiffComplianceViewMode::ResolvedViolations,
278 DiffComplianceViewMode::ResolvedViolations => DiffComplianceViewMode::OldViolations,
279 DiffComplianceViewMode::OldViolations => DiffComplianceViewMode::NewSbomViolations,
280 DiffComplianceViewMode::NewSbomViolations => DiffComplianceViewMode::Overview,
281 };
282 self.selected_violation = 0;
283 self.scroll_offset = 0;
284 }
285
286 pub const fn select_next(&mut self, max: usize) {
287 if max > 0 && self.selected_violation + 1 < max {
288 self.selected_violation += 1;
289 }
290 }
291
292 pub const fn select_prev(&mut self) {
293 if self.selected_violation > 0 {
294 self.selected_violation -= 1;
295 }
296 }
297
298 pub const fn toggle_severity_filter(&mut self) {
300 self.severity_filter = self.severity_filter.next();
301 self.selected_violation = 0;
302 self.scroll_offset = 0;
303 }
304
305 pub fn toggle_group_by_element(&mut self) {
307 self.group_by_element = !self.group_by_element;
308 self.selected_violation = 0;
309 self.scroll_offset = 0;
310 }
311}