Software Bill of Materials

The Software Bill of Materials (SBOM) is a west extension command that can be invoked by west ncs-sbom. It provides a list of used licenses for an application build or specific files.

Note

Generating a list of licenses from an application build is experimental. The accuracy of detection is constantly verified. Both implementation and usage may change in the future.

Overview

The process of using the ncs-sbom command involves the following steps:

  1. Create a list of input files based on provided command-line arguments, for example, all source files used for building a specific application. For details, see Specifying input.

  2. Detect the license applied to each file, for example, read SPDX identifier from SPDX-License-Identifier tag. For details, see Detectors.

  3. Create an output report containing all the files and license information related to them. Depending on the selected output format, the command can also group files into packages and include package metadata in the report, for example, write a report file in HTML format. For details, see Specifying output.

When the input is a build directory, the command starts from the linked target, walks the Ninja dependency graph to collect build inputs, validates the result against the .map file, and checks archive contents with the GNU ar tool.

Requirements

The ncs-sbom command requires installation of additional Python packages.

Use the following command to install the requirements.

Enter the following command in a command-line window in the ncs folder:

pip3 install -r nrf/scripts/requirements-west-ncs-sbom.txt

Note

The scancode-toolkit detector relies on the Scancode-Toolkit, which is not part of the standard nRF Connect SDK toolchain bundle. On Windows and Linux, the requirements-west-ncs-sbom.txt file installs ScanCode Toolkit together with its Python dependencies.

On Linux, ScanCode Toolkit requires installation of additional system dependencies. To install the required tools on Ubuntu, run:

sudo apt install python-dev bzip2 xz-utils zlib1g libxml2-dev libxslt1-dev libpopt0

On macOS with Apple Silicon installing ScanCode Toolkit with pip is not supported. Install ScanCode Toolkit separately from a release archive and use --scancode to point to the executable if needed.

For more details, see Scancode-Toolkit Installation.

Using the command

The following examples demonstrate the basic usage of the ncs-sbom command. The input options and output options can be combined as needed.

  • To see the help, run the following command:

    west ncs-sbom -h
    
  • To analyze a build directory and generate the default HTML report in the build directory run:

     west ncs-sbom -d build-directory
  • To analyze a build directory and generate an SPDX report run:

    west ncs-sbom -d build-directory --output-spdx file-name.spdx
  • To analyze selected files and generate an HTML report run:

    west ncs-sbom --input-files file1 file2 --output-html file-name.html
  • To analyze selected files and generate an SPDX report run:

    west ncs-sbom --input-files file1 file2 --output-spdx file-name.spdx

Specifying input

You can specify all input options several times to provide more input for the report generation, for example, generate a report for two applications. You can also mix them, for example, to generate a report for the application and some directory.

  • To get an application SBOM from a build directory, use the following option:

    -d build_directory
    

    You have to first build the build_directory with the west build command using Ninja as the underlying build tool (default). The build must be successful. Any change in the application configuration may affect the results, so always rebuild it after reconfiguration and before calling the west ncs-sbom.

    You can skip this option if you are in the application directory and you have a default build directory there - the same way as in west build command.

    The Extracting a list of files from a build directory section describes in detail how to extract a list of files from a build directory.

    You can use the -d option multiple times. For example, to include both the mcuboot child image and the main application, use the following command:

    west ncs-sbom -d build -d build/mcuboot

    Note

    If the build directory is a sysbuild root (contains domains.yaml) the command runs one analysis for each domain. It generates one output file for each requested output format and each domain. For example, with the default settings it generates one HTML report for each domain. If both HTML and SPDX outputs are requested, it generates two files for each domain. To adjust the output file names, append _<domain> before the extension (for example, sbom_report_with_mcuboot.html). To control where {domain} appears in the filename, include {domain} in --output-html or --output-spdx (for example, --output-spdx sbom_{domain}_sysbuild.spdx). In PS, escape the curly braces with backticks.

    Note

    All files that are not dependencies of the zephyr/zephyr.elf target are not taken as an input. If you modify the .elf file after the linking, the modifications are not applied.

    The -d option is experimental.

    Note

    The build directory input expects the standard west/CMake/Ninja files including build.ninja, CMakeCache.txt and the target .map file. The same flow can also be used for nRF Connect SDK Bare Metal applications if the build directory provides these files.

    Note

    Toolchain package detection uses metadata written by the build system. The built-in runtime license mappings cover the Zephyr SDK layouts bundled with nRF Connect SDK including arm-zephyr-eabi and riscv64-zephyr-elf.

  • Provide a list of input files directly on the command line:

    --input-files file1 file2 ...

    Each argument of this option can contain globs as defined by Python’s Path.glob with two additions:

    • Support for absolute paths.

    • Exclamation mark ! to exclude files.

    For example, if you want to include all .c files from the current directory and all subdirectories recursively:

    --input-files '**/*.c'
    

    Make sure to have correct quotes around globs, to not have the glob resolved by your shell, and go untouched to the command.

    You can prefix a pattern with the exclamation mark ! to exclude some files. Patterns are evaluated from left to right, so ! excludes files from patterns before it, but not after. For example, if you want to include all .c files from the current directory and all subdirectories recursively except all main.c files, run:

    --input-files '**/*.c' '!**/main.c'
    
  • Read a list of input files from a file:

    --input-list-file list_file

    It does the same as --input-files, but it reads files and patterns from a file (one file or pattern per line). Files and patterns contained in the list file are relative to the list file location (not the current directory). Comments starting with a # character are allowed.

Specifying output

You can specify the format of the report output using the output argument.

  • To generate a report in HTML format:

    --output-html file-name.html

    The HTML report overview section provides more details about the report.

    If you use the -d option, you do not need to specify any output argument. The sbom_report.html file is generated in your build directory (the first one if you specify more than one build directory).

  • To generate an SPDX 2.2 format report (for CRA/EO 14028/FDA compliance):

    --output-spdx file-name.spdx

    The SPDX report groups files into packages and includes:

    • Package supplier information (auto-detected from git URLs or specified via --package-supplier)

    • Component name, version, and download location

    • Package URLs (PURLs) for unique package identification

    • Common Platform Enumeration (CPE) identifiers when specified via --package-cpe

    • Dependency relationships showing supply chain connections

    • File checksums and license information

    SPDX 2.2 is currently the supported machine-readable standardized output format.

    This format meets requirements from:

    • Cyber Resilience Act (CRA)

    • U.S. Executive Order 14028

    • FDA cybersecurity guidelines

  • To generate a cache database:

    --output-cache-database cache-database.json

    For details, see cache-database detector.

Detectors

The ncs-sbom command includes the following detectors:

  • spdx-tag - Search for the SPDX-License-Identifier in the source code or the binary file.

    For guidelines, see SPDX identifier. Enabled by default.

  • full-text - Compare the contents of the source file with a small database of reference texts.

    The database is part of the ncs-sbom command. Enabled by default.

  • scancode-toolkit - License detection by the Scancode-Toolkit. Enabled and optional by default.

    If the scancode command is not on your PATH, you can use the --scancode option to provide it, for example:

    --scancode ~/scancode-toolkit/scancode
    

    This detector is optional because it is significantly slower than the others. Due to its limitations, it is run on single files one by one using a single process.

  • external-file - Search for license information in an external file. Enabled by default.

    The external file has the following properties:

    • It is located in the same directory as the file under detection or in one of its parent directories .

    • Its name contains LICENSE, LICENCE or COPYING (case insensitive).

    • It has an SPDX-License-Identifier tag.

    • It has one or several NCS-SBOM-Apply-To-File tags containing file paths or globs (as defined by the Python’s Path.glob). They are relative to the external file.

    If any of the NCS-SBOM-Apply-To-File tags matches the file under detection, the license from the SPDX tag is used, for example:

    /* The following lines will apply Nordic 5-Clause license to all ".a" files
     * and ".lib" files in the "lib" directory and all its subdirectories.
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     * NCS-SBOM-Apply-To-File: lib/**/*.a
     * NCS-SBOM-Apply-To-File: lib/**/*.lib
     */
    

    This mechanism is also used for precompiled libraries including libraries in sdk-nrfxlib.

  • cache-database - Use license information detected and cached earlier in the cache database file. Disabled by default.

    Provide the cache database file using the following argument:

    --input-cache-database cache-database.json

    Each database entry has a path relative to the west workspace directory, a hash, and a list of detected licenses. If the file under detection has the same path and hash, the list of licenses from the database is used.

    Note

    To generate the database based on, for example the scancode-toolkit detector, run the following command:

    west ncs-sbom --input-files files ... --license-detectors scancode-toolkit --output-cache-database cache-database.json
  • git-info - Detect the source repository URL and revision for files and group files into packages. Enabled by default.

    The information is used in the HTML and SPDX outputs to group files into packages. If --package-supplier is not provided the supplier is auto-detected from the repository URL.

If you prefer a non-default set of detectors, you can provide a list of comma-separated detectors with the --license-detectors option, for example:

--license-detectors spdx-tag,scancode-toolkit

Some of the detectors are optional, which means that they are not executed for a file that already has licenses detected by some other previously executed detector. Detectors are executed from left to right using a list provided by the --license-detectors.

--optional-license-detectors scancode-toolkit

Some detectors may run in parallel on all available CPU cores, which speeds up the detection time. Use the -n option to limit the number of parallel threads or processes.

Compliance Options

The following options enhance SBOM compliance with CRA, EO 14028, and FDA requirements:

  • --package-supplier - Set the supplier/vendor name for packages:

    --package-supplier "Nordic Semiconductor ASA"
    

    If not specified, the supplier is auto-detected from git repository owner/organization names.

  • --package-cpe - Set the Common Platform Enumeration (CPE) identifier:

    --package-cpe "cpe:2.3:a:nordicsemi:nrf_connect_sdk:2.0.0:*:*:*:*:*:*:*"
    

    CPE identifiers follow the CPE 2.3 specification and help identify software packages in vulnerability databases.

These options ensure that generated SBOMs include all required fields for regulatory compliance.

HTML report overview

The HTML report has following structure:

  • Summary of the report, containing the following:

    • Notes at the beginning.

      General information on the report.

    • List of inputs.

      The file sources.

    • List of licenses.

      All licenses detected in the input files.

    • List of added license texts.

      If a license is not in the SPDX License List and it is in the internal database, the license text is added to the report.

    You can click links in the summary to get more details about specific items.

  • List of files without any license information or with license information that cannot be detected automatically.

    You have to investigate them manually to get the license information.

  • Details about each detected license:

    • License identifier.

    • Information if it is a standard SPDX license.

    • License name if available.

    • Link to license text or more details if available.

    • All files from the input covered by this license.

  • Details about each detected package:

    • Package name and version if available.

    • URL if available.

    • Licenses detected in files from the package.

  • License texts added to this report.

Extracting a list of files from a build directory

The ncs-sbom extracts a list of files from a build directory. It queries ninja for the targets and dependencies.

The entry point is the zephyr/zephyr.elf target file. The script asks ninja for all input targets of the zephyr/zephyr.elf target. It also asks for all input targets of the previously extracted input targets, until it reaches all leaves in the dependency tree. The result is a list of all the leaves.

To change the target or specify multiple targets, you can add them after the build directory in the -d option, for example:

-d build_directory target1.elf target2.elf

There are two additional methods for improving the correctness of the above algorithm:

  • Each library is examined using the GNU ar tool.

    If the list of files returned by the GNU ar tool is covered by the list returned from the ninja, the list is assumed to be valid. Otherwise, the library is assumed to be a leaf, so it is shown in the report and its inputs are not analyzed further.

  • The ncs-sbom parses the .map file created during the zephyr/zephyr.elf linking.

    It provides a list of all object files and libraries linked to the zephyr/zephyr.elf file. The script ends with a fatal error if any file in the .map file is not visible by ninja.

    Exceptions are the runtime and standard libraries. You can specify the list of exceptions with the --allowed-in-map-file-only option. By default, it contains common names for the runtime and standard libraries including libgcc.a, libc*.a, libstdc++*.a, libm*.a, crti.o, crt0.o, crtn.o, crtbegin.o, and crtend.o.

    If the .map file and the associated .elf file have different names, you can provide the .map file after the : sign following the target, for example:

    -d build_directory target.elf:file.map

Integration with the GN meta-build system

The ncs-sbom script reads a list of all commands needed to build provided targets. If there is a gn gen command, the script enters the command’s build directory and tries to extract files from it using the same method as described earlier. The results are integrated with the main build directory results.

This also applies to applications that use GN-based external projects such as Matter applications.