From 5cfc3be4c67b20f259cce30f41f3a6a057e70b57 Mon Sep 17 00:00:00 2001 From: Daniel Alley Date: Mon, 10 Apr 2023 17:03:16 -0400 Subject: [PATCH] Support SOURCE_DATE_EPOCH standard for reproducable builds Doesn't allow fully reproducable builds on its own, but it should help. --- CHANGELOG.md | 2 ++ src/rpm/builder.rs | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2312c6b5..b085800c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `get_entry_data_as_u16_array()`, `get_entry_data_as_u32()`, `get_entry_data_as_u32_array()`, `get_entry_data_as_u64()`, `get_entry_data_as_u64_array()`, `get_entry_data_as_string_array()`, `get_entry_data_as_i18n_string()` +- Support the `SOURCE_DATE_EPOCH` environment variable for overriding the timestamp during package + builds (for reproducable builds), as well as allow it to be manually overridden with `build_time()` ### Fixed diff --git a/src/rpm/builder.rs b/src/rpm/builder.rs index 6be0601a..b256f385 100644 --- a/src/rpm/builder.rs +++ b/src/rpm/builder.rs @@ -133,11 +133,18 @@ pub struct RPMBuilder { impl RPMBuilder { pub fn new(name: &str, version: &str, license: &str, arch: &str, desc: &str) -> Self { + // Implement the SOURCE_DATE_EPOCH standard for reproducable builds + // https://reproducible-builds.org/docs/source-date-epoch/ + let source_date_epoch = std::env::var("SOURCE_DATE_EPOCH"); + // @todo, should these values be calculated lazily (only when .build()) is called? - let build_time = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .expect("system time predates the Unix epoch?") - .as_secs() as u32; + let build_time: u32 = source_date_epoch + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or_else(|| SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("system time predates the Unix epoch?") + .as_secs() as u32); let build_host = gethostname().to_string_lossy().to_string(); RPMBuilder { @@ -216,6 +223,18 @@ impl RPMBuilder { self } + // @todo: rpmbuild provides a few different settings for this through different mechanisms. we could + // possibly accept an enum with various options here, or find some other way to do so. + // + // CurrentTime + // SpecifiedTime(u32) + // MostRecentChangelog + // SourceDateEpoch + pub fn build_time(mut self, timestamp: u32) -> Self { + self.build_time = timestamp; + self + } + pub fn add_changelog_entry(mut self, author: E, description: F, timestamp: u32) -> Self where E: Into,