1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
//! Software Bill of Materials (SBOM) support.
use libcnb_data::sbom::SbomFormat;
use std::fs;
use std::path::{Path, PathBuf};
/// A software bill of materials (SBOM).
///
/// Since the CNB specification supports multiple SBOM formats and there are many ways to generate
/// and represent them, libcnb.rs treats them as raw bytes with attached metadata about the format.
///
/// This means there is no direct support for generating an SBOM file with libcnb.rs. Leverage
/// external tooling such as build tool plugins or Rust crates to generate SBOM files. libcnb.rs
/// offers [`From`]/[`TryFrom`] implementations for common Rust SBOM libraries. Enable the
/// corresponding features to gain access to them.
#[derive(Debug, Clone)]
pub struct Sbom {
pub format: SbomFormat,
pub data: Vec<u8>,
}
impl Sbom {
/// Constructs an `Sbom` from the given path, treating it as the SBOM format specified.
///
/// Note that there is no validation performed by libcnb.rs, the CNB lifecycle will error at
/// runtime should the SBOM be invalid.
pub fn from_path<P: AsRef<Path>>(format: SbomFormat, path: P) -> std::io::Result<Self> {
fs::read(path.as_ref()).map(|data| Self { format, data })
}
/// Constructs an `Sbom` from the given bytes, treating it as the SBOM format specified.
///
/// Note that there is no validation performed by libcnb.rs, the CNB lifecycle will error at
/// runtime should the SBOM be invalid.
pub fn from_bytes<D: Into<Vec<u8>>>(format: SbomFormat, data: D) -> Self {
Self {
format,
data: data.into(),
}
}
}
#[cfg(feature = "cyclonedx-bom")]
impl TryFrom<cyclonedx_bom::models::bom::Bom> for Sbom {
type Error = cyclonedx_bom::errors::JsonWriteError;
fn try_from(cyclonedx_bom: cyclonedx_bom::models::bom::Bom) -> Result<Self, Self::Error> {
let mut data = vec![];
cyclonedx_bom.output_as_json_v1_3(&mut data)?;
Ok(Self {
format: SbomFormat::CycloneDxJson,
data,
})
}
}
pub(crate) fn cnb_sbom_path<P: AsRef<Path>>(
sbom_format: &SbomFormat,
base_directory: P,
base_name: &str,
) -> PathBuf {
let suffix = match sbom_format {
SbomFormat::CycloneDxJson => "cdx.json",
SbomFormat::SpdxJson => "spdx.json",
SbomFormat::SyftJson => "syft.json",
};
base_directory
.as_ref()
.join(format!("{base_name}.sbom.{suffix}"))
}