Skip to content

Generating an SBOM for your project

Introduction

In order to generate a Software Bill of Materials (SBOM) for a CERN project you will have to:

  1. Run a tool to generate the SBOM.
  2. Check that the generated SBOM is meaningful, and in particular that the fields indicated in the Mandatory Fields section are present.

Currently there is no preferred SBOM standard, so you can generate SBOMs in either SPDX or CycloneDX.

SBOM generation

GitLab Dependency Scanning

If your project is stored on GitLab and it uses one of the supported package managers you may use the dependency scanning tool that the GitLab team has recently made available.

To enable it and use it see the relevant documentation at:

After generating the dependencies, if the output is meaningful, export the resulting SBOM in JSON format.

Harbor SBOM generator

If you have containerised your application and uploaded it to CERN's images registry you can run Harbor's scanner (Trivy) to generate an SBOM in SPDX standard, and later download it.

For more detailed information check the Kubernetes teams documentation.

Code scanners

We suggest to create a build SBOM using Trivy or Syft/Grype. If it is not possible, you should generate a source SBOM with Scancode, which will require a longer run.

Trivy is a comprehensive and efficient open-source vulnerability scanner that supports both container images and source repositories, among others. It excels in detecting vulnerabilities, misconfigurations, and license compliance issues, and it natively supports SBOM generation in both SPDX and CycloneDX, the main SBOM standards.

To scan a repository:

docker run --rm -v local-repository:/project/ \
   registry.cern.ch/docker.io/aquasec/trivy fs \
   --format cyclonedx --scanners vuln --output /project/sbom.cdx.json \
   /project/

To scan a container image:

docker run --rm -v output-folder:/project/ \
   registry.cern.ch/docker.io/aquasec/trivy image \
   --format cyclonedx --scanners vuln --output ./project/sbom.cdx.json \
   image_name:version

In this way we are scanning a filesystem (fs) or an image (image) to generate a CycloneDX SBOM (--format cyclonedx) and populating it with known information of possible vulnerabilities based on the package components found (--scanners vuln).

More details are available in the Trivy documentation.

Syft + Grype (build SBOM)

Syft and Grype, both developed by Anchore, are another valid option for SBOM generation and vulnerability scanning. Syft specializes in generating SBOMs from container images and filesystems, supporting multiple output formats including SPDX and CycloneDX.

The usage of these tools is equivalent for what concerns SBOM generation, but Grype complements Syft by consuming these SBOMs to perform vulnerability analysis using a rich set of vulnerability databases.

To scan a repository:

docker run --rm -v local-repository:/project/ \
   registry.cern.ch/docker.io/anchore/grype /project/ \
   -o cyclonedx-json > ./sbom.cdx.json

To scan a container image:

docker run --rm registry.cern.ch/docker.io/anchore/grype \
   image-name:version -o cyclonedx-json > ./sbom.cdx.json

The usage is quite straightforward, without the need to specify the type of target it automatically scans it and generates a CycloneDX SBOM (-o cyclonedx-json) that will be redirected to the specified file.

Relevant documentation:

ScanCode toolkit (source SBOM)

ScanCode is an open-source tool specifically designed for analyzing source code to generate SBOMs and license compliance reports. Unlike container- or binary-focused tools, ScanCode is more focused at parsing source trees to detect dependencies, licenses and copyrights. It supports output in both SPDX and CycloneDX.

For ScanCode, SPDX is the standard that gives more insightful results. They do not support JSON SPDX, so we suggest to run it through an image that automatically converts the resulting SBOM from tag-value to JSON.

To scan a repository:

docker run --rm -v local-repository:/project \
   registry.cern.ch/code-scanners/scancode:32.3.3-json -clpeui -n 4 \
   --spdx-tv sbom.spdx /project

In the example command above we are scanning the codebase for everything: copyrights (c), licenses (l), packages (p), emails (e), urls (u) and other info (i) like file size, type, etc. We run it with 4 processes (-n 4) and generate as output an SBOM in the SPDX standard and tag-value format. Using the suggested image the file is also converted to JSON, which is preferred. In case of any issue use the image registry.cern.ch/code-scanners/scancode:32.3.3 to run scancode directly without the conversion script.

If your repository contains a huge number of file we also suggest to add to the run the parameter --ignore <pattern> to skip files or directories that are not relevant for SBOM generation or compliance analysis, e.g. "docs/*", "tests/*"...

Scancode documentation:

Mandatory fields

CycloneDX (v1.x)

At the beginning of the CycloneDX SBOM you should see something like this:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "version": 1,
  "metadata": {
    "timestamp": "2025-04-07T10:00:00Z",
    "tools": [
      {
        "vendor": "ExampleTool",
        "name": "cyclonedx-exporter",
        "version": "1.0"
      }
    ],
    "properties": [
      {
        "name": "contact",
        "value": <YOUR EMAIL>
      },
      {
        "name": "unit",
        "value": <ORGANISATIONAL UNIT>
      },
      {
        "name": "servicenow.element",
        "value": <SERVICENOW ELEMENT>
      }
    ],
    "component": {
      "type": "application",
      "name": <REPOSITORY NAME>,
      "version": "git-main",
      "purl": "pkg:github/example/my-repo-name",
      "externalReferences": [
        {
          "type": "vcs",
          "url": <REPOSITORY VCS URL>
        }
      ]
    }
  },
  "components": [
      ...
  ]
}

It is important to review the SBOM and add the fields in angular brackets:

  • properties:
  • contact: your email, e.g. "john.smith@cern.ch", as responsible for the application.
  • unit: your organisational unit formatted as Department-Group-Section, e.g. "IT-CD-CC".
  • servicenow.element: Optional (if applicable). Service element in Service-now as present in the services list.
  • component.name: simple string containing the name of the application. This field could already be present, correct it if incorrect.
  • component.externalReferences: add the above specified element to indicate the GitLab/GitHub URL of your application.

SPDX (v2.x)

At the beginning of your SPDX SBOM (In JSON format) you should have something like:

{
  "spdxVersion": "SPDX-2.3",
  "dataLicense": "CC0-1.0",
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": <REPOSITORY NAME>,
  "documentNamespace": "https://document-namespace.com/",
  "creationInfo": {
    "licenseListVersion": "3.25",
    "creators": [
      ...,
      "Person: <YOUR NAME> (<EMAIL CONTACT>)"
    ],
    "created": "2025-04-07T11:06:00Z"
  },
  "annotations": [
    {
      "annotationDate": <DATE>,
      "annotationType": "OTHER",
      "annotator": "Person: <YOUR NAME>",
      "comment": "Repository: <REPOSITORY VCS URL>"
    },
    {
      "annotationDate": <DATE>,
      "annotationType": "OTHER",
      "annotator": "Person: <YOUR NAME>",
      "comment": "Organisational unit: <ORGANISATIONAL UNIT>"
    },
    {
      "annotationDate": <DATE>,
      "annotationType": "OTHER",
      "annotator": "Person: <YOUR NAME>",
      "comment": "ServiceNow element: <SERVICENOW ELEMENT>"
    }
  ],
  "packages": [
      ...
  ]
}

If not present or not correct, please substitute all values in angular brackets. In detail:

  • name: the name of the scanned project.
  • creators: this array should already be present and contain the name of the tool used for SBOM generation. Add another element containing your name and email (as responsible for the application), e.g. "Person: John Smith (john.smith@cern.ch)".
  • annotations: this array should not be present after automatic creation. Add it along with three elements (or two, if your application is not present in ServiceNow) containing the following information:
  • annotationDate: when the annotation was created, in the format YYYY-MM-DDThh-mm-ssZ where YYYY is the year, MM the month, DD the day, T a delimeter for time, hh the hours, mm the minutes, ss the seconds and Z the universal time indicator. Example: 2025-04-16T10:30:00Z.
  • annotationType: must be equal to "OTHER".
  • annotator: the string "Person: " followed by your name, e.g. "Person: John Smith".
  • comment: this field will contain the actual information:
    • Repository: <REPOSITORY VCS URL>: GitLab/GitHub URL of your application.
    • Organisational unit: <ORGANISATIONAL UNIT>: your organisational unit formatted as Department-Group-Section, e.g. "IT-CD-CC".
    • ServiceNow element: <SERVICENOW ELEMENT>: Optional (if applicable). Service element in Service-now as present in the services list.

Generic SBOM

If the SBOM is not in one of the two main standards (e.g. it was generated using GitLab's Dependency Scanning) make sure that it contains the requested fields, for instance in JSON:

{
    "contact": <YOUR EMAIL>,
    "unit": <YOUR ORGANISATIONAL UNIT>,
    "servicenow.element": <SERVICENOW ELEMENT>,
    "name": <REPOSITORY NAME>,
    "url": <REPOSITORY VCS URL>,
    "dependencies": [
        ...
    ]
}

Where:

  • contact: your email, e.g. "john.smith@cern.ch", as responsible for the application.
  • unit: your organisational unit formatted as Department-Group-Section, e.g. "IT-CD-CC".
  • servicenow.element: Optional (if applicable). Service element in Service-now as present in the services list.
  • name: the name of your application.
  • url: GitLab/GitHub URL of your application.

Other references