1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub enum SbomFormat {
9 CycloneDx,
10 Spdx,
11}
12
13impl std::fmt::Display for SbomFormat {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 match self {
16 Self::CycloneDx => write!(f, "CycloneDX"),
17 Self::Spdx => write!(f, "SPDX"),
18 }
19 }
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct DocumentMetadata {
25 pub format: SbomFormat,
27 pub format_version: String,
29 pub spec_version: String,
31 pub serial_number: Option<String>,
33 pub created: DateTime<Utc>,
35 pub creators: Vec<Creator>,
37 pub name: Option<String>,
39 pub security_contact: Option<String>,
41 pub vulnerability_disclosure_url: Option<String>,
43 pub support_end_date: Option<DateTime<Utc>>,
45 pub lifecycle_phase: Option<String>,
47 pub completeness_declaration: CompletenessDeclaration,
49 pub signature: Option<SignatureInfo>,
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
58#[non_exhaustive]
59pub enum CompletenessDeclaration {
60 Complete,
62 IncompleteFirstPartyOnly,
64 IncompleteThirdPartyOnly,
66 Incomplete,
68 #[default]
70 Unknown,
71 NotSpecified,
73}
74
75impl std::fmt::Display for CompletenessDeclaration {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 match self {
78 Self::Complete => write!(f, "complete"),
79 Self::IncompleteFirstPartyOnly => write!(f, "incomplete (first-party only)"),
80 Self::IncompleteThirdPartyOnly => write!(f, "incomplete (third-party only)"),
81 Self::Incomplete => write!(f, "incomplete"),
82 Self::Unknown => write!(f, "unknown"),
83 Self::NotSpecified => write!(f, "not specified"),
84 }
85 }
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct SignatureInfo {
91 pub algorithm: String,
93 pub has_value: bool,
95}
96
97impl Default for DocumentMetadata {
98 fn default() -> Self {
99 Self {
100 format: SbomFormat::CycloneDx,
101 format_version: String::new(),
102 spec_version: String::new(),
103 serial_number: None,
104 created: Utc::now(),
105 creators: Vec::new(),
106 name: None,
107 security_contact: None,
108 vulnerability_disclosure_url: None,
109 support_end_date: None,
110 lifecycle_phase: None,
111 completeness_declaration: CompletenessDeclaration::default(),
112 signature: None,
113 }
114 }
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct Creator {
120 pub creator_type: CreatorType,
122 pub name: String,
124 pub email: Option<String>,
126}
127
128#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
130pub enum CreatorType {
131 Person,
132 Organization,
133 Tool,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138pub struct Organization {
139 pub name: String,
141 pub urls: Vec<String>,
143 pub contacts: Vec<Contact>,
145}
146
147impl Organization {
148 #[must_use]
150 pub const fn new(name: String) -> Self {
151 Self {
152 name,
153 urls: Vec::new(),
154 contacts: Vec::new(),
155 }
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
161pub struct Contact {
162 pub name: Option<String>,
164 pub email: Option<String>,
166 pub phone: Option<String>,
168}
169
170#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
172#[non_exhaustive]
173pub enum ComponentType {
174 Application,
175 Framework,
176 #[default]
177 Library,
178 Container,
179 OperatingSystem,
180 Device,
181 Firmware,
182 File,
183 Data,
184 MachineLearningModel,
185 Platform,
186 DeviceDriver,
187 Cryptographic,
188 Other(String),
189}
190
191impl std::fmt::Display for ComponentType {
192 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193 match self {
194 Self::Application => write!(f, "application"),
195 Self::Framework => write!(f, "framework"),
196 Self::Library => write!(f, "library"),
197 Self::Container => write!(f, "container"),
198 Self::OperatingSystem => write!(f, "operating-system"),
199 Self::Device => write!(f, "device"),
200 Self::Firmware => write!(f, "firmware"),
201 Self::File => write!(f, "file"),
202 Self::Data => write!(f, "data"),
203 Self::MachineLearningModel => write!(f, "machine-learning-model"),
204 Self::Platform => write!(f, "platform"),
205 Self::DeviceDriver => write!(f, "device-driver"),
206 Self::Cryptographic => write!(f, "cryptographic"),
207 Self::Other(s) => write!(f, "{s}"),
208 }
209 }
210}
211
212#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
214pub struct Hash {
215 pub algorithm: HashAlgorithm,
217 pub value: String,
219}
220
221impl Hash {
222 #[must_use]
224 pub const fn new(algorithm: HashAlgorithm, value: String) -> Self {
225 Self { algorithm, value }
226 }
227}
228
229#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
231pub enum HashAlgorithm {
232 Md5,
233 Sha1,
234 Sha256,
235 Sha384,
236 Sha512,
237 Sha3_256,
238 Sha3_384,
239 Sha3_512,
240 Blake2b256,
241 Blake2b384,
242 Blake2b512,
243 Blake3,
244 Other(String),
245}
246
247impl std::fmt::Display for HashAlgorithm {
248 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249 match self {
250 Self::Md5 => write!(f, "MD5"),
251 Self::Sha1 => write!(f, "SHA-1"),
252 Self::Sha256 => write!(f, "SHA-256"),
253 Self::Sha384 => write!(f, "SHA-384"),
254 Self::Sha512 => write!(f, "SHA-512"),
255 Self::Sha3_256 => write!(f, "SHA3-256"),
256 Self::Sha3_384 => write!(f, "SHA3-384"),
257 Self::Sha3_512 => write!(f, "SHA3-512"),
258 Self::Blake2b256 => write!(f, "BLAKE2b-256"),
259 Self::Blake2b384 => write!(f, "BLAKE2b-384"),
260 Self::Blake2b512 => write!(f, "BLAKE2b-512"),
261 Self::Blake3 => write!(f, "BLAKE3"),
262 Self::Other(s) => write!(f, "{s}"),
263 }
264 }
265}
266
267#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct ExternalReference {
270 pub ref_type: ExternalRefType,
272 pub url: String,
274 pub comment: Option<String>,
276 pub hashes: Vec<Hash>,
278}
279
280#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
282pub enum ExternalRefType {
283 Vcs,
284 IssueTracker,
285 Website,
286 Advisories,
287 Bom,
288 MailingList,
289 Social,
290 Chat,
291 Documentation,
292 Support,
293 SourceDistribution,
294 BinaryDistribution,
295 License,
296 BuildMeta,
297 BuildSystem,
298 ReleaseNotes,
299 SecurityContact,
300 ModelCard,
301 Log,
302 Configuration,
303 Evidence,
304 Formulation,
305 Attestation,
306 ThreatModel,
307 AdversaryModel,
308 RiskAssessment,
309 VulnerabilityAssertion,
310 ExploitabilityStatement,
311 Pentest,
312 StaticAnalysis,
313 DynamicAnalysis,
314 RuntimeAnalysis,
315 ComponentAnalysis,
316 Maturity,
317 Certification,
318 QualityMetrics,
319 Codified,
320 Other(String),
321}
322
323impl std::fmt::Display for ExternalRefType {
324 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
325 match self {
326 Self::Vcs => write!(f, "vcs"),
327 Self::IssueTracker => write!(f, "issue-tracker"),
328 Self::Website => write!(f, "website"),
329 Self::Advisories => write!(f, "advisories"),
330 Self::Bom => write!(f, "bom"),
331 Self::MailingList => write!(f, "mailing-list"),
332 Self::Social => write!(f, "social"),
333 Self::Chat => write!(f, "chat"),
334 Self::Documentation => write!(f, "documentation"),
335 Self::Support => write!(f, "support"),
336 Self::SourceDistribution => write!(f, "distribution"),
337 Self::BinaryDistribution => write!(f, "distribution-intake"),
338 Self::License => write!(f, "license"),
339 Self::BuildMeta => write!(f, "build-meta"),
340 Self::BuildSystem => write!(f, "build-system"),
341 Self::ReleaseNotes => write!(f, "release-notes"),
342 Self::SecurityContact => write!(f, "security-contact"),
343 Self::ModelCard => write!(f, "model-card"),
344 Self::Log => write!(f, "log"),
345 Self::Configuration => write!(f, "configuration"),
346 Self::Evidence => write!(f, "evidence"),
347 Self::Formulation => write!(f, "formulation"),
348 Self::Attestation => write!(f, "attestation"),
349 Self::ThreatModel => write!(f, "threat-model"),
350 Self::AdversaryModel => write!(f, "adversary-model"),
351 Self::RiskAssessment => write!(f, "risk-assessment"),
352 Self::VulnerabilityAssertion => write!(f, "vulnerability-assertion"),
353 Self::ExploitabilityStatement => write!(f, "exploitability-statement"),
354 Self::Pentest => write!(f, "pentest-report"),
355 Self::StaticAnalysis => write!(f, "static-analysis-report"),
356 Self::DynamicAnalysis => write!(f, "dynamic-analysis-report"),
357 Self::RuntimeAnalysis => write!(f, "runtime-analysis-report"),
358 Self::ComponentAnalysis => write!(f, "component-analysis-report"),
359 Self::Maturity => write!(f, "maturity-report"),
360 Self::Certification => write!(f, "certification-report"),
361 Self::QualityMetrics => write!(f, "quality-metrics"),
362 Self::Codified => write!(f, "codified"),
363 Self::Other(s) => write!(f, "{s}"),
364 }
365 }
366}
367
368#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
370pub enum DependencyType {
371 DependsOn,
373 OptionalDependsOn,
375 DevDependsOn,
377 BuildDependsOn,
379 TestDependsOn,
381 RuntimeDependsOn,
383 ProvidedDependsOn,
385 Describes,
387 Generates,
389 Contains,
391 AncestorOf,
393 VariantOf,
395 DistributionArtifact,
397 PatchFor,
399 CopyOf,
401 FileAdded,
403 FileDeleted,
405 FileModified,
407 DynamicLink,
409 StaticLink,
411 Other(String),
413}
414
415impl std::fmt::Display for DependencyType {
416 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
417 match self {
418 Self::DependsOn => write!(f, "depends-on"),
419 Self::OptionalDependsOn => write!(f, "optional-depends-on"),
420 Self::DevDependsOn => write!(f, "dev-depends-on"),
421 Self::BuildDependsOn => write!(f, "build-depends-on"),
422 Self::TestDependsOn => write!(f, "test-depends-on"),
423 Self::RuntimeDependsOn => write!(f, "runtime-depends-on"),
424 Self::ProvidedDependsOn => write!(f, "provided-depends-on"),
425 Self::Describes => write!(f, "describes"),
426 Self::Generates => write!(f, "generates"),
427 Self::Contains => write!(f, "contains"),
428 Self::AncestorOf => write!(f, "ancestor-of"),
429 Self::VariantOf => write!(f, "variant-of"),
430 Self::DistributionArtifact => write!(f, "distribution-artifact"),
431 Self::PatchFor => write!(f, "patch-for"),
432 Self::CopyOf => write!(f, "copy-of"),
433 Self::FileAdded => write!(f, "file-added"),
434 Self::FileDeleted => write!(f, "file-deleted"),
435 Self::FileModified => write!(f, "file-modified"),
436 Self::DynamicLink => write!(f, "dynamic-link"),
437 Self::StaticLink => write!(f, "static-link"),
438 Self::Other(s) => write!(f, "{s}"),
439 }
440 }
441}
442
443#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
445pub enum DependencyScope {
446 #[default]
447 Required,
448 Optional,
449 Excluded,
450}
451
452impl std::fmt::Display for DependencyScope {
453 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
454 match self {
455 Self::Required => write!(f, "required"),
456 Self::Optional => write!(f, "optional"),
457 Self::Excluded => write!(f, "excluded"),
458 }
459 }
460}
461
462#[derive(Debug, Clone, Default, Serialize, Deserialize)]
464pub struct FormatExtensions {
465 pub cyclonedx: Option<serde_json::Value>,
467 pub spdx: Option<serde_json::Value>,
469}
470
471#[derive(Debug, Clone, Default, Serialize, Deserialize)]
473pub struct ComponentExtensions {
474 pub properties: Vec<Property>,
476 pub annotations: Vec<Annotation>,
478 pub raw: Option<serde_json::Value>,
480}
481
482#[derive(Debug, Clone, Serialize, Deserialize)]
484pub struct Property {
485 pub name: String,
486 pub value: String,
487}
488
489#[derive(Debug, Clone, Serialize, Deserialize)]
491pub struct Annotation {
492 pub annotator: String,
493 pub annotation_date: DateTime<Utc>,
494 pub annotation_type: String,
495 pub comment: String,
496}