use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SbomFormat {
CycloneDx,
Spdx,
}
impl std::fmt::Display for SbomFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::CycloneDx => write!(f, "CycloneDX"),
Self::Spdx => write!(f, "SPDX"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DocumentMetadata {
pub format: SbomFormat,
pub format_version: String,
pub spec_version: String,
pub serial_number: Option<String>,
pub created: DateTime<Utc>,
pub creators: Vec<Creator>,
pub name: Option<String>,
pub security_contact: Option<String>,
pub vulnerability_disclosure_url: Option<String>,
pub support_end_date: Option<DateTime<Utc>>,
pub lifecycle_phase: Option<String>,
pub completeness_declaration: CompletenessDeclaration,
pub signature: Option<SignatureInfo>,
pub distribution_classification: Option<String>,
pub citations_count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[non_exhaustive]
pub enum CompletenessDeclaration {
Complete,
IncompleteFirstPartyOnly,
IncompleteThirdPartyOnly,
Incomplete,
#[default]
Unknown,
NotSpecified,
}
impl std::fmt::Display for CompletenessDeclaration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Complete => write!(f, "complete"),
Self::IncompleteFirstPartyOnly => write!(f, "incomplete (first-party only)"),
Self::IncompleteThirdPartyOnly => write!(f, "incomplete (third-party only)"),
Self::Incomplete => write!(f, "incomplete"),
Self::Unknown => write!(f, "unknown"),
Self::NotSpecified => write!(f, "not specified"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignatureInfo {
pub algorithm: String,
pub has_value: bool,
}
impl Default for DocumentMetadata {
fn default() -> Self {
Self {
format: SbomFormat::CycloneDx,
format_version: String::new(),
spec_version: String::new(),
serial_number: None,
created: Utc::now(),
creators: Vec::new(),
name: None,
security_contact: None,
vulnerability_disclosure_url: None,
support_end_date: None,
lifecycle_phase: None,
completeness_declaration: CompletenessDeclaration::default(),
signature: None,
distribution_classification: None,
citations_count: 0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Creator {
pub creator_type: CreatorType,
pub name: String,
pub email: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum CreatorType {
Person,
Organization,
Tool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Organization {
pub name: String,
pub urls: Vec<String>,
pub contacts: Vec<Contact>,
}
impl Organization {
#[must_use]
pub const fn new(name: String) -> Self {
Self {
name,
urls: Vec::new(),
contacts: Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Contact {
pub name: Option<String>,
pub email: Option<String>,
pub phone: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum ComponentType {
Application,
Framework,
#[default]
Library,
Container,
OperatingSystem,
Device,
Firmware,
File,
Data,
MachineLearningModel,
Platform,
DeviceDriver,
Cryptographic,
Other(String),
}
impl std::fmt::Display for ComponentType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Application => write!(f, "application"),
Self::Framework => write!(f, "framework"),
Self::Library => write!(f, "library"),
Self::Container => write!(f, "container"),
Self::OperatingSystem => write!(f, "operating-system"),
Self::Device => write!(f, "device"),
Self::Firmware => write!(f, "firmware"),
Self::File => write!(f, "file"),
Self::Data => write!(f, "data"),
Self::MachineLearningModel => write!(f, "machine-learning-model"),
Self::Platform => write!(f, "platform"),
Self::DeviceDriver => write!(f, "device-driver"),
Self::Cryptographic => write!(f, "cryptographic"),
Self::Other(s) => write!(f, "{s}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Hash {
pub algorithm: HashAlgorithm,
pub value: String,
}
impl Hash {
#[must_use]
pub const fn new(algorithm: HashAlgorithm, value: String) -> Self {
Self { algorithm, value }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum HashAlgorithm {
Md5,
Sha1,
Sha256,
Sha384,
Sha512,
Sha3_256,
Sha3_384,
Sha3_512,
Blake2b256,
Blake2b384,
Blake2b512,
Blake3,
Streebog256,
Streebog512,
Other(String),
}
impl std::fmt::Display for HashAlgorithm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Md5 => write!(f, "MD5"),
Self::Sha1 => write!(f, "SHA-1"),
Self::Sha256 => write!(f, "SHA-256"),
Self::Sha384 => write!(f, "SHA-384"),
Self::Sha512 => write!(f, "SHA-512"),
Self::Sha3_256 => write!(f, "SHA3-256"),
Self::Sha3_384 => write!(f, "SHA3-384"),
Self::Sha3_512 => write!(f, "SHA3-512"),
Self::Blake2b256 => write!(f, "BLAKE2b-256"),
Self::Blake2b384 => write!(f, "BLAKE2b-384"),
Self::Blake2b512 => write!(f, "BLAKE2b-512"),
Self::Blake3 => write!(f, "BLAKE3"),
Self::Streebog256 => write!(f, "Streebog-256"),
Self::Streebog512 => write!(f, "Streebog-512"),
Self::Other(s) => write!(f, "{s}"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExternalReference {
pub ref_type: ExternalRefType,
pub url: String,
pub comment: Option<String>,
pub hashes: Vec<Hash>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ExternalRefType {
Vcs,
IssueTracker,
Website,
Advisories,
Bom,
MailingList,
Social,
Chat,
Documentation,
Support,
SourceDistribution,
BinaryDistribution,
License,
BuildMeta,
BuildSystem,
ReleaseNotes,
SecurityContact,
ModelCard,
Log,
Configuration,
Evidence,
Formulation,
Attestation,
ThreatModel,
AdversaryModel,
RiskAssessment,
VulnerabilityAssertion,
ExploitabilityStatement,
Pentest,
StaticAnalysis,
DynamicAnalysis,
RuntimeAnalysis,
ComponentAnalysis,
Maturity,
Certification,
QualityMetrics,
Codified,
Citation,
Patent,
PatentAssertion,
PatentFamily,
Other(String),
}
impl std::fmt::Display for ExternalRefType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Vcs => write!(f, "vcs"),
Self::IssueTracker => write!(f, "issue-tracker"),
Self::Website => write!(f, "website"),
Self::Advisories => write!(f, "advisories"),
Self::Bom => write!(f, "bom"),
Self::MailingList => write!(f, "mailing-list"),
Self::Social => write!(f, "social"),
Self::Chat => write!(f, "chat"),
Self::Documentation => write!(f, "documentation"),
Self::Support => write!(f, "support"),
Self::SourceDistribution => write!(f, "distribution"),
Self::BinaryDistribution => write!(f, "distribution-intake"),
Self::License => write!(f, "license"),
Self::BuildMeta => write!(f, "build-meta"),
Self::BuildSystem => write!(f, "build-system"),
Self::ReleaseNotes => write!(f, "release-notes"),
Self::SecurityContact => write!(f, "security-contact"),
Self::ModelCard => write!(f, "model-card"),
Self::Log => write!(f, "log"),
Self::Configuration => write!(f, "configuration"),
Self::Evidence => write!(f, "evidence"),
Self::Formulation => write!(f, "formulation"),
Self::Attestation => write!(f, "attestation"),
Self::ThreatModel => write!(f, "threat-model"),
Self::AdversaryModel => write!(f, "adversary-model"),
Self::RiskAssessment => write!(f, "risk-assessment"),
Self::VulnerabilityAssertion => write!(f, "vulnerability-assertion"),
Self::ExploitabilityStatement => write!(f, "exploitability-statement"),
Self::Pentest => write!(f, "pentest-report"),
Self::StaticAnalysis => write!(f, "static-analysis-report"),
Self::DynamicAnalysis => write!(f, "dynamic-analysis-report"),
Self::RuntimeAnalysis => write!(f, "runtime-analysis-report"),
Self::ComponentAnalysis => write!(f, "component-analysis-report"),
Self::Maturity => write!(f, "maturity-report"),
Self::Certification => write!(f, "certification-report"),
Self::QualityMetrics => write!(f, "quality-metrics"),
Self::Codified => write!(f, "codified"),
Self::Citation => write!(f, "citation"),
Self::Patent => write!(f, "patent"),
Self::PatentAssertion => write!(f, "patent-assertion"),
Self::PatentFamily => write!(f, "patent-family"),
Self::Other(s) => write!(f, "{s}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum DependencyType {
DependsOn,
OptionalDependsOn,
DevDependsOn,
BuildDependsOn,
TestDependsOn,
RuntimeDependsOn,
ProvidedDependsOn,
Describes,
Generates,
Contains,
AncestorOf,
VariantOf,
DistributionArtifact,
PatchFor,
CopyOf,
FileAdded,
FileDeleted,
FileModified,
DynamicLink,
StaticLink,
Provides,
Other(String),
}
impl std::fmt::Display for DependencyType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::DependsOn => write!(f, "depends-on"),
Self::OptionalDependsOn => write!(f, "optional-depends-on"),
Self::DevDependsOn => write!(f, "dev-depends-on"),
Self::BuildDependsOn => write!(f, "build-depends-on"),
Self::TestDependsOn => write!(f, "test-depends-on"),
Self::RuntimeDependsOn => write!(f, "runtime-depends-on"),
Self::ProvidedDependsOn => write!(f, "provided-depends-on"),
Self::Describes => write!(f, "describes"),
Self::Generates => write!(f, "generates"),
Self::Contains => write!(f, "contains"),
Self::AncestorOf => write!(f, "ancestor-of"),
Self::VariantOf => write!(f, "variant-of"),
Self::DistributionArtifact => write!(f, "distribution-artifact"),
Self::PatchFor => write!(f, "patch-for"),
Self::CopyOf => write!(f, "copy-of"),
Self::FileAdded => write!(f, "file-added"),
Self::FileDeleted => write!(f, "file-deleted"),
Self::FileModified => write!(f, "file-modified"),
Self::DynamicLink => write!(f, "dynamic-link"),
Self::StaticLink => write!(f, "static-link"),
Self::Provides => write!(f, "provides"),
Self::Other(s) => write!(f, "{s}"),
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum DependencyScope {
#[default]
Required,
Optional,
Excluded,
}
impl std::fmt::Display for DependencyScope {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Required => write!(f, "required"),
Self::Optional => write!(f, "optional"),
Self::Excluded => write!(f, "excluded"),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct FormatExtensions {
pub cyclonedx: Option<serde_json::Value>,
pub spdx: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ComponentExtensions {
pub properties: Vec<Property>,
pub annotations: Vec<Annotation>,
pub raw: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Property {
pub name: String,
pub value: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Annotation {
pub annotator: String,
pub annotation_date: DateTime<Utc>,
pub annotation_type: String,
pub comment: String,
}