Skip to content

Commit 6a865f5

Browse files
authored
Merge pull request #852 from Shnatsel/reproducible-builds
Reproducible builds MVP
2 parents bda5d8a + b022463 commit 6a865f5

4 files changed

Lines changed: 32 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cargo-cyclonedx/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ percent-encoding = "2.3.1"
3434
purl = { version = "0.1.3", default-features = false, features = ["package-type"] }
3535
regex = "1.9.3"
3636
serde = { version = "1.0.193", features = ["derive"] }
37+
time = "0.3.36"
3738
thiserror = "2.0.0"
3839
validator = { version = "0.19.0" }
3940

cargo-cyclonedx/src/cli.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ pub enum Opts {
2424
#[derive(Parser, Debug)]
2525
#[clap(version)]
2626
#[clap(group(ArgGroup::new("dependencies-group").required(false).args(&["all", "top-level"])))]
27+
// TODO: replace with clap's Arg::env in 0.6.x after a semver break
28+
#[command(
29+
after_help = "The SOURCE_DATE_EPOCH env var is honored to enable reproducible builds,\n\
30+
see https://reproducible-builds.org/docs/source-date-epoch/"
31+
)]
2732
pub struct Args {
2833
/// Path to Cargo.toml
2934
#[clap(long = "manifest-path", value_name = "PATH", value_hint = clap::ValueHint::FilePath)]

cargo-cyclonedx/src/generator.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,14 @@ impl SbomGenerator {
186186
dep_kinds: &DependencyKindMap,
187187
) -> Result<(Bom, TargetKinds), GeneratorError> {
188188
let mut bom = Bom::default();
189+
190+
// If we're in reproducible build mode, do not include the random serial number
191+
// TODO: make it part of SBOM config instead in the next semver break
192+
// due to https://github.com/PyO3/maturin/issues/3091
193+
if let Ok(_) = std::env::var("SOURCE_DATE_EPOCH") {
194+
bom.serial_number = None;
195+
}
196+
189197
let root_package = &packages[package];
190198

191199
let components: Vec<_> = packages
@@ -512,6 +520,23 @@ impl SbomGenerator {
512520
let authors = Self::create_authors(package);
513521

514522
let mut metadata = Metadata::new()?;
523+
524+
// If we're in reproducible build mode, use a fixed timestam provided by the environment.
525+
// This is needed for Linux distributions: https://github.com/CycloneDX/cyclonedx-rust-cargo/issues/850
526+
// Specification: https://reproducible-builds.org/docs/source-date-epoch/
527+
//
528+
// TODO: make it part of SBOM config instead in the next semver break
529+
// due to https://github.com/PyO3/maturin/issues/3091
530+
if let Ok(timestamp) = std::env::var("SOURCE_DATE_EPOCH") {
531+
let timestamp =
532+
i64::from_str_radix(&timestamp, 10).expect("Invalid reproducible build timestamp");
533+
let datetime = time::OffsetDateTime::from_unix_timestamp(timestamp).unwrap();
534+
let time_str = datetime
535+
.format(&time::format_description::well_known::Iso8601::DEFAULT)
536+
.unwrap();
537+
metadata.timestamp = Some(time_str.try_into().unwrap());
538+
}
539+
515540
if !authors.is_empty() {
516541
metadata.authors = Some(authors);
517542
}

0 commit comments

Comments
 (0)