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:
- Run a tool to generate the SBOM.
- 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:
- https://gitlab.docs.cern.ch/docs/Secure%20your%20application/dependency-scanning
- https://gitlab.cern.ch/help/user/application_security/dependency_list/index.md
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 (build SBOM - recommended)¶
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 formatYYYY-MM-DDThh-mm-ssZ
whereYYYY
is the year,MM
the month,DD
the day,T
a delimeter for time,hh
the hours,mm
the minutes,ss
the seconds andZ
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.