sbom_tools/parsers/
traits.rs1use crate::model::NormalizedSbom;
7use std::path::Path;
8use thiserror::Error;
9
10#[derive(Error, Debug)]
12pub enum ParseError {
13 #[error("IO error: {0}")]
14 IoError(String),
15
16 #[error("JSON parse error: {0}")]
17 JsonError(String),
18
19 #[error("XML parse error: {0}")]
20 XmlError(String),
21
22 #[error("YAML parse error: {0}")]
23 YamlError(String),
24
25 #[error("Invalid SBOM structure: {0}")]
26 InvalidStructure(String),
27
28 #[error("Unsupported format version: {0}")]
29 UnsupportedVersion(String),
30
31 #[error("Unknown SBOM format: {0}")]
32 UnknownFormat(String),
33
34 #[error("Missing required field: {0}")]
35 MissingField(String),
36
37 #[error("Validation error: {0}")]
38 ValidationError(String),
39}
40
41impl From<std::io::Error> for ParseError {
42 fn from(err: std::io::Error) -> Self {
43 ParseError::IoError(err.to_string())
44 }
45}
46
47impl From<serde_json::Error> for ParseError {
48 fn from(err: serde_json::Error) -> Self {
49 ParseError::JsonError(err.to_string())
50 }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
55pub struct FormatConfidence(f32);
56
57impl FormatConfidence {
58 pub const NONE: Self = Self(0.0);
60 pub const LOW: Self = Self(0.25);
62 pub const MEDIUM: Self = Self(0.5);
64 pub const HIGH: Self = Self(0.75);
66 pub const CERTAIN: Self = Self(1.0);
68
69 pub fn new(value: f32) -> Self {
71 Self(value.clamp(0.0, 1.0))
72 }
73
74 pub fn value(&self) -> f32 {
76 self.0
77 }
78
79 pub fn can_parse(&self) -> bool {
81 self.0 >= 0.25
82 }
83}
84
85impl Default for FormatConfidence {
86 fn default() -> Self {
87 Self::NONE
88 }
89}
90
91#[derive(Debug, Clone)]
93pub struct FormatDetection {
94 pub confidence: FormatConfidence,
96 pub variant: Option<String>,
98 pub version: Option<String>,
100 pub warnings: Vec<String>,
102}
103
104impl FormatDetection {
105 pub fn no_match() -> Self {
107 Self {
108 confidence: FormatConfidence::NONE,
109 variant: None,
110 version: None,
111 warnings: Vec::new(),
112 }
113 }
114
115 pub fn with_confidence(confidence: FormatConfidence) -> Self {
117 Self {
118 confidence,
119 variant: None,
120 version: None,
121 warnings: Vec::new(),
122 }
123 }
124
125 pub fn variant(mut self, variant: &str) -> Self {
127 self.variant = Some(variant.to_string());
128 self
129 }
130
131 pub fn version(mut self, version: &str) -> Self {
133 self.version = Some(version.to_string());
134 self
135 }
136
137 pub fn warning(mut self, warning: &str) -> Self {
139 self.warnings.push(warning.to_string());
140 self
141 }
142}
143
144pub trait SbomParser {
149 fn parse(&self, path: &Path) -> Result<NormalizedSbom, ParseError> {
151 let content = std::fs::read_to_string(path)?;
152 self.parse_str(&content)
153 }
154
155 fn parse_str(&self, content: &str) -> Result<NormalizedSbom, ParseError>;
157
158 fn supported_versions(&self) -> Vec<&str>;
160
161 fn format_name(&self) -> &str;
163
164 fn detect(&self, content: &str) -> FormatDetection;
169
170 fn can_parse(&self, content: &str) -> bool {
175 self.detect(content).confidence.can_parse()
176 }
177
178 fn confidence(&self, content: &str) -> FormatConfidence {
182 self.detect(content).confidence
183 }
184}