libverify_core/
profile.rs1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5use crate::control::{ControlFinding, ControlId};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct SeverityLabels {
10 pub info: String,
11 pub warning: String,
12 pub error: String,
13}
14
15impl Default for SeverityLabels {
16 fn default() -> Self {
17 Self {
18 info: "compliant".to_string(),
19 warning: "observation".to_string(),
20 error: "exception".to_string(),
21 }
22 }
23}
24
25impl SeverityLabels {
26 pub fn label_for(&self, severity: FindingSeverity) -> &str {
27 match severity {
28 FindingSeverity::Info => &self.info,
29 FindingSeverity::Warning => &self.warning,
30 FindingSeverity::Error => &self.error,
31 }
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
37#[serde(rename_all = "snake_case")]
38pub enum FindingSeverity {
39 Info,
40 Warning,
41 Error,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
46#[serde(rename_all = "snake_case")]
47pub enum GateDecision {
48 Pass,
49 Review,
50 Fail,
51}
52
53impl GateDecision {
54 pub fn as_str(&self) -> &'static str {
55 match self {
56 Self::Pass => "pass",
57 Self::Review => "review",
58 Self::Fail => "fail",
59 }
60 }
61}
62
63impl fmt::Display for GateDecision {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 f.write_str(self.as_str())
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub struct ProfileOutcome {
72 pub control_id: ControlId,
73 pub severity: FindingSeverity,
74 pub decision: GateDecision,
75 pub rationale: String,
76}
77
78pub trait ControlProfile {
80 fn name(&self) -> &str;
81 fn map(&self, finding: &ControlFinding) -> ProfileOutcome;
82 fn severity_labels(&self) -> SeverityLabels {
83 SeverityLabels::default()
84 }
85}
86
87pub fn apply_profile(
89 profile: &dyn ControlProfile,
90 findings: &[ControlFinding],
91) -> Vec<ProfileOutcome> {
92 findings
93 .iter()
94 .map(|finding| profile.map(finding))
95 .collect()
96}