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 pub distribution_classification: Option<String>,
53 pub citations_count: usize,
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
62#[non_exhaustive]
63pub enum CompletenessDeclaration {
64 Complete,
66 IncompleteFirstPartyOnly,
68 IncompleteThirdPartyOnly,
70 Incomplete,
72 #[default]
74 Unknown,
75 NotSpecified,
77}
78
79impl std::fmt::Display for CompletenessDeclaration {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 match self {
82 Self::Complete => write!(f, "complete"),
83 Self::IncompleteFirstPartyOnly => write!(f, "incomplete (first-party only)"),
84 Self::IncompleteThirdPartyOnly => write!(f, "incomplete (third-party only)"),
85 Self::Incomplete => write!(f, "incomplete"),
86 Self::Unknown => write!(f, "unknown"),
87 Self::NotSpecified => write!(f, "not specified"),
88 }
89 }
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct SignatureInfo {
95 pub algorithm: String,
97 pub has_value: bool,
99}
100
101impl Default for DocumentMetadata {
102 fn default() -> Self {
103 Self {
104 format: SbomFormat::CycloneDx,
105 format_version: String::new(),
106 spec_version: String::new(),
107 serial_number: None,
108 created: Utc::now(),
109 creators: Vec::new(),
110 name: None,
111 security_contact: None,
112 vulnerability_disclosure_url: None,
113 support_end_date: None,
114 lifecycle_phase: None,
115 completeness_declaration: CompletenessDeclaration::default(),
116 signature: None,
117 distribution_classification: None,
118 citations_count: 0,
119 }
120 }
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct Creator {
126 pub creator_type: CreatorType,
128 pub name: String,
130 pub email: Option<String>,
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
136pub enum CreatorType {
137 Person,
138 Organization,
139 Tool,
140}
141
142#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
144pub struct Organization {
145 pub name: String,
147 pub urls: Vec<String>,
149 pub contacts: Vec<Contact>,
151}
152
153impl Organization {
154 #[must_use]
156 pub const fn new(name: String) -> Self {
157 Self {
158 name,
159 urls: Vec::new(),
160 contacts: Vec::new(),
161 }
162 }
163}
164
165#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
167pub struct Contact {
168 pub name: Option<String>,
170 pub email: Option<String>,
172 pub phone: Option<String>,
174}
175
176#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
178#[non_exhaustive]
179pub enum ComponentType {
180 Application,
181 Framework,
182 #[default]
183 Library,
184 Container,
185 OperatingSystem,
186 Device,
187 Firmware,
188 File,
189 Data,
190 MachineLearningModel,
191 Platform,
192 DeviceDriver,
193 Cryptographic,
194 Other(String),
195}
196
197impl std::fmt::Display for ComponentType {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 match self {
200 Self::Application => write!(f, "application"),
201 Self::Framework => write!(f, "framework"),
202 Self::Library => write!(f, "library"),
203 Self::Container => write!(f, "container"),
204 Self::OperatingSystem => write!(f, "operating-system"),
205 Self::Device => write!(f, "device"),
206 Self::Firmware => write!(f, "firmware"),
207 Self::File => write!(f, "file"),
208 Self::Data => write!(f, "data"),
209 Self::MachineLearningModel => write!(f, "machine-learning-model"),
210 Self::Platform => write!(f, "platform"),
211 Self::DeviceDriver => write!(f, "device-driver"),
212 Self::Cryptographic => write!(f, "cryptographic"),
213 Self::Other(s) => write!(f, "{s}"),
214 }
215 }
216}
217
218#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
220pub struct Hash {
221 pub algorithm: HashAlgorithm,
223 pub value: String,
225}
226
227impl Hash {
228 #[must_use]
230 pub const fn new(algorithm: HashAlgorithm, value: String) -> Self {
231 Self { algorithm, value }
232 }
233}
234
235#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
237pub enum HashAlgorithm {
238 Md5,
239 Sha1,
240 Sha256,
241 Sha384,
242 Sha512,
243 Sha3_256,
244 Sha3_384,
245 Sha3_512,
246 Blake2b256,
247 Blake2b384,
248 Blake2b512,
249 Blake3,
250 Streebog256,
251 Streebog512,
252 Other(String),
253}
254
255impl std::fmt::Display for HashAlgorithm {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 match self {
258 Self::Md5 => write!(f, "MD5"),
259 Self::Sha1 => write!(f, "SHA-1"),
260 Self::Sha256 => write!(f, "SHA-256"),
261 Self::Sha384 => write!(f, "SHA-384"),
262 Self::Sha512 => write!(f, "SHA-512"),
263 Self::Sha3_256 => write!(f, "SHA3-256"),
264 Self::Sha3_384 => write!(f, "SHA3-384"),
265 Self::Sha3_512 => write!(f, "SHA3-512"),
266 Self::Blake2b256 => write!(f, "BLAKE2b-256"),
267 Self::Blake2b384 => write!(f, "BLAKE2b-384"),
268 Self::Blake2b512 => write!(f, "BLAKE2b-512"),
269 Self::Blake3 => write!(f, "BLAKE3"),
270 Self::Streebog256 => write!(f, "Streebog-256"),
271 Self::Streebog512 => write!(f, "Streebog-512"),
272 Self::Other(s) => write!(f, "{s}"),
273 }
274 }
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
279pub struct ExternalReference {
280 pub ref_type: ExternalRefType,
282 pub url: String,
284 pub comment: Option<String>,
286 pub hashes: Vec<Hash>,
288}
289
290#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
292pub enum ExternalRefType {
293 Vcs,
294 IssueTracker,
295 Website,
296 Advisories,
297 Bom,
298 MailingList,
299 Social,
300 Chat,
301 Documentation,
302 Support,
303 SourceDistribution,
304 BinaryDistribution,
305 License,
306 BuildMeta,
307 BuildSystem,
308 ReleaseNotes,
309 SecurityContact,
310 ModelCard,
311 Log,
312 Configuration,
313 Evidence,
314 Formulation,
315 Attestation,
316 ThreatModel,
317 AdversaryModel,
318 RiskAssessment,
319 VulnerabilityAssertion,
320 ExploitabilityStatement,
321 Pentest,
322 StaticAnalysis,
323 DynamicAnalysis,
324 RuntimeAnalysis,
325 ComponentAnalysis,
326 Maturity,
327 Certification,
328 QualityMetrics,
329 Codified,
330 Citation,
331 Patent,
332 PatentAssertion,
333 PatentFamily,
334 Other(String),
335}
336
337impl std::fmt::Display for ExternalRefType {
338 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
339 match self {
340 Self::Vcs => write!(f, "vcs"),
341 Self::IssueTracker => write!(f, "issue-tracker"),
342 Self::Website => write!(f, "website"),
343 Self::Advisories => write!(f, "advisories"),
344 Self::Bom => write!(f, "bom"),
345 Self::MailingList => write!(f, "mailing-list"),
346 Self::Social => write!(f, "social"),
347 Self::Chat => write!(f, "chat"),
348 Self::Documentation => write!(f, "documentation"),
349 Self::Support => write!(f, "support"),
350 Self::SourceDistribution => write!(f, "distribution"),
351 Self::BinaryDistribution => write!(f, "distribution-intake"),
352 Self::License => write!(f, "license"),
353 Self::BuildMeta => write!(f, "build-meta"),
354 Self::BuildSystem => write!(f, "build-system"),
355 Self::ReleaseNotes => write!(f, "release-notes"),
356 Self::SecurityContact => write!(f, "security-contact"),
357 Self::ModelCard => write!(f, "model-card"),
358 Self::Log => write!(f, "log"),
359 Self::Configuration => write!(f, "configuration"),
360 Self::Evidence => write!(f, "evidence"),
361 Self::Formulation => write!(f, "formulation"),
362 Self::Attestation => write!(f, "attestation"),
363 Self::ThreatModel => write!(f, "threat-model"),
364 Self::AdversaryModel => write!(f, "adversary-model"),
365 Self::RiskAssessment => write!(f, "risk-assessment"),
366 Self::VulnerabilityAssertion => write!(f, "vulnerability-assertion"),
367 Self::ExploitabilityStatement => write!(f, "exploitability-statement"),
368 Self::Pentest => write!(f, "pentest-report"),
369 Self::StaticAnalysis => write!(f, "static-analysis-report"),
370 Self::DynamicAnalysis => write!(f, "dynamic-analysis-report"),
371 Self::RuntimeAnalysis => write!(f, "runtime-analysis-report"),
372 Self::ComponentAnalysis => write!(f, "component-analysis-report"),
373 Self::Maturity => write!(f, "maturity-report"),
374 Self::Certification => write!(f, "certification-report"),
375 Self::QualityMetrics => write!(f, "quality-metrics"),
376 Self::Codified => write!(f, "codified"),
377 Self::Citation => write!(f, "citation"),
378 Self::Patent => write!(f, "patent"),
379 Self::PatentAssertion => write!(f, "patent-assertion"),
380 Self::PatentFamily => write!(f, "patent-family"),
381 Self::Other(s) => write!(f, "{s}"),
382 }
383 }
384}
385
386#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
388#[non_exhaustive]
389pub enum DependencyType {
390 DependsOn,
392 OptionalDependsOn,
394 DevDependsOn,
396 BuildDependsOn,
398 TestDependsOn,
400 RuntimeDependsOn,
402 ProvidedDependsOn,
404 Describes,
406 Generates,
408 Contains,
410 AncestorOf,
412 VariantOf,
414 DistributionArtifact,
416 PatchFor,
418 CopyOf,
420 FileAdded,
422 FileDeleted,
424 FileModified,
426 DynamicLink,
428 StaticLink,
430 Provides,
432 Other(String),
434}
435
436impl std::fmt::Display for DependencyType {
437 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
438 match self {
439 Self::DependsOn => write!(f, "depends-on"),
440 Self::OptionalDependsOn => write!(f, "optional-depends-on"),
441 Self::DevDependsOn => write!(f, "dev-depends-on"),
442 Self::BuildDependsOn => write!(f, "build-depends-on"),
443 Self::TestDependsOn => write!(f, "test-depends-on"),
444 Self::RuntimeDependsOn => write!(f, "runtime-depends-on"),
445 Self::ProvidedDependsOn => write!(f, "provided-depends-on"),
446 Self::Describes => write!(f, "describes"),
447 Self::Generates => write!(f, "generates"),
448 Self::Contains => write!(f, "contains"),
449 Self::AncestorOf => write!(f, "ancestor-of"),
450 Self::VariantOf => write!(f, "variant-of"),
451 Self::DistributionArtifact => write!(f, "distribution-artifact"),
452 Self::PatchFor => write!(f, "patch-for"),
453 Self::CopyOf => write!(f, "copy-of"),
454 Self::FileAdded => write!(f, "file-added"),
455 Self::FileDeleted => write!(f, "file-deleted"),
456 Self::FileModified => write!(f, "file-modified"),
457 Self::DynamicLink => write!(f, "dynamic-link"),
458 Self::StaticLink => write!(f, "static-link"),
459 Self::Provides => write!(f, "provides"),
460 Self::Other(s) => write!(f, "{s}"),
461 }
462 }
463}
464
465#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
467pub enum DependencyScope {
468 #[default]
469 Required,
470 Optional,
471 Excluded,
472}
473
474impl std::fmt::Display for DependencyScope {
475 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
476 match self {
477 Self::Required => write!(f, "required"),
478 Self::Optional => write!(f, "optional"),
479 Self::Excluded => write!(f, "excluded"),
480 }
481 }
482}
483
484#[derive(Debug, Clone, Default, Serialize, Deserialize)]
486pub struct FormatExtensions {
487 pub cyclonedx: Option<serde_json::Value>,
489 pub spdx: Option<serde_json::Value>,
491}
492
493#[derive(Debug, Clone, Default, Serialize, Deserialize)]
495pub struct ComponentExtensions {
496 pub properties: Vec<Property>,
498 pub annotations: Vec<Annotation>,
500 pub raw: Option<serde_json::Value>,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize)]
506pub struct Property {
507 pub name: String,
508 pub value: String,
509}
510
511#[derive(Debug, Clone, Serialize, Deserialize)]
513pub struct Annotation {
514 pub annotator: String,
515 pub annotation_date: DateTime<Utc>,
516 pub annotation_type: String,
517 pub comment: String,
518}