* [PATCH v3 0/3] spdx: add support to include releaseTime
@ 2026-09-28 19:03 daniel.turull
2026-09-28 19:03 ` [PATCH v3 1/3] classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash daniel.turull
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: daniel.turull @ 2026-09-28 19:03 UTC (permalink / raw)
To: openembedded-core; +Cc: JPEWhacker, mathieu.dubois-briand, Daniel Turull
From: Daniel Turull <daniel.turull@ericsson.com>
We have a requirements to include release time of open source components
in the SBOM. There is a field specific for that in spdx 3 spec.
https://spdx.github.io/spdx-spec/v3.0.1/model/Core/Properties/releaseTime/
This can also be used to evaluate how old are some of the core
components and decide if they need replacement.
The previous 2 versions did not have cover letter.
Tested with oe-selftest -r spdx
Daniel Turull (3):
classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash
create-spdx-3.0: record component release date in SPDX output
scripts/contrib: add spdx-release-date-report.py
meta/classes-global/base.bbclass | 4 +
meta/classes/create-spdx-3.0.bbclass | 2 +-
meta/lib/oe/spdx30_tasks.py | 19 ++
meta/lib/oeqa/selftest/cases/spdx.py | 39 ++++
scripts/contrib/spdx-release-date-report.py | 193 ++++++++++++++++++++
5 files changed, 256 insertions(+), 1 deletion(-)
create mode 100755 scripts/contrib/spdx-release-date-report.py
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 1/3] classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash
2026-09-28 19:03 [PATCH v3 0/3] spdx: add support to include releaseTime daniel.turull
@ 2026-09-28 19:03 ` daniel.turull
2026-09-29 14:53 ` Joshua Watt
2026-09-28 19:03 ` [PATCH v3 2/3] create-spdx-3.0: record component release date in SPDX output daniel.turull
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: daniel.turull @ 2026-09-28 19:03 UTC (permalink / raw)
To: openembedded-core; +Cc: JPEWhacker, mathieu.dubois-briand, Daniel Turull
From: Daniel Turull <daniel.turull@ericsson.com>
epochfile_read() memoizes its result into __CACHED_SOURCE_DATE_EPOCH
via d.setVar(), so its runtime value leaks into the basehash of any
task that calls it, causing a "metadata is not deterministic" error
once SDE_FILE is populated.
Exclude it, since it is not meaningful build metadata.
AI-Generated: Uses Kiro with Claude Sonnet 5
Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
---
This should fix the selftest errors reported by Mathieu
---
meta/classes-global/base.bbclass | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/meta/classes-global/base.bbclass b/meta/classes-global/base.bbclass
index 9553f00432..01a030399e 100644
--- a/meta/classes-global/base.bbclass
+++ b/meta/classes-global/base.bbclass
@@ -249,6 +249,10 @@ do_unpack[postfuncs] += "create_source_date_epoch_stamp"
def get_source_date_epoch_value(d):
return oe.reproducible.epochfile_read(d.getVar('SDE_FILE'), d)
+# epochfile_read() memoizes into this variable via d.setVar(), so its
+# runtime value must not leak into any task's hash.
+oe.reproducible.epochfile_read[vardepsexclude] = "__CACHED_SOURCE_DATE_EPOCH"
+
def get_layers_branch_rev(d):
revisions = oe.buildcfg.get_layer_revisions(d)
layers_branch_rev = ["%-20s = \"%s:%s\"" % (r[1], r[2], r[3]) for r in revisions]
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 2/3] create-spdx-3.0: record component release date in SPDX output
2026-09-28 19:03 [PATCH v3 0/3] spdx: add support to include releaseTime daniel.turull
2026-09-28 19:03 ` [PATCH v3 1/3] classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash daniel.turull
@ 2026-09-28 19:03 ` daniel.turull
2026-09-28 20:59 ` [OE-core] " Richard Purdie
2026-09-28 19:04 ` [PATCH v3 3/3] scripts/contrib: add spdx-release-date-report.py daniel.turull
2026-09-29 6:16 ` [OE-core] [PATCH v3 0/3] spdx: add support to include releaseTime Yoann Congal
3 siblings, 1 reply; 9+ messages in thread
From: daniel.turull @ 2026-09-28 19:03 UTC (permalink / raw)
To: openembedded-core; +Cc: JPEWhacker, mathieu.dubois-briand, Daniel Turull
From: Daniel Turull <daniel.turull@ericsson.com>
Record each recipe's release date in the releaseTime property of its
software_Package object, using the SOURCE_DATE_EPOCH already computed
for reproducible builds.
Accuracy depends on how SOURCE_DATE_EPOCH was derived: exact for
git-tagged recipes, best-effort for tarball/http(s) sources. Some
Python sdists (e.g. cryptography, hypothesis, maturin) normalize all
file mtimes to a fixed placeholder, so their releaseTime reflects
packaging-tool behavior, not the real release date.
Tested with oe-selftest -r spdx, and with `bitbake world
--runall=do_create_spdx`: 1011/1150 recipes got a releaseTime (range
1998-12-30 to 2026-09-17), 139 correctly had none.
AI-Generated: Uses Kiro with Claude Sonnet 5
Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
---
v2:
- Dropped all options per Joshua's feedback; read SDE_FILE directly.
- Dropped the redundant else: delattr(recipe, "releaseTime") branch.
- Selftest compares against SDE_FILE content directly instead of
SOURCE_DATE_EPOCH, which can diverge from it.
- Fixed a leak: recipes with no git checkout and no fetched source
had SDE_FILE holding only SOURCE_DATE_EPOCH_FALLBACK, showing a
bogus 2011-04-05T23:00:00Z releaseTime instead of none.
v3:
- Also run after do_unpack: do_deploy_source_date_epoch's setscene
shortcut can skip it, leaving SOURCE_DATE_EPOCH unset.
- get_release_date() reads SOURCE_DATE_EPOCH again instead of
SDE_FILE, now that they're guaranteed equivalent.
- test_release_date_source_date_epoch: switched to tar (base-files
has S == UNPACKDIR and never gets a real SOURCE_DATE_EPOCH).
- Added test_release_date_omitted_for_fallback_value.
---
meta/classes/create-spdx-3.0.bbclass | 2 +-
meta/lib/oe/spdx30_tasks.py | 19 ++++++++++++++
meta/lib/oeqa/selftest/cases/spdx.py | 39 ++++++++++++++++++++++++++++
3 files changed, 59 insertions(+), 1 deletion(-)
diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass
index 56fd01fd53..2b1465b5a6 100644
--- a/meta/classes/create-spdx-3.0.bbclass
+++ b/meta/classes/create-spdx-3.0.bbclass
@@ -192,7 +192,7 @@ python do_create_recipe_spdx() {
import oe.spdx30_tasks
oe.spdx30_tasks.create_recipe_spdx(d)
}
-addtask do_create_recipe_spdx
+addtask do_create_recipe_spdx after do_unpack do_deploy_source_date_epoch
SSTATETASKS += "do_create_recipe_spdx"
do_create_recipe_spdx[sstate-inputdirs] = "${SPDXRECIPEDEPLOY}"
diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py
index b6456a214a..964c2f1594 100644
--- a/meta/lib/oe/spdx30_tasks.py
+++ b/meta/lib/oe/spdx30_tasks.py
@@ -36,6 +36,21 @@ def set_timestamp_now(d, o, prop):
delattr(o, prop)
+def get_release_date(d):
+ """Resolve the release date to record in a recipe's releaseTime property.
+
+ Uses SOURCE_DATE_EPOCH; omits the fallback value since it's not a
+ meaningful release date.
+
+ Returns a datetime, or None if no release date should be recorded.
+ """
+ source_date_epoch = d.getVar("SOURCE_DATE_EPOCH")
+ if not source_date_epoch or source_date_epoch == d.getVar("SOURCE_DATE_EPOCH_FALLBACK"):
+ return None
+
+ return datetime.fromtimestamp(int(source_date_epoch), tz=timezone.utc)
+
+
def add_license_expression(
d, objset, license_expression, license_data, search_objsets=[]
):
@@ -633,6 +648,10 @@ def create_recipe_spdx(d):
if val := d.getVar("DESCRIPTION"):
recipe.description = val
+ release_date = get_release_date(d)
+ if release_date is not None:
+ recipe.releaseTime = release_date
+
for cpe_id in oe.cve_check.get_cpe_ids(
d.getVar("CVE_PRODUCT"), d.getVar("CVE_VERSION")
):
diff --git a/meta/lib/oeqa/selftest/cases/spdx.py b/meta/lib/oeqa/selftest/cases/spdx.py
index 8285189382..668915b686 100644
--- a/meta/lib/oeqa/selftest/cases/spdx.py
+++ b/meta/lib/oeqa/selftest/cases/spdx.py
@@ -6,6 +6,7 @@
import textwrap
import hashlib
+from datetime import datetime, timezone
from oeqa.selftest.case import OESelftestTestCase
from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars
import oe.spdx30
@@ -443,3 +444,41 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase):
r'\d',
f"Version '{version}' for package '{name}' should contain digits"
)
+
+ def test_release_date_source_date_epoch(self):
+ """releaseTime should be derived from SOURCE_DATE_EPOCH."""
+ objset = self.check_recipe_spdx(
+ "tar",
+ "{DEPLOY_DIR_SPDX}/{SSTATE_PKGARCH}/static/static-tar.spdx.json",
+ task="create_recipe_spdx",
+ )
+
+ source_date_epoch = get_bb_var("SOURCE_DATE_EPOCH", "tar")
+ expected = datetime.fromtimestamp(int(source_date_epoch), tz=timezone.utc)
+
+ recipe = None
+ for pkg in objset.foreach_type(oe.spdx30.software_Package):
+ if pkg.name == "tar":
+ recipe = pkg
+ break
+
+ self.assertIsNotNone(recipe, "Unable to find tar software_Package")
+ self.assertEqual(recipe.releaseTime, expected)
+
+ def test_release_date_omitted_for_fallback_value(self):
+ """releaseTime must be omitted when SDE_FILE only has the fallback."""
+ # packagegroup-base has no SRC_URI, so it only ever gets the fallback.
+ objset = self.check_recipe_spdx(
+ "packagegroup-base",
+ "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/static/static-packagegroup-base.spdx.json",
+ task="create_recipe_spdx",
+ )
+
+ recipe = None
+ for pkg in objset.foreach_type(oe.spdx30.software_Package):
+ if pkg.name == "packagegroup-base":
+ recipe = pkg
+ break
+
+ self.assertIsNotNone(recipe, "Unable to find packagegroup-base software_Package")
+ self.assertIsNone(recipe.releaseTime)
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 3/3] scripts/contrib: add spdx-release-date-report.py
2026-09-28 19:03 [PATCH v3 0/3] spdx: add support to include releaseTime daniel.turull
2026-09-28 19:03 ` [PATCH v3 1/3] classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash daniel.turull
2026-09-28 19:03 ` [PATCH v3 2/3] create-spdx-3.0: record component release date in SPDX output daniel.turull
@ 2026-09-28 19:04 ` daniel.turull
2026-09-29 6:16 ` [OE-core] [PATCH v3 0/3] spdx: add support to include releaseTime Yoann Congal
3 siblings, 0 replies; 9+ messages in thread
From: daniel.turull @ 2026-09-28 19:04 UTC (permalink / raw)
To: openembedded-core; +Cc: JPEWhacker, mathieu.dubois-briand, Daniel Turull
From: Daniel Turull <daniel.turull@ericsson.com>
Reports each recipe's releaseTime (added by the create-spdx-3.0 patch)
from either a DEPLOY_DIR_SPDX tree or a single merged image SBOM. Used
to spot-check release dates across a build and surface recipes missing
one; helped find the SOURCE_DATE_EPOCH_FALLBACK leak and archive-mtime
issues fixed by the two preceding patches.
AI-Generated: Uses Kiro with Claude Sonnet 5
Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
---
scripts/contrib/spdx-release-date-report.py | 193 ++++++++++++++++++++
1 file changed, 193 insertions(+)
create mode 100755 scripts/contrib/spdx-release-date-report.py
diff --git a/scripts/contrib/spdx-release-date-report.py b/scripts/contrib/spdx-release-date-report.py
new file mode 100755
index 0000000000..be429409fc
--- /dev/null
+++ b/scripts/contrib/spdx-release-date-report.py
@@ -0,0 +1,193 @@
+#! /usr/bin/env python3
+#
+# Copyright OpenEmbedded Contributors
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Author: Daniel Turull <daniel.turull@ericsson.com>
+#
+# Reports, per recipe, whether a valid releaseTime was recorded in SPDX
+# 3.0.1 output.
+#
+# AI-Generated: Uses Kiro (Claude)
+
+import argparse
+import csv
+import glob
+import json
+import logging
+import os
+import re
+import sys
+
+
+def load_jsonld_graph(path):
+ """Return the @graph list of a SPDX 3.0.1 JSON-LD document, or [] on error."""
+ try:
+ with open(path, "r", encoding="utf-8") as f:
+ data = json.load(f)
+ except (OSError, json.JSONDecodeError) as e:
+ logging.warning("Skipping %s: %s", path, e)
+ return []
+ return data.get("@graph", [])
+
+
+def collect_release_dates(deploy_dir):
+ """
+ Map recipe name -> releaseTime (or None) from all static/static-*.spdx.json
+ files found under deploy_dir.
+ """
+ release_dates = {}
+ pattern = os.path.join(deploy_dir, "**", "static", "static-*.spdx.json")
+ for path in sorted(glob.glob(pattern, recursive=True)):
+ for element in load_jsonld_graph(path):
+ if element.get("type") != "software_Package":
+ continue
+ name = element.get("name")
+ if not name:
+ continue
+ # First occurrence wins; the same recipe can appear for multiple
+ # arches (e.g. allarch vs machine-specific) with identical data.
+ release_dates.setdefault(name, element.get("releaseTime"))
+ return release_dates
+
+
+def _to_row(name, release_date):
+ return {
+ "recipe": name,
+ "release_date": release_date or "",
+ "valid_date": bool(release_date),
+ }
+
+
+def build_report(deploy_dir):
+ """
+ Build the report: [{"recipe": ..., "release_date": ..., "valid_date": bool}]
+ """
+ release_dates = collect_release_dates(deploy_dir)
+ return [_to_row(name, release_dates[name]) for name in sorted(release_dates)]
+
+
+# Per-recipe document namespace shared by all elements of that recipe in a
+# merged SBOM, e.g. http://spdx.org/spdxdocs/acl-<uuid>/<hash>/recipe/acl
+DOC_NAMESPACE_RE = re.compile(
+ r"^(https?://spdx\.org/spdxdocs/[^/]+-"
+ r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/"
+)
+
+
+def doc_namespace(spdx_id):
+ """Extract the per-recipe document namespace from a SPDX ID, or None."""
+ match = DOC_NAMESPACE_RE.match(spdx_id or "")
+ return match.group(1) if match else None
+
+
+def build_report_from_file(spdx_file):
+ """
+ Build the same report as build_report(), but from a single merged SBOM
+ document (e.g. an image's *.rootfs.spdx.json) instead of a DEPLOY_DIR_SPDX
+ tree. Recipes are identified by their document namespace.
+ """
+ graph = load_jsonld_graph(spdx_file)
+
+ recipes = {} # namespace -> {"name": ..., "release_date": ...}
+ for element in graph:
+ if element.get("type") != "software_Package":
+ continue
+
+ namespace = doc_namespace(element.get("spdxId"))
+ if namespace is None:
+ continue
+
+ if element.get("software_primaryPurpose") == "specification" and element.get("name"):
+ # The recipe itself, as opposed to its runtime package(s).
+ recipes[namespace] = {
+ "name": element["name"],
+ "release_date": element.get("releaseTime"),
+ }
+
+ report = [_to_row(info["name"], info["release_date"]) for info in recipes.values()]
+ report.sort(key=lambda r: r["recipe"])
+ return report
+
+
+def filter_rows(report, missing_only, sort_by_date=False):
+ rows = [r for r in report if not missing_only or not r["valid_date"]]
+ if sort_by_date:
+ rows.sort(key=lambda r: (not r["valid_date"], r["release_date"], r["recipe"]))
+ return rows
+
+
+def print_table(rows):
+ if not rows:
+ print("No matching recipes found.")
+ return
+
+ name_width = max(len("recipe"), *(len(r["recipe"]) for r in rows))
+ print(f"{'recipe':<{name_width}} {'release_date':<21} valid")
+ for r in rows:
+ print(f"{r['recipe']:<{name_width}} {r['release_date']:<21} {r['valid_date']}")
+
+
+def write_csv(rows, path):
+ with open(path, "w", newline="", encoding="utf-8") as f:
+ writer = csv.writer(f)
+ writer.writerow(["recipe", "release_date", "valid_date"])
+ for r in rows:
+ writer.writerow([r["recipe"], r["release_date"], r["valid_date"]])
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Report recipe release dates from SPDX 3.0.1 output"
+ )
+ parser.add_argument(
+ "--deploy-dir",
+ required=True,
+ help="Path to DEPLOY_DIR_SPDX (e.g. tmp/deploy/spdx/3.0.1) or to a "
+ "single merged image SBOM file (e.g. "
+ "tmp/deploy/images/<machine>/<image>.rootfs.spdx.json)",
+ )
+ parser.add_argument(
+ "--missing-only",
+ action="store_true",
+ help="Only report recipes without a valid release date",
+ )
+ parser.add_argument(
+ "--csv",
+ help="Write the report to a CSV file instead of only printing a table",
+ )
+ parser.add_argument(
+ "--sort-by-date",
+ action="store_true",
+ help="Sort output by release date instead of recipe name (missing dates last)",
+ )
+ args = parser.parse_args()
+
+ logging.basicConfig(format="[%(filename)s:%(lineno)d] %(message)s", level=logging.INFO)
+
+ if os.path.isdir(args.deploy_dir):
+ report = build_report(args.deploy_dir)
+ elif os.path.isfile(args.deploy_dir):
+ report = build_report_from_file(args.deploy_dir)
+ else:
+ parser.error(f"--deploy-dir {args.deploy_dir} does not exist")
+
+ total = len(report)
+ valid = sum(1 for r in report if r["valid_date"])
+ logging.info("Recipes with SPDX static data: %d", total)
+ logging.info("Recipes with a valid release date: %d", valid)
+ logging.info("Recipes missing a release date: %d", total - valid)
+
+ rows = filter_rows(report, args.missing_only, args.sort_by_date)
+ print_table(rows)
+
+ if args.csv:
+ write_csv(rows, args.csv)
+ logging.info("CSV report written to %s", args.csv)
+
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [OE-core] [PATCH v3 2/3] create-spdx-3.0: record component release date in SPDX output
2026-09-28 19:03 ` [PATCH v3 2/3] create-spdx-3.0: record component release date in SPDX output daniel.turull
@ 2026-09-28 20:59 ` Richard Purdie
2026-09-29 4:54 ` Daniel Turull
0 siblings, 1 reply; 9+ messages in thread
From: Richard Purdie @ 2026-09-28 20:59 UTC (permalink / raw)
To: daniel.turull, openembedded-core; +Cc: JPEWhacker, mathieu.dubois-briand
On Mon, 2026-09-28 at 21:03 +0200, Daniel Turull via lists.openembedded.org wrote:
> From: Daniel Turull <daniel.turull@ericsson.com>
>
> Record each recipe's release date in the releaseTime property of its
> software_Package object, using the SOURCE_DATE_EPOCH already computed
> for reproducible builds.
>
> Accuracy depends on how SOURCE_DATE_EPOCH was derived: exact for
> git-tagged recipes, best-effort for tarball/http(s) sources. Some
> Python sdists (e.g. cryptography, hypothesis, maturin) normalize all
> file mtimes to a fixed placeholder, so their releaseTime reflects
> packaging-tool behavior, not the real release date.
>
> Tested with oe-selftest -r spdx, and with `bitbake world
> --runall=do_create_spdx`: 1011/1150 recipes got a releaseTime (range
> 1998-12-30 to 2026-09-17), 139 correctly had none.
>
> AI-Generated: Uses Kiro with Claude Sonnet 5
> Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
> ---
> v2:
> - Dropped all options per Joshua's feedback; read SDE_FILE directly.
> - Dropped the redundant else: delattr(recipe, "releaseTime") branch.
> - Selftest compares against SDE_FILE content directly instead of
> SOURCE_DATE_EPOCH, which can diverge from it.
> - Fixed a leak: recipes with no git checkout and no fetched source
> had SDE_FILE holding only SOURCE_DATE_EPOCH_FALLBACK, showing a
> bogus 2011-04-05T23:00:00Z releaseTime instead of none.
> v3:
> - Also run after do_unpack: do_deploy_source_date_epoch's setscene
> shortcut can skip it, leaving SOURCE_DATE_EPOCH unset.
> - get_release_date() reads SOURCE_DATE_EPOCH again instead of
> SDE_FILE, now that they're guaranteed equivalent.
> - test_release_date_source_date_epoch: switched to tar (base-files
> has S == UNPACKDIR and never gets a real SOURCE_DATE_EPOCH).
> - Added test_release_date_omitted_for_fallback_value.
> ---
> meta/classes/create-spdx-3.0.bbclass | 2 +-
> meta/lib/oe/spdx30_tasks.py | 19 ++++++++++++++
> meta/lib/oeqa/selftest/cases/spdx.py | 39 ++++++++++++++++++++++++++++
> 3 files changed, 59 insertions(+), 1 deletion(-)
>
> diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass
> index 56fd01fd53..2b1465b5a6 100644
> --- a/meta/classes/create-spdx-3.0.bbclass
> +++ b/meta/classes/create-spdx-3.0.bbclass
> @@ -192,7 +192,7 @@ python do_create_recipe_spdx() {
> import oe.spdx30_tasks
> oe.spdx30_tasks.create_recipe_spdx(d)
> }
> -addtask do_create_recipe_spdx
> +addtask do_create_recipe_spdx after do_unpack do_deploy_source_date_epoch
>
> SSTATETASKS += "do_create_recipe_spdx"
> do_create_recipe_spdx[sstate-inputdirs] = "${SPDXRECIPEDEPLOY}"
I'm not really very happy about this part of the change. The "recipe"
SPDX data was meant to be the data which can be obtained from the
recipe without fetching the sources. This changes that and adds a
fetch/unpack requirement. At this point it may as well be merged with
other SPDX data that being generated "later" in the build as the
"recipe" only data is losing it's meaning?
Cheers,
Richard
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [OE-core] [PATCH v3 2/3] create-spdx-3.0: record component release date in SPDX output
2026-09-28 20:59 ` [OE-core] " Richard Purdie
@ 2026-09-29 4:54 ` Daniel Turull
0 siblings, 0 replies; 9+ messages in thread
From: Daniel Turull @ 2026-09-29 4:54 UTC (permalink / raw)
To: richard.purdie@linuxfoundation.org,
openembedded-core@lists.openembedded.org
Cc: JPEWhacker@gmail.com, mathieu.dubois-briand@bootlin.com
On Mon, 2026-09-28 at 21:59 +0100, Richard Purdie wrote:
> On Mon, 2026-09-28 at 21:03 +0200, Daniel Turull via lists.openembedded.org wrote:
> > From: Daniel Turull <daniel.turull@ericsson.com>
> >
> > Record each recipe's release date in the releaseTime property of its
> > software_Package object, using the SOURCE_DATE_EPOCH already computed
> > for reproducible builds.
> >
> > Accuracy depends on how SOURCE_DATE_EPOCH was derived: exact for
> > git-tagged recipes, best-effort for tarball/http(s) sources. Some
> > Python sdists (e.g. cryptography, hypothesis, maturin) normalize all
> > file mtimes to a fixed placeholder, so their releaseTime reflects
> > packaging-tool behavior, not the real release date.
> >
> > Tested with oe-selftest -r spdx, and with `bitbake world
> > --runall=do_create_spdx`: 1011/1150 recipes got a releaseTime (range
> > 1998-12-30 to 2026-09-17), 139 correctly had none.
> >
> > AI-Generated: Uses Kiro with Claude Sonnet 5
> > Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
> > ---
> > v2:
> > - Dropped all options per Joshua's feedback; read SDE_FILE directly.
> > - Dropped the redundant else: delattr(recipe, "releaseTime") branch.
> > - Selftest compares against SDE_FILE content directly instead of
> > SOURCE_DATE_EPOCH, which can diverge from it.
> > - Fixed a leak: recipes with no git checkout and no fetched source
> > had SDE_FILE holding only SOURCE_DATE_EPOCH_FALLBACK, showing a
> > bogus 2011-04-05T23:00:00Z releaseTime instead of none.
> > v3:
> > - Also run after do_unpack: do_deploy_source_date_epoch's setscene
> > shortcut can skip it, leaving SOURCE_DATE_EPOCH unset.
> > - get_release_date() reads SOURCE_DATE_EPOCH again instead of
> > SDE_FILE, now that they're guaranteed equivalent.
> > - test_release_date_source_date_epoch: switched to tar (base-files
> > has S == UNPACKDIR and never gets a real SOURCE_DATE_EPOCH).
> > - Added test_release_date_omitted_for_fallback_value.
> > ---
> > meta/classes/create-spdx-3.0.bbclass | 2 +-
> > meta/lib/oe/spdx30_tasks.py | 19 ++++++++++++++
> > meta/lib/oeqa/selftest/cases/spdx.py | 39 ++++++++++++++++++++++++++++
> > 3 files changed, 59 insertions(+), 1 deletion(-)
> >
> > diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass
> > index 56fd01fd53..2b1465b5a6 100644
> > --- a/meta/classes/create-spdx-3.0.bbclass
> > +++ b/meta/classes/create-spdx-3.0.bbclass
> > @@ -192,7 +192,7 @@ python do_create_recipe_spdx() {
> > import oe.spdx30_tasks
> > oe.spdx30_tasks.create_recipe_spdx(d)
> > }
> > -addtask do_create_recipe_spdx
> > +addtask do_create_recipe_spdx after do_unpack do_deploy_source_date_epoch
> >
> > SSTATETASKS += "do_create_recipe_spdx"
> > do_create_recipe_spdx[sstate-inputdirs] = "${SPDXRECIPEDEPLOY}"
>
> I'm not really very happy about this part of the change. The "recipe"
> SPDX data was meant to be the data which can be obtained from the
> recipe without fetching the sources. This changes that and adds a
> fetch/unpack requirement. At this point it may as well be merged with
> other SPDX data that being generated "later" in the build as the
> "recipe" only data is losing it's meaning?
>
ok, I was a bit hesitant on this change as well. I'll check how can it be added
later in the process without touching the task dependencies and order.
Cheers,
Daniel
> Cheers,
>
> Richard
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [OE-core] [PATCH v3 0/3] spdx: add support to include releaseTime
2026-09-28 19:03 [PATCH v3 0/3] spdx: add support to include releaseTime daniel.turull
` (2 preceding siblings ...)
2026-09-28 19:04 ` [PATCH v3 3/3] scripts/contrib: add spdx-release-date-report.py daniel.turull
@ 2026-09-29 6:16 ` Yoann Congal
2026-09-29 6:36 ` Daniel Turull
3 siblings, 1 reply; 9+ messages in thread
From: Yoann Congal @ 2026-09-29 6:16 UTC (permalink / raw)
To: daniel.turull, openembedded-core; +Cc: JPEWhacker, mathieu.dubois-briand
On Mon Sep 28, 2026 at 9:03 PM CEST, Daniel Turull via lists.openembedded.org wrote:
> From: Daniel Turull <daniel.turull@ericsson.com>
>
> We have a requirements to include release time of open source components
> in the SBOM. There is a field specific for that in spdx 3 spec.
>
> https://spdx.github.io/spdx-spec/v3.0.1/model/Core/Properties/releaseTime/
>
> This can also be used to evaluate how old are some of the core
> components and decide if they need replacement.
>
> The previous 2 versions did not have cover letter.
>
> Tested with oe-selftest -r spdx
>
> Daniel Turull (3):
> classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash
> create-spdx-3.0: record component release date in SPDX output
> scripts/contrib: add spdx-release-date-report.py
>
> meta/classes-global/base.bbclass | 4 +
> meta/classes/create-spdx-3.0.bbclass | 2 +-
> meta/lib/oe/spdx30_tasks.py | 19 ++
> meta/lib/oeqa/selftest/cases/spdx.py | 39 ++++
> scripts/contrib/spdx-release-date-report.py | 193 ++++++++++++++++++++
> 5 files changed, 256 insertions(+), 1 deletion(-)
> create mode 100755 scripts/contrib/spdx-release-date-report.py
Hello,
Note: while this is not a fix, this looks related to
https://bugzilla.yoctoproject.org/show_bug.cgi?id=15530
Thanks!
--
Yoann Congal
Smile ECS
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [OE-core] [PATCH v3 0/3] spdx: add support to include releaseTime
2026-09-29 6:16 ` [OE-core] [PATCH v3 0/3] spdx: add support to include releaseTime Yoann Congal
@ 2026-09-29 6:36 ` Daniel Turull
0 siblings, 0 replies; 9+ messages in thread
From: Daniel Turull @ 2026-09-29 6:36 UTC (permalink / raw)
To: openembedded-core@lists.openembedded.org, yoann.congal@smile.fr
Cc: JPEWhacker@gmail.com, mathieu.dubois-briand@bootlin.com
On Tue, 2026-09-29 at 08:16 +0200, Yoann Congal wrote:
> On Mon Sep 28, 2026 at 9:03 PM CEST, Daniel Turull via lists.openembedded.org wrote:
> > From: Daniel Turull <daniel.turull@ericsson.com>
> >
> > We have a requirements to include release time of open source components
> > in the SBOM. There is a field specific for that in spdx 3 spec.
> >
> > https://spdx.github.io/spdx-spec/v3.0.1/model/Core/Properties/releaseTime/
> >
> > This can also be used to evaluate how old are some of the core
> > components and decide if they need replacement.
> >
> > The previous 2 versions did not have cover letter.
> >
> > Tested with oe-selftest -r spdx
> >
> > Daniel Turull (3):
> > classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash
> > create-spdx-3.0: record component release date in SPDX output
> > scripts/contrib: add spdx-release-date-report.py
> >
> > meta/classes-global/base.bbclass | 4 +
> > meta/classes/create-spdx-3.0.bbclass | 2 +-
> > meta/lib/oe/spdx30_tasks.py | 19 ++
> > meta/lib/oeqa/selftest/cases/spdx.py | 39 ++++
> > scripts/contrib/spdx-release-date-report.py | 193 ++++++++++++++++++++
> > 5 files changed, 256 insertions(+), 1 deletion(-)
> > create mode 100755 scripts/contrib/spdx-release-date-report.py
>
> Hello,
>
> Note: while this is not a fix, this looks related to
> https://bugzilla.yoctoproject.org/show_bug.cgi?id=15530
>
> Thanks!
Thanks for the pointer Yoann. I'll take a look if I can do something with the
ticket once I have the current series right.
Definitely the ticket is going in that direction that I was thinking.
Daniel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash
2026-09-28 19:03 ` [PATCH v3 1/3] classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash daniel.turull
@ 2026-09-29 14:53 ` Joshua Watt
0 siblings, 0 replies; 9+ messages in thread
From: Joshua Watt @ 2026-09-29 14:53 UTC (permalink / raw)
To: daniel.turull; +Cc: openembedded-core, mathieu.dubois-briand
[-- Attachment #1: Type: text/plain, Size: 1584 bytes --]
LGTM, thanks
Reviewed-by: Joshua Watt <JPEWhacker@gmail.com>
On Mon, Sep 28, 2026 at 1:04 PM <daniel.turull@ericsson.com> wrote:
> From: Daniel Turull <daniel.turull@ericsson.com>
>
> epochfile_read() memoizes its result into __CACHED_SOURCE_DATE_EPOCH
> via d.setVar(), so its runtime value leaks into the basehash of any
> task that calls it, causing a "metadata is not deterministic" error
> once SDE_FILE is populated.
>
> Exclude it, since it is not meaningful build metadata.
>
> AI-Generated: Uses Kiro with Claude Sonnet 5
> Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
> ---
> This should fix the selftest errors reported by Mathieu
> ---
> meta/classes-global/base.bbclass | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/meta/classes-global/base.bbclass
> b/meta/classes-global/base.bbclass
> index 9553f00432..01a030399e 100644
> --- a/meta/classes-global/base.bbclass
> +++ b/meta/classes-global/base.bbclass
> @@ -249,6 +249,10 @@ do_unpack[postfuncs] +=
> "create_source_date_epoch_stamp"
> def get_source_date_epoch_value(d):
> return oe.reproducible.epochfile_read(d.getVar('SDE_FILE'), d)
>
> +# epochfile_read() memoizes into this variable via d.setVar(), so its
> +# runtime value must not leak into any task's hash.
> +oe.reproducible.epochfile_read[vardepsexclude] =
> "__CACHED_SOURCE_DATE_EPOCH"
> +
> def get_layers_branch_rev(d):
> revisions = oe.buildcfg.get_layer_revisions(d)
> layers_branch_rev = ["%-20s = \"%s:%s\"" % (r[1], r[2], r[3]) for r
> in revisions]
>
[-- Attachment #2: Type: text/html, Size: 2238 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-09-29 14:53 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-28 19:03 [PATCH v3 0/3] spdx: add support to include releaseTime daniel.turull
2026-09-28 19:03 ` [PATCH v3 1/3] classes/base: exclude __CACHED_SOURCE_DATE_EPOCH from task hash daniel.turull
2026-09-29 14:53 ` Joshua Watt
2026-09-28 19:03 ` [PATCH v3 2/3] create-spdx-3.0: record component release date in SPDX output daniel.turull
2026-09-28 20:59 ` [OE-core] " Richard Purdie
2026-09-29 4:54 ` Daniel Turull
2026-09-28 19:04 ` [PATCH v3 3/3] scripts/contrib: add spdx-release-date-report.py daniel.turull
2026-09-29 6:16 ` [OE-core] [PATCH v3 0/3] spdx: add support to include releaseTime Yoann Congal
2026-09-29 6:36 ` Daniel Turull
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox