* [ptxdist] [PATCH] report: make SBoMs reproducible
@ 2026-10-17 10:13 Ladislav Michl
2026-11-13 8:38 ` [ptxdist] [APPLIED] " Michael Olbrich
0 siblings, 1 reply; 2+ messages in thread
From: Ladislav Michl @ 2026-10-17 10:13 UTC (permalink / raw)
To: ptxdist
From: Ladislav Michl <ladis@triops.cz>
Use SOURCE_DATE_EPOCH for timestamp.
Signed-off-by: Ladislav Michl <ladis@triops.cz>
---
scripts/report/cyclonedx_sbom.py | 7 +++++--
scripts/report/sbom.py | 8 +++++++-
scripts/report/spdx_sbom.py | 3 +--
3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/scripts/report/cyclonedx_sbom.py b/scripts/report/cyclonedx_sbom.py
index 28f31c480..8a2cc0a85 100644
--- a/scripts/report/cyclonedx_sbom.py
+++ b/scripts/report/cyclonedx_sbom.py
@@ -8,9 +8,9 @@
import json
from base64 import b64encode
-from datetime import datetime
from os import path
from shutil import copy
+from uuid import NAMESPACE_DNS, UUID, uuid5
from cyclonedx.factory.license import LicenseFactory
from cyclonedx.model import (
@@ -49,6 +49,9 @@ class CycloneDXSbomGenerator(SbomGenerator):
self.lc_factory = LicenseFactory()
def write(self, file, bom):
+ bom.serial_number = UUID(int=0)
+ content = JsonV1Dot6(bom).output_as_string(indent=2)
+ bom.serial_number = uuid5(uuid5(NAMESPACE_DNS, "sbom.ptxdist.org"), content)
outputter = JsonV1Dot6(bom)
file.write(outputter.output_as_string(indent=2).encode("utf-8"))
@@ -216,7 +219,7 @@ class CycloneDXSbomGenerator(SbomGenerator):
document = Bom()
document.metadata = BomMetaData(
- timestamp=datetime.now(),
+ timestamp=self.timestamp(),
properties=SortedSet(
[
Property(name="vendor", value=data["bsp"]["vendor"]),
diff --git a/scripts/report/sbom.py b/scripts/report/sbom.py
index 95a91c876..1c7790bac 100644
--- a/scripts/report/sbom.py
+++ b/scripts/report/sbom.py
@@ -7,7 +7,8 @@
#
import re
-from os import path
+from datetime import datetime, timezone
+from os import environ, path
from report.generator import Generator
from report.report import ReportException
@@ -104,6 +105,11 @@ class SbomGenerator(Generator):
patches.append((tag, patch))
return patches
+ def timestamp(self):
+ if epoch := environ.get("SOURCE_DATE_EPOCH"):
+ return datetime.fromtimestamp(int(epoch), timezone.utc)
+ return datetime.now(timezone.utc)
+
def setup_env(self):
env = {}
for tmp in self._env:
diff --git a/scripts/report/spdx_sbom.py b/scripts/report/spdx_sbom.py
index 252828bc5..958471b3b 100644
--- a/scripts/report/spdx_sbom.py
+++ b/scripts/report/spdx_sbom.py
@@ -8,7 +8,6 @@
import hashlib
import uuid
-from datetime import datetime, timezone
from os import path
from shutil import copy
@@ -145,7 +144,7 @@ class SpdxSbomGenerator(SbomGenerator):
def build(self, data):
creationInfo = spdx.SPDXCreationInfo()
creationInfo.created = (
- datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace('+00:00', 'Z')
+ self.timestamp().replace(microsecond=0).isoformat().replace("+00:00", "Z")
)
creationInfo.creators = [
f"Organization: {data['bsp']['vendor']}",
--
2.47.3
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [ptxdist] [APPLIED] report: make SBoMs reproducible
2026-10-17 10:13 [ptxdist] [PATCH] report: make SBoMs reproducible Ladislav Michl
@ 2026-11-13 8:38 ` Michael Olbrich
0 siblings, 0 replies; 2+ messages in thread
From: Michael Olbrich @ 2026-11-13 8:38 UTC (permalink / raw)
To: ptxdist; +Cc: Ladislav Michl
Thanks, applied as 4121943f0d4d0c59c082c87cd51eb32291d6629c.
Michael
[sent from post-receive hook]
On Fri, 13 Nov 2026 09:38:36 +0100, Ladislav Michl <oss-lists@triops.cz> wrote:
> Use SOURCE_DATE_EPOCH for timestamp.
>
> Signed-off-by: Ladislav Michl <ladis@triops.cz>
> Message-Id: <atNKL-2RFyKTjz1Q@lenoch>
> Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
>
> diff --git a/scripts/report/cyclonedx_sbom.py b/scripts/report/cyclonedx_sbom.py
> index 28f31c480b47..8a2cc0a85900 100644
> --- a/scripts/report/cyclonedx_sbom.py
> +++ b/scripts/report/cyclonedx_sbom.py
> @@ -8,9 +8,9 @@
>
> import json
> from base64 import b64encode
> -from datetime import datetime
> from os import path
> from shutil import copy
> +from uuid import NAMESPACE_DNS, UUID, uuid5
>
> from cyclonedx.factory.license import LicenseFactory
> from cyclonedx.model import (
> @@ -49,6 +49,9 @@ class CycloneDXSbomGenerator(SbomGenerator):
> self.lc_factory = LicenseFactory()
>
> def write(self, file, bom):
> + bom.serial_number = UUID(int=0)
> + content = JsonV1Dot6(bom).output_as_string(indent=2)
> + bom.serial_number = uuid5(uuid5(NAMESPACE_DNS, "sbom.ptxdist.org"), content)
> outputter = JsonV1Dot6(bom)
> file.write(outputter.output_as_string(indent=2).encode("utf-8"))
>
> @@ -216,7 +219,7 @@ class CycloneDXSbomGenerator(SbomGenerator):
> document = Bom()
>
> document.metadata = BomMetaData(
> - timestamp=datetime.now(),
> + timestamp=self.timestamp(),
> properties=SortedSet(
> [
> Property(name="vendor", value=data["bsp"]["vendor"]),
> diff --git a/scripts/report/sbom.py b/scripts/report/sbom.py
> index 95a91c876a90..1c7790baca6b 100644
> --- a/scripts/report/sbom.py
> +++ b/scripts/report/sbom.py
> @@ -7,7 +7,8 @@
> #
>
> import re
> -from os import path
> +from datetime import datetime, timezone
> +from os import environ, path
>
> from report.generator import Generator
> from report.report import ReportException
> @@ -104,6 +105,11 @@ class SbomGenerator(Generator):
> patches.append((tag, patch))
> return patches
>
> + def timestamp(self):
> + if epoch := environ.get("SOURCE_DATE_EPOCH"):
> + return datetime.fromtimestamp(int(epoch), timezone.utc)
> + return datetime.now(timezone.utc)
> +
> def setup_env(self):
> env = {}
> for tmp in self._env:
> diff --git a/scripts/report/spdx_sbom.py b/scripts/report/spdx_sbom.py
> index 252828bc5136..958471b3bb4e 100644
> --- a/scripts/report/spdx_sbom.py
> +++ b/scripts/report/spdx_sbom.py
> @@ -8,7 +8,6 @@
>
> import hashlib
> import uuid
> -from datetime import datetime, timezone
> from os import path
> from shutil import copy
>
> @@ -145,7 +144,7 @@ class SpdxSbomGenerator(SbomGenerator):
> def build(self, data):
> creationInfo = spdx.SPDXCreationInfo()
> creationInfo.created = (
> - datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace('+00:00', 'Z')
> + self.timestamp().replace(microsecond=0).isoformat().replace("+00:00", "Z")
> )
> creationInfo.creators = [
> f"Organization: {data['bsp']['vendor']}",
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-13 8:38 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-17 10:13 [ptxdist] [PATCH] report: make SBoMs reproducible Ladislav Michl
2026-11-13 8:38 ` [ptxdist] [APPLIED] " Michael Olbrich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox