Torizon Yocto SBOM

Hi,

I have a yocto build based on torizon-core-docker with a couple of extra layers.

I am trying to run the SBOM through cve bin tool. I have tested one of the published SBOM’s from https://artifacts.toradex.com/ui/ and that runs successfully.

I have enabled the SBOM generation flags as described in the Yocto documentation https://docs.yoctoproject.org/4.2/dev-manual/sbom.html. However, the output files from the build have the extension spdx.json instead of .spdx. I have looked at the documentation published here - https://developer.toradex.com/torizon/traceability/sbom/ which requires the SBOM to be in the format of spdx to run through the cve bin tool.

Looking at the other posts on the forum I have seen that the SBOM’s that are published are generated from Yocto. https://community.toradex.com/t/where-to-find-the-sbom-for-a-torizon-build/21257/2 I have looked online and cannot get Yocto to output the files in the correct format. Is there another process that is taking place in-between generating the SBOM and publishing the SBOM on the artifacts webpage.

The Yocto SBOM contents also differs from the artifacts SBOM.

Kind Regards

Hi, I’m the Toradex AI Assistant.

I might make mistakes. Our support team will step in if needed. If I answered your question, please tick the “Solution” checkbox. For follow-up questions to me, please use @ToradexAI in your post.

Did you like my answer? :+1: :-1:


Hello! Thank you for reaching out with your question.

You’ve correctly noted that Toradex publishes merged SBOMs in SPDX (tag-value or .spdx) format for Torizon OS images—these download and work directly with cve-bin-tool(1)(2). However, when you enable SBOM generation in Yocto, you typically receive per-package SBOM files in SPDX JSON format (with the .spdx.json extension). By default, Yocto (as of 4.x) generates SBOMs in JSON only.

The Toradex documentation doesn’t specify additional scripts or tools used to convert these .spdx.json files into the merged .spdx tag-value format—only that the merged files are provided for Torizon OS builds from their build infrastructure.

Here’s what you can do to work toward the format that cve-bin-tool expects:

Options for Converting Yocto SBOM Output

1. Convert SPDX JSON to Tag-Value Format

There are open source tools developed by the SPDX community that can convert between SPDX formats:

  • spdx-tools Python library
    You can use spdx-tools to convert JSON to tag-value:
    pip install spdx-tools
    spdx-convert spdx.json spdx
    
    Adjust the filenames as needed for your case.

2. Merge SBOM Files

If your build creates multiple SBOMs (one for each package), you will need to merge them before running tools like cve-bin-tool. Unfortunately, Yocto doesn’t do this natively.

  • The SPDX community and other third-party tools provide SBOM merging utilities.
  • Alternatively, review Toradex’s documentation on SBOMs; the published SBOMs can serve as a format reference.

3. Using the SBOM with cve-bin-tool

Once you have a merged .spdx (tag-value) file, you can run:

cve-bin-tool --sbom spdx --sbom-file merged-output.spdx

(1)

Summary

  • Yocto generates .spdx.json files, which need to be converted and merged for use with security tools.
  • Toradex’s build process for the official images generates a merged .spdx file, but the process (likely involving conversion and merging) is not detailed publicly.
  • Use SPDX tools to convert/merge your SBOMs to the tag-value .spdx format for compatibility.

Useful Links:

If you need specific guidance on using any of these tools or further clarification, feel free to ask!

Best regards,
Toradex AI Assistant.

Greetings @DAH,

You are correct that Yocto produces a bunch of *.spdx.json files when enabling SBOMs during the build.

What we do, is we actually use another tool to take all of those *.spdx.json files and merges them into a single master *.spdx file. We use this tool here in our internal builds: GitHub - philips-software/SPDXMerge: SPDX Merge tool

Fortunately this tool also comes as a container for easier execution. To be clear this is what we do in our builds:

  • After your Yocto build is done if SBOM was enabled in your deploy directory there should be a *.spdx.tar.zst file that contains all the individual *.spdx.json files for the various packages/software that comprises the build.
  • This tarball gets unpacked into a temporary directory.
  • In the unpacked contents there is a index.json file this is not actually an SBOM file, delete it before proceeding.
  • We then execute the following docker command:
docker run --rm -v <path to unpacked tarball directory>:/code -v <path to your deploy directory>:/output -e DOCPATH=/code -e OUTPATH=/output -e NAME=toradex-sbom -e MERGETYPE=1 -e AUTHOR=Toradex -e EMAIL=cicd@toradex.com -e DOCNAMESPACE=https://spdx.toradex.com -e FILETYPE=T docker.io/philipssoftware/spdxmerge:v0.2.0

This will take all the *.spdx.json files and merge them into a single *.spdx file. You should be able to use this with various CVE tools. Feel free to tweak the arguments of the command to better fit your case. The arguments are better described on the Github repo for the tool I linked above.

Best Regards,
Jeremias

Hi Jeremias,

Thank you so much for the comprehensive reply.

I will give this a try and report back.

Kind Regards

Glad we were able to help. Please do let us know if it works for you.

Meanwhile we’ll see about having these instructions properly documented on our developer website.

Best Regards,
Jeremias

Hi Jeremias,

I have managed to get spdx.json files merged into a single *.spdx using the SPDXMerge tool. However, it does not work when I use your command to create a container. It only works when I run the python script outside of a container.

When running just the python scripts with the same input files it works.

torizon@training:~/sbom$ python SPDXMerge/spdxmerge/SPDXMerge.py --docpath /home/torizon/sbom/input/ --outpath /home/torizon/sbom/output/ --name debug-sbom --version 2.2 --mergetype 1 --author debug --email hello@world.com --docnamespace https://debug.com --filetype T
File /home/torizon/sbom/output/merged-SBoM-deep.spdx is generated

However when running the docker command which does not work.

torizon@training:~/sbom$ docker run --rm -v /home/torizon/sbom/input/:/code -v /home/torizon/sbom:/output -e DOCPATH=/code -e OUTPATH=/output -e NAME=debug-sbom -e MERGETYPE=1 -e AUTHOR=Debug -e EMAIL=hello@world.com -e DOCNAMESPACE=https://debug.com -e FILETYPE=T docker.io/philipssoftware/spdxmerge:v0.2.0
arguments:
 - DOCPATH      : /code
 - OUTPATH      : /output
 - NAME         : debug-sbom
 - MERGETYPE    : 1
 - AUTHOR       : Debug
 - EMAIL        : hello@world.com
 - DOCNAMESPACE : https://debug.com
 - FILETYPE     : T
Traceback (most recent call last):
  File "/app/spdxmerge/SPDXMerge.py", line 35, in <module>
    main()
  File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/spdxmerge/SPDXMerge.py", line 28, in main
    doc_list = read_docs(docpath)
               ^^^^^^^^^^^^^^^^^^
  File "/app/spdxmerge/utils.py", line 9, in read_docs
    doc, _error = parse_anything.parse_file(dir+"/"+file)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/spdx/parsers/parse_anything.py", line 53, in parse_file
    return p.parse(f)
           ^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/spdx/parsers/jsonparser.py", line 30, in parse
    return super(Parser, self).parse()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/spdx/parsers/jsonyamlxml.py", line 1762, in parse
    self.parse_packages(self.document_object.get("packages"))
  File "/usr/local/lib/python3.11/site-packages/spdx/parsers/jsonyamlxml.py", line 1887, in parse_packages
    self.parse_package(package, self.parse_relationship)
  File "/usr/local/lib/python3.11/site-packages/spdx/parsers/jsonyamlxml.py", line 1165, in parse_package
    self.parse_pkg_declared_license(package.get("licenseDeclared"))
  File "/usr/local/lib/python3.11/site-packages/spdx/parsers/jsonyamlxml.py", line 1496, in parse_pkg_declared_license
    license_object = self.replace_license(
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/spdx/parsers/jsonyamlxml.py", line 327, in replace_license
    license_objects = list(
                      ^^^^^
  File "/usr/local/lib/python3.11/site-packages/spdx/parsers/jsonyamlxml.py", line 329, in <lambda>
    lambda lic: lic.identifier == license_object.identifier,
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'identifier'

Any help would be much appreciated. Thank you

I double-checked and I missed a couple of steps. I see in our automation we remove additional files other than index.json before running the merge:

find "${SPDX_WORK_DIR}" -name "recipe-*" -exec rm '{}' \;
find "${SPDX_WORK_DIR}" -name "kernel-module-*" -exec rm '{}' \;
find "${SPDX_WORK_DIR}" -name "iptables-module-*" -exec rm '{}' \;
find "${SPDX_WORK_DIR}" -name "packagegroup-*" -exec rm '{}' \;
find "${SPDX_WORK_DIR}" -name "runtime-*" -exec rm '{}' \;

If I remove these as well, then the spdx-merge via the container works without error. I don’t really know why it works with the python scripts directly without removing these. Could be a version difference in the scripts packaged with the container image.

I can see the docker image hasn’t been updated in two years: https://hub.docker.com/r/philipssoftware/spdxmerge/tags

While the Github repository has obviously had commits more recent than this. I imagine this could explain the discrepancy in behavior.

Best Regards,
Jeremias

You can also try sbomasm, its a tool which is actively maintained and open-source. It allows you to merge sboms using various algorithms GitHub - interlynk-io/sbomasm: sbomasm: The Complete SBOM Management Toolkit

The tools also allows for edit & remove operations, to make the resulting sbom compliant based on various requirements