@@ -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