Dependency scanning by using SBOM

  • Tier: Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
  • Status: Beta
History

Dependency scanning using CycloneDX SBOM analyzes your application’s dependencies for known vulnerabilities. All dependencies are scanned, including transitive dependencies.

Dependency scanning is often considered part of Software Composition Analysis (SCA). SCA can contain aspects of inspecting the items your code uses. These items typically include application and system dependencies that are almost always imported from external sources, rather than sourced from items you wrote yourself.

Dependency scanning can run in the development phase of your application’s lifecycle. Every time a pipeline produces an SBOM report, security findings are identified and compared between the source and target branches. Findings and their severity are listed in the merge request, enabling you to proactively address the risk to your application, before the code change is committed. Security findings for reported SBOM components are also identified by Continuous Vulnerability Scanning when new security advisories are published, independently from CI/CD pipelines.

GitLab offers both dependency scanning and container scanning to ensure coverage for all of these dependency types. To cover as much of your risk area as possible, we encourage you to use all of our security scanners. For a comparison of these features, see Dependency Scanning compared to Container Scanning.

How it scans an application

The dependency scanning using SBOM approach relies on two distinct phases:

  • First, the dependency detection phase that focuses solely on creating a comprehensive inventory of your project’s dependencies and their relationship (dependency graph). This inventory is captured in an SBOM (Software Bill of Materials) document.
  • Second, after the CI/CD pipeline completes, the GitLab platform processes your SBOM report and performs a thorough security analysis using the built-in GitLab SBOM Vulnerability Scanner. It is the same scanner that provides Continuous Vulnerability Scanning.

This separation of concerns and the modularity of this architecture allows to better support customers through expansion of language support, a tighter integration and experience within the GitLab platform, and a shift towards industry standard report types.

Dependency detection

Dependency scanning using SBOM requires the detected dependencies to be captured in a CycloneDX SBOM document. However, the modular aspect of this functionality allows you to select how this document is generated:

  • Using the Dependency Scanning analyzer provided by GitLab (recommended)
  • Using the (deprecated) Gemnasium analyzer provided by GitLab
  • Using a custom job with a 3rd party CycloneDX SBOM generator or a custom tool.

In order to activate dependency scanning using SBOM, the provided CycloneDX SBOM document must:

When using GitLab provided analyzers, these requirements are met.

Security analysis

Once a compatible CycloneDX SBOM document is uploaded, GitLab automatically performs the security analysis with the GitLab SBOM Vulnerability Scanner. Each component is checked against the GitLab Advisory Database and scan results are processed in the following manners:

If the SBOM report is declared by a CI/CD job on the default branch: vulnerabilities are created, and can be seen in the vulnerability report.

If the SBOM report is declared by a CI/CD job on a non-default branch: security findings are created, and can be seen in the security tab of the pipeline view and MR security widget. This functionality is behing a feature flag and tracked in Epic 14636.

Supported package types

For the security analysis to be effective, the components listed in your SBOM report must have corresponding entries in the GitLab Advisory Database.

The GitLab SBOM Vulnerablity Scanner can report Dependency Scanning vulnerabilities for components with the following PURL types:

  • cargo
  • composer
  • conan
  • gem
  • golang
  • maven
  • npm
  • nuget
  • pypi

Configuration

Enable the Dependency Scanning using SBOM feature with one of the following options:

  • Use the latest Dependency Scanning CI/CD template Dependency-Scanning.latest.gitlab-ci.yml to enable a GitLab provided analyzer.
    • The (deprecated) Gemnasium analyzer is used by default.
    • To enable the new Dependency Scanning analyzer, set the CI/CD variable DS_ENFORCE_NEW_ANALYZER to true.
  • Use the Scan Execution Policies with the latest template to enable a GitLab provided analyzer.
    • The (deprecated) Gemnasium analyzer is used by default.
    • To enable the new Dependency Scanning analyzer, set the CI/CD variable DS_ENFORCE_NEW_ANALYZER to true.
  • Use the Dependency Scanning CI/CD component to enable the new Dependency Scanning analyzer.
  • Provide your own CycloneDX SBOM document.

The preferred method is to use the new Dependency Scanning analyzer and this is what is documented in the next section. To enable the (deprecated) Gemnasium analyzer please refer to the enablement instructions for the legacy Dependency Scanning feature.

Enabling the analyzer

The Dependency Scanning analyzer produces a CycloneDX SBOM report compatible with GitLab. If your application can’t generate such a report, you can use the GitLab analyzer to produce one.

Prerequisites:

  • A supported lock file or dependency graph must exist in the repository or must be passed as an artifact to the dependency-scanning job.
  • The component’s stage is required in the .gitlab-ci.yml file.
  • With self-managed runners you need a GitLab Runner with the docker or kubernetes executor.
    • If you’re using SaaS runners on GitLab.com, this is enabled by default.

To enable the analyzer, you must:

  • Use either the latest Dependency Scanning CI/CD template Dependency-Scanning.latest.gitlab-ci.yml and enforce the new Dependency Scanning analyzer by setting the CI/CD variable DS_ENFORCE_NEW_ANALYZER to true.

    Copy to clipboard
      include:
        - template: Jobs/Dependency-Scanning.latest.gitlab-ci.yml
    
      variables:
        DS_ENFORCE_NEW_ANALYZER: 'true'
  • Use the Scan Execution Policies with the latest template and enforce the new Dependency Scanning analyzer by setting the CI/CD variable DS_ENFORCE_NEW_ANALYZER to true.

  • Use the Dependency Scanning CI/CD component

    Copy to clipboard
      include:
        - component: $CI_SERVER_FQDN/components/dependency-scanning/main@0

Language-specific instructions

If your project doesn’t have a supported lock file dependency graph committed to its repository, you need to provide one.

The examples below show how to create a file that is supported by the GitLab analyzer for popular languages and package managers.

Go

If your project provides only a go.mod file, the Dependency Scanning analyzer can still extract the list of components. However, dependency path information is not available. Additionally, you might encounter false positives if there are multiple versions of the same module.

To benefit from improved component detection and feature coverage, you should provide a go.graph file generated using the go mod graph command from the Go toolchain.

The following example .gitlab-ci.yml demonstrates how to enable the CI/CD component with dependency path support on a Go project. The dependency graph is output as a job artifact in the build stage, before dependency scanning runs.

Copy to clipboard
stages:
  - build
  - test

include:
  - component: $CI_SERVER_FQDN/components/dependency-scanning/main@0

go:build:
  stage: build
  image: "golang:latest"
  script:
    - "go mod tidy"
    - "go build ./..."
    - "go mod graph > go.graph"
  artifacts:
    when: on_success
    access: developer
    paths: ["**/go.graph"]

Gradle

To enable the CI/CD component on a Gradle project:

  1. Edit the build.gradle or build.gradle.kts to use the gradle-dependency-lock-plugin.
  2. Configure the .gitlab-ci.yml file to generate the dependencies.lock artifacts, and pass them to the dependency-scanning job.

The following example demonstrates how to configure the component for a Gradle project.

Copy to clipboard
stages:
  - build
  - test

# Define the image that contains Java and Gradle
image: gradle:8.0-jdk11

include:
  - component: $CI_SERVER_FQDN/components/dependency-scanning/main@0

build:
  # Running in the build stage ensures that the dependency-scanning job
  # receives the maven.graph.json artifacts.
  stage: build
  script:
    - gradle generateLock saveLock
    - gradle assemble
  # generateLock saves the lock file in the build/ directory of a project
  # and saveLock copies it into the root of a project. To avoid duplicates
  # and get an accurate location of the dependency, use find to remove the
  # lock files in the build/ directory only.
  after_script:
    - find . -path '*/build/dependencies.lock' -print -delete
  # Collect all dependencies.lock artifacts and pass them onto jobs
  # in sequential stages.
  artifacts:
    paths:
      - "**/dependencies.lock"

Maven

The following example .gitlab-ci.yml demonstrates how to enable the CI/CD component on a Maven project. The dependency graph is output as a job artifact in the build stage, before dependency scanning runs.

Copy to clipboard
stages:
  - build
  - test

image: maven:3.9.9-eclipse-temurin-21

include:
  - component: $CI_SERVER_FQDN/components/dependency-scanning/main@0

build:
  # Running in the build stage ensures that the dependency-scanning job
  # receives the maven.graph.json artifacts.
  stage: build
  script:
    - mvn install
    - mvn dependency:tree -DoutputType=json -DoutputFile=maven.graph.json
  # Collect all maven.graph.json artifacts and pass them onto jobs
  # in sequential stages.
  artifacts:
    paths:
      - "**/*.jar"
      - "**/maven.graph.json"

pip

If your project provides a requirements.txt lock file generated by the pip-compile command line tool, the Dependency Scanning analyzer can extract the list of components and the dependency graph information, which provides support for the dependency path feature.

Alternatively, your project can provide a pipdeptree.json dependency graph export generated by the pipdeptree --json command line utility.

The following example .gitlab-ci.yml demonstrates how to enable the CI/CD component with dependency path support on a pip project. The build stage outputs the dependency graph as a job artifact before dependency scanning runs.

Copy to clipboard
stages:
  - build
  - test

include:
  - component: $CI_SERVER_FQDN/components/dependency-scanning/main@0

build:
  stage: build
  image: "python:latest"
  script:
    - "pip install pipdeptree"
    - "pipdeptree --json > pipdeptree.json"
  artifacts:
    when: on_success
    access: developer
    paths: ["**/pipdeptree.json"]

Pipenv

If your project provides only a Pipfile.lock file, the Dependency Scanning analyzer can still extract the list of components. However, dependency path information is not available.

To benefit from improved feature coverage, you should provide a pipenv.graph.json file generated by the pipenv graph command.

The following example .gitlab-ci.yml demonstrates how to enable the CI/CD component with dependency path support on a Pipenv project. The build stage outputs the dependency graph as a job artifact before dependency scanning runs.

Copy to clipboard
stages:
  - build
  - test

include:
  - component: $CI_SERVER_FQDN/components/dependency-scanning/main@0

build:
  stage: build
  image: "python:latest"
  script:
    - "pipenv graph --json-tree > pipenv.graph.json"
  artifacts:
    when: on_success
    access: developer
    paths: ["**/pipenv.graph.json"]

sbt

To enable the CI/CD component on an sbt project:

The following example .gitlab-ci.yml demonstrates how to enable the CI/CD component with dependency path support in an sbt project. The build stage outputs the dependency graph as a job artifact before dependency scanning runs.

Copy to clipboard
stages:
  - build
  - test

include:
  - component: $CI_SERVER_FQDN/components/dependency-scanning/main@0

build:
  stage: build
  image: "sbtscala/scala-sbt:eclipse-temurin-17.0.13_11_1.10.7_3.6.3"
  script:
    - "sbt dependencyDot"
  artifacts:
    when: on_success
    access: developer
    paths: ["**/dependencies-compile.dot"]

Customizing analyzer behavior

The analyzer can be customized by configuring the CI/CD component’s inputs.

Output

The dependency scanning analyzer produces CycloneDX Software Bill of Materials (SBOM) for each supported lock file or dependency graph export detected.

CycloneDX Software Bill of Materials

  • Generally available in GitLab 15.7.

The dependency scanning analyzer outputs a CycloneDX Software Bill of Materials (SBOM) for each supported lock or dependency graph export it detects. The CycloneDX SBOMs are created as job artifacts.

The CycloneDX SBOMs are:

  • Named gl-sbom-<package-type>-<package-manager>.cdx.json.
  • Available as job artifacts of the dependency scanning job.
  • Uploaded as cyclonedx reports.
  • Saved in the same directory as the detected lock or dependency graph exports files.

For example, if your project has the following structure:

Copy to clipboard
.
├── ruby-project/
│   └── Gemfile.lock
├── ruby-project-2/
│   └── Gemfile.lock
└── php-project/
    └── composer.lock

The following CycloneDX SBOMs are created as job artifacts:

Copy to clipboard
.
├── ruby-project/
│   ├── Gemfile.lock
│   └── gl-sbom-gem-bundler.cdx.json
├── ruby-project-2/
│   ├── Gemfile.lock
│   └── gl-sbom-gem-bundler.cdx.json
└── php-project/
    ├── composer.lock
    └── gl-sbom-packagist-composer.cdx.json

Merging multiple CycloneDX SBOMs

You can use a CI/CD job to merge the multiple CycloneDX SBOMs into a single SBOM.

GitLab uses CycloneDX Properties to store implementation-specific details in the metadata of each CycloneDX SBOM, such as the location of dependency graph exports and lock files. If multiple CycloneDX SBOMs are merged together, this information is removed from the resulting merged file.

For example, the following .gitlab-ci.yml extract demonstrates how the Cyclone SBOM files can be merged, and the resulting file validated.

Copy to clipboard
stages:
  - test
  - merge-cyclonedx-sboms

include:
  - component: $CI_SERVER_FQDN/components/dependency-scanning/main@0

merge cyclonedx sboms:
  stage: merge-cyclonedx-sboms
  image:
    name: cyclonedx/cyclonedx-cli:0.27.1
    entrypoint: [""]
  script:
    - find . -name "gl-sbom-*.cdx.json" -exec cyclonedx merge --output-file gl-sbom-all.cdx.json --input-files "{}" +
    # optional: validate the merged sbom
    - cyclonedx validate --input-version v1_6 --input-file gl-sbom-all.cdx.json
  artifacts:
    paths:
      - gl-sbom-all.cdx.json

Troubleshooting

When working with dependency scanning, you might encounter the following issues.

Warning: grep: command not found

The analyzer image contains minimal dependencies to decrease the image’s attack surface. As a result, utilities commonly found in other images, like grep, are missing from the image. This may result in a warning like /usr/bin/bash: line 3: grep: command not found to appear in the job log. This warning does not impact the results of the analyzer and can be ignored.