@@ -409,6 +409,38 @@ def install_runtime(sitepackages: PathLike) -> None:
409409 wfp .write (rfp .read ())
410410
411411
412+ def copy_sbom_files (dirs : Dirs ) -> None :
413+ """
414+ Copy SBOM files from Python source to the prefix directory.
415+
416+ SBOM files (Software Bill of Materials) document the build dependencies
417+ and source file checksums. These files are available in Python 3.12+.
418+
419+ :param dirs: The working directories
420+ :type dirs: ``relenv.build.common.Dirs``
421+ """
422+ # Find the Python source directory in dirs.sources
423+ python_source = None
424+ if dirs .sources .exists ():
425+ # Look for Python-{version} directory
426+ for entry in dirs .sources .iterdir ():
427+ if entry .is_dir () and entry .name .startswith ("Python-" ):
428+ python_source = entry
429+ break
430+
431+ if python_source :
432+ sbom_files = ["sbom.spdx.json" , "externals.spdx.json" ]
433+ source_misc_dir = python_source / "Misc"
434+ for sbom_file in sbom_files :
435+ source_sbom = source_misc_dir / sbom_file
436+ if source_sbom .exists ():
437+ dest_sbom = pathlib .Path (dirs .prefix ) / sbom_file
438+ shutil .copy2 (str (source_sbom ), str (dest_sbom ))
439+ log .info ("Copied %s to archive" , sbom_file )
440+ else :
441+ log .debug ("SBOM file %s not found (Python < 3.12?)" , sbom_file )
442+
443+
412444def finalize (
413445 env : MutableMapping [str , str ],
414446 dirs : Dirs ,
@@ -553,6 +585,9 @@ def runpip(pkg: Union[str, os.PathLike[str]], upgrade: bool = False) -> None:
553585 runpip (MODULE_DIR .parent , upgrade = True )
554586 else :
555587 runpip ("relenv" , upgrade = True )
588+
589+ copy_sbom_files (dirs )
590+
556591 globs = [
557592 "/bin/python*" ,
558593 "/bin/pip*" ,
@@ -563,6 +598,7 @@ def runpip(pkg: Union[str, os.PathLike[str]], upgrade: bool = False) -> None:
563598 "*.so" ,
564599 "/lib/*.so.*" ,
565600 "*.py" ,
601+ "*.spdx.json" , # Include SBOM files
566602 # Mac specific, factor this out
567603 "*.dylib" ,
568604 ]
0 commit comments