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)]
388pub enum DependencyType {
389 DependsOn,
391 OptionalDependsOn,
393 DevDependsOn,
395 BuildDependsOn,
397 TestDependsOn,
399 RuntimeDependsOn,
401 ProvidedDependsOn,
403 Describes,
405 Generates,
407 Contains,
409 AncestorOf,
411 VariantOf,
413 DistributionArtifact,
415 PatchFor,
417 CopyOf,
419 FileAdded,
421 FileDeleted,
423 FileModified,
425 DynamicLink,
427 StaticLink,
429 Other(String),
431}
432
433impl std::fmt::Display for DependencyType {
434 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
435 match self {
436 Self::DependsOn => write!(f, "depends-on"),
437 Self::OptionalDependsOn => write!(f, "optional-depends-on"),
438 Self::DevDependsOn => write!(f, "dev-depends-on"),
439 Self::BuildDependsOn => write!(f, "build-depends-on"),
440 Self::TestDependsOn => write!(f, "test-depends-on"),
441 Self::RuntimeDependsOn => write!(f, "runtime-depends-on"),
442 Self::ProvidedDependsOn => write!(f, "provided-depends-on"),
443 Self::Describes => write!(f, "describes"),
444 Self::Generates => write!(f, "generates"),
445 Self::Contains => write!(f, "contains"),
446 Self::AncestorOf => write!(f, "ancestor-of"),
447 Self::VariantOf => write!(f, "variant-of"),
448 Self::DistributionArtifact => write!(f, "distribution-artifact"),
449 Self::PatchFor => write!(f, "patch-for"),
450 Self::CopyOf => write!(f, "copy-of"),
451 Self::FileAdded => write!(f, "file-added"),
452 Self::FileDeleted => write!(f, "file-deleted"),
453 Self::FileModified => write!(f, "file-modified"),
454 Self::DynamicLink => write!(f, "dynamic-link"),
455 Self::StaticLink => write!(f, "static-link"),
456 Self::Other(s) => write!(f, "{s}"),
457 }
458 }
459}
460
461#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
463pub enum DependencyScope {
464 #[default]
465 Required,
466 Optional,
467 Excluded,
468}
469
470impl std::fmt::Display for DependencyScope {
471 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
472 match self {
473 Self::Required => write!(f, "required"),
474 Self::Optional => write!(f, "optional"),
475 Self::Excluded => write!(f, "excluded"),
476 }
477 }
478}
479
480#[derive(Debug, Clone, Default, Serialize, Deserialize)]
482pub struct FormatExtensions {
483 pub cyclonedx: Option<serde_json::Value>,
485 pub spdx: Option<serde_json::Value>,
487}
488
489#[derive(Debug, Clone, Default, Serialize, Deserialize)]
491pub struct ComponentExtensions {
492 pub properties: Vec<Property>,
494 pub annotations: Vec<Annotation>,
496 pub raw: Option<serde_json::Value>,
498}
499
500#[derive(Debug, Clone, Serialize, Deserialize)]
502pub struct Property {
503 pub name: String,
504 pub value: String,
505}
506
507#[derive(Debug, Clone, Serialize, Deserialize)]
509pub struct Annotation {
510 pub annotator: String,
511 pub annotation_date: DateTime<Utc>,
512 pub annotation_type: String,
513 pub comment: String,
514}