Create SPDX with Yocto
Tags: yoct, spdx, sbom
Published: 2023-02-19 06:07:25

# Overview
Poky(yocto) has support to generate spdx files.(create-spdx.bbclass). This article explains how to use it.  
There are other ways to generate spddx files with using meta-spdxscanner, but they are not described here.  

# How to generate spdx files
At first, you have to do this as usual.  

```bash
$ source oe-init-build-env 
```

Then, edit conf/local.conf as follows.  

```diff
+ INHERIT += "create-spdx"      # required. enable to generate spdx files.
+ SPDX_PRETTY = "1"             # optional. if "1", output spdx files will be formatted.
+ SPDX_INCLUDE_SOURCES = "1"    # optional. if "1", output spdx files includes [file-information section](https://spdx.github.io/spdx-spec/v2.3/file-information/).
+ SPDX_ARCHIVE_SOURCES = "1"    # optional. if "1", bitbake will create source files archive for each package.
+ SPDX_ARCHIVE_PACKAGED = "1"   # optional. if "1", bitbake will create output binary archive for each package.
```

Finally, run build.  

```bash
# for example, `bitbake core-image-minimal`
$ bitbake ${TARGET_IMAGE_NAME}
```

If you want to generate one spdx file for specific package.
Please note that this command output spdx files to ${WORKDIR}/spdx of target package.  

```bash
# for example, `bitbake -c create_spdx gcc`
$ bitbake -c create_spdx ${TARGET_PACKAGE_NAME}

# if you want to confirm ${WORKDIR} of ${TARGET_PACKAGE_NAME}
# for example, `bitbake -e gcc | grep ^WORKDIR=`
$ bitbake -e ${TARGET_PACKAGE_NAME} | grep ^WORKDIR=
```

# Outputs
bitbake outputs as follows.  

```bash
# if you want to confirm ${DEPLOY_DIR}
# for example, `bitbake -e core-image-minimal | grep ^DEPLOY_DIR=`
$ bitbake -e ${TARGET_IMAGE_NAME} | grep ^DEPLOY_DIR= 

# for example, `cd tmp/deploy`
$ cd ${DEPLOY_DIR}
$ tree -d 
.
├── images # Outputs
│   └── ${MACHINE}
│       ├── ${IMAGE_NAME}-${MACHINE}.spdx.index.json
│       ├── ${IMAGE_NAME}-${MACHINE}.spdx.json
│       └── ${IMAGE_NAME}-${MACHINE}.spdx.tar.zst
│
└── spdx   # intermediate product. With the exception of some ARCHIVE files, they are just intermediate generated files and are not explained here.
```

## ${IMAGE_NAME}-${MACHINE}.spdx.json
This is a spdx file for target image. 

</br>

## ${IMAGE_NAME}-${MACHINE}.spdx.index.json
This file includes a spdx file list that is correspondint to packages following below conditions.

* the package installed into target image
* the package depended by packages installed into target image

</br>

## ${IMAGE_NAME}-${MACHINE}.spdx.tar.zst
This archive file contains spdx files listed in ${IMAGE_NAME}-${MACHINE}.spdx.index.json.
There are 3-types of spdx file in this archive.

* ${PN}.spdx.json
* recipe-${PN}.spdx.json
* runtime-${PN}.spdx.json

Only `file-information section` and `relationship information section` of these files are described below.  
The other sections are not so distinctive and should be checked by actually looking at the files.  
If you don't know `file-information section` or `relationship information section`, see following links.

* [file-information section](https://spdx.github.io/spdx-spec/v2.3/file-information/)
* [relationship information section](https://spdx.github.io/spdx-spec/v2.3/relationships-between-SPDX-elements/)

</br>

### ${PN}.spdx.json 
* file-information section(`files`)
    * files created by the target package and installed in the target image
* relationship information section(`relationships`)
    * reference to [the file-information section](https://spdx.github.io/spdx-spec/v2.3/file-information/) of the source files of this package
    * reference to [the file-information section](https://spdx.github.io/spdx-spec/v2.3/file-information/) of the header files of external libraries

</br>

### recipe-${PN}.spdx.json
* file-information section(`files`)
    * the source files of the target package.  
* relationship information section(`relationships`)
    * reference to [the file-information section](https://spdx.github.io/spdx-spec/v2.3/file-information/) of the source files of this package
    * reference to [the file-information section](https://spdx.github.io/spdx-spec/v2.3/file-information/) of the recipe files of external libraries

</br>

### runtime-${PN}.spdx.json
* file-information section(`files`)
    * Nothing
* relationship information section(`relationships`)
    * reference to [the package information section](https://spdx.github.io/spdx-spec/v2.3/package-information/) of the packages this package depends on

# Which information is where?
## installed packages list
```bash
# for example, `cat tmp/deploy/images/qemux86-64/core-image-minimal-qemux86-64.manifest`
$ cat  ${DEPLOY_DIR}/images/${MACHINE}/${TARGET_IMAGE_NAME}-${MACHINE}.manifest
```

## license info of package
```bash
# for example, `tar -I zstd -xvf core-image-minimal-qemux86-64.spdx.tar.zst`
$ tar -I zstd -xvf ${IMAGE_NAME}-${MACHINE}.spdx.tar.zst

# for example, `cat tmp/deploy/images/qemux86-64/libc6.spdx.json`
$ cat ${DEPLOY_DIR}/images/${MACHINE}/${TARGET_PACKAGE_NAME}.spdx.json
...
  "packages": [
    {
      "SPDXID": "SPDXRef-Package-libc6",
      "copyrightText": "NOASSERTION",
      "downloadLocation": "NOASSERTION",
      "hasFiles": [
        "SPDXRef-PackagedFile-libc6-1",
        "SPDXRef-PackagedFile-libc6-2",
        "SPDXRef-PackagedFile-libc6-3",
        "SPDXRef-PackagedFile-libc6-4",
        "SPDXRef-PackagedFile-libc6-5",
        "SPDXRef-PackagedFile-libc6-6",
        "SPDXRef-PackagedFile-libc6-7",
        "SPDXRef-PackagedFile-libc6-8",
        "SPDXRef-PackagedFile-libc6-9",
        "SPDXRef-PackagedFile-libc6-10",
        "SPDXRef-PackagedFile-libc6-11",
        "SPDXRef-PackagedFile-libc6-12",
        "SPDXRef-PackagedFile-libc6-13",
        "SPDXRef-PackagedFile-libc6-14",
        "SPDXRef-PackagedFile-libc6-15",
        "SPDXRef-PackagedFile-libc6-16"
      ],
      "licenseConcluded": "NOASSERTION",
      "licenseDeclared": "GPL-2.0-only AND LGPL-2.1-only",
      "licenseInfoFromFiles": [
        "NOASSERTION"
      ],
      "name": "libc6",
      "packageFileName": "libc6.tar.zst",
      "packageVerificationCode": {
        "packageVerificationCodeValue": "dc1d4ff83689b1922ab1a0b8dfaa80e40986c3b2"
      },
      "supplier": "Organization: OpenEmbedded ()",
      "versionInfo": "2.35"
    }
  ],
...
```

## license info of source files

```bash
# for example, `tar -I zstd -xvf core-image-minimal-qemux86-64.spdx.tar.zst`
$ tar -I zstd -xvf ${IMAGE_NAME}-${MACHINE}.spdx.tar.zst

# for example, `cat tmp/deploy/images/qemux86-64/recipe-libffi.spdx.json`
$ cat ${DEPLOY_DIR}/images/${MACHINE}/recipe-${TARGET_PACKAGE_NAME}.spdx.json
...
  "files": [
    {
      "SPDXID": "SPDXRef-SourceFile-libffi-1",
      "checksums": [
        {
          "algorithm": "SHA1",
          "checksumValue": "1541a69f581bcdf9405369d32fc834cb0d6aa621"
        },
        {
          "algorithm": "SHA256",
          "checksumValue": "e99c283675c59ad08620044e9b8758acb318dc1c93944009470b594db31e961b"
        }
      ],
      "copyrightText": "NOASSERTION",
      "fileName": "not-win32.patch",
      "fileTypes": [
        "SOURCE"
      ],
      "licenseConcluded": "NOASSERTION",
      "licenseInfoInFiles": [
        "NOASSERTION"
      ]
    },
    {
      "SPDXID": "SPDXRef-SourceFile-libffi-2",
      "checksums": [
        {
          "algorithm": "SHA1",
          "checksumValue": "245bae99b2b5916865ee2e5c9dc9f817cf8771bb"
        },
        {
          "algorithm": "SHA256",
          "checksumValue": "328c7c2908c43ce42eefda072307d2fc7fe8f5ae1d21f7f9f0b832e469e21be9"
        }
      ],
      "copyrightText": "NOASSERTION",
      "fileName": "0001-arm-sysv-reverted-clang-VFP-mitigation.patch",
      "fileTypes": [
        "SOURCE"
      ],
      "licenseConcluded": "NOASSERTION",
      "licenseInfoInFiles": [
        "NOASSERTION"
      ]
    },
    {
      "SPDXID": "SPDXRef-SourceFile-libffi-3",
      "checksums": [
        {
          "algorithm": "SHA1",
          "checksumValue": "88f1017994a6dc390903d73474fd193b86038564"
        },
        {
          "algorithm": "SHA256",
          "checksumValue": "e4d016c7690f82469d7eb52487e56c3c26429c5400f7f86e056b12e54a746ad3"
        }
      ],
      "copyrightText": "NOASSERTION",
      "fileName": "libffi-3.4.4/fficonfig.h.in",
      "fileTypes": [
        "SOURCE"
      ],
      "licenseConcluded": "NOASSERTION",
      "licenseInfoInFiles": [
        "NOASSERTION"
      ]
    },
    ...
```

## source files of the package
To do this, please set SPDX_INCLUDE_SOURCES and SPDX_ARCHIVE_SOURCES as "1".  

```bash
$ tar -I zstd -xvf ${DEPLOY_DIR}/spdx/${MACHINE}/recipes/recipe-${PN}.yst.zst
```

## installed binary of the package
To do this, please set SPDX_ARCHIVE_PACKAGED as "1".  

```bash
$ tar -I zstd -xvf  ${DEPLOY_DIR}/spdx/${MACHINE}/packages/${PN}.yst.zst
```