use serde::{Deserialize, Serialize};
use std::fmt::Display;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BillOfMaterials {
pub sbom_type: BomType,
pub version: String,
pub tools: Vec<BomTool>,
pub sha: String,
pub timestamp: chrono::DateTime<chrono::Utc>,
pub container: Container,
pub components: Vec<BomComponent>,
pub vulnerabilities: Vec<BomVulnerability>,
}
impl BillOfMaterials {
pub fn new(sbom_type: BomType, version: String) -> Self {
Self {
sbom_type,
version,
tools: Vec::new(),
sha: String::new(),
timestamp: chrono::Utc::now(),
container: Container::default(),
components: Vec::new(),
vulnerabilities: Vec::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BomTool {
pub name: String,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(non_camel_case_types)]
pub enum BomType {
CycloneDX_1_5,
CycloneDX_1_6,
SPDX,
}
impl Display for BomType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BomType::CycloneDX_1_5 => write!(f, "CycloneDX v1.5"),
BomType::CycloneDX_1_6 => write!(f, "CycloneDX v1.6"),
BomType::SPDX => write!(f, "SPDX"),
}
}
}
impl BomType {
pub fn to_file_name(&self) -> String {
match self {
BomType::CycloneDX_1_5 | BomType::CycloneDX_1_6 => "cdx",
BomType::SPDX => "spdx",
}
.to_string()
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
pub struct BomComponent {
pub purl: String,
pub cpe: Option<String>,
pub name: String,
pub comp_type: BomComponentType,
pub signature: Option<String>,
}
impl BomComponent {
pub fn from_purl(purl: String) -> Self {
Self {
purl,
..Default::default()
}
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct BomVulnerability {
pub name: String,
pub source: String,
pub severity: BomVulnerabilitySeverity,
pub description: Option<String>,
pub url: Option<String>,
pub components: Vec<BomComponent>,
}
impl BomVulnerability {
pub fn new(name: String, source: String, severity: String) -> Self {
BomVulnerability {
name,
source,
severity: BomVulnerabilitySeverity::from(severity),
..Default::default()
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub enum BomVulnerabilitySeverity {
Critical,
High,
Medium,
Low,
Informational,
#[default]
Unknown,
}
impl From<String> for BomVulnerabilitySeverity {
fn from(value: String) -> Self {
match value.to_lowercase().as_str() {
"critical" | "very-high" => BomVulnerabilitySeverity::Critical,
"high" => BomVulnerabilitySeverity::High,
"medium" | "moderate" => BomVulnerabilitySeverity::Medium,
"low" => BomVulnerabilitySeverity::Low,
"informational" | "very-low" => BomVulnerabilitySeverity::Informational,
_ => BomVulnerabilitySeverity::Unknown,
}
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct Container {
pub image: Option<String>,
pub version: Option<String>,
pub image_digest: Option<String>,
pub image_tag: Option<String>,
}
impl From<BomType> for String {
fn from(value: BomType) -> Self {
value.to_string()
}
}
impl From<BomType> for Vec<u8> {
fn from(value: BomType) -> Self {
match value {
BomType::CycloneDX_1_5 => value.to_string().as_bytes().to_vec(),
BomType::CycloneDX_1_6 => value.to_string().as_bytes().to_vec(),
BomType::SPDX => value.to_string().as_bytes().to_vec(),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub enum BomComponentType {
Library,
Application,
Framework,
OperatingSystem,
Container,
Firmware,
CryptoLibrary,
Service,
Database,
OperatingEnvironment,
Middleware,
ProgrammingLanguage,
#[default]
Unknown,
}
impl From<String> for BomComponentType {
fn from(value: String) -> Self {
match value.to_lowercase().as_str() {
"library" => BomComponentType::Library,
"application" => BomComponentType::Application,
"framework" => BomComponentType::Framework,
"operating_system" => BomComponentType::OperatingSystem,
"container" => BomComponentType::Container,
"firmware" => BomComponentType::Firmware,
"service" => BomComponentType::Service,
"database" => BomComponentType::Database,
"operating_environment" => BomComponentType::OperatingEnvironment,
"middleware" => BomComponentType::Middleware,
"programming_language" => BomComponentType::ProgrammingLanguage,
_ => BomComponentType::Unknown,
}
}
}