Skip to main content
Ungathered Thoughts

Reporting from Composer to Dependency Track from Gitlab CI

For organisations using open source to build software, I believe a high-level view of the components being consumed is critical to maintenance and vulnerability response. Tools like this offer not just vulnerability detection, but also risk reduction, opportunity to manage dependencies more efficiently across projects, risk reduction, and license and policy compliance.

Dependency Track is a tool which organisations can use to gather and analyse their component usage. It does this by permitting submission of software bill of materials (SBOM) reports into a store, and combining this with automated import of vulnerability and component data alongside organisational policies.

I'd demoed Dependency Track in Drupal South Shorts in 2021, and figured it was worth another look as part of a project I'm working on.

Bringing up a Dependency Track instance

I used Dependency Track's instructions to deploy an instance using Docker Compose per their Deploying with Docker instructions. This works great - but do pay attention to the system requirements; Dependency Track looks lightweight on the surface, but behind the scenes it is importing and analysing a fair bit of data.

CPU usage bringing up Dependency Track

Dependency Track has a frontend and an API service. For reporting to Dependency Track, the API endpoint needs to be externally accessible.

Note that there's a short period after you bring the environment up when it's chugging away yoinking data from NIST and various other sources. Allow that time to ingest before expecting useful output.

The default creds are admin/admin, which you'll change before accessing the admin interface. Post-login, you probably want to set up a few things in the admin section; I recommend configuring Administration > Email for notifications. As I would be analysing Drupal projects for my instance, under Administration > Repositories > Composer, I added Drupal's Packagist endpoint https://packages.drupal.org/8 as well.

I then added a couple of Projects to test with. One of these is xurizaemon/commerce-demo, which is a public repository.

Generating SBOM in CI

I use CycloneDX/cyclonedx-php-composer for this. There are other tools, such as Gemnasium, and they might work equally well. In the Gitlab CI job, I'll install CycloneDX/cyclonedx-php-composer using composer global require (to keep it separate from the project-specific dependencies), then execute the new Composer command.

The job depends on some configuration, which I apply in Gitlab's CI/CD Variables settings. These are:

Variable key Example Description
DEPENDENCYTRACK_API_URL https://dt-api.example.org Base URL of the Dependency Track API service
DEPENDENCYTRACK_API_KEY abc_aaaabbbbccccddddEEEEFFFFGGGGHHHH API key for reporting
DEPENDENCYTRACK_PROJECT odt_lFrEC3SumNas1VOBNeFz3pUoLdLIEnII Project identifier

For the API Key, in Dependency Track navigate Administration > Access Management > Teams; the "Automation" team should have an API key already assigned. For the Project ID, in Dependency Track navigate Projects > {selected project} > View Details and copy the Object Identifier.

If these aren't configured, the job will bail out with a configuration warning.

report dependencies:
stage: check
image: composer:2
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
needs:
- composer install
before_script:
# Verify that the required variables have been configured in Gitlab CI/CD Variables before proceeding.
- >
if [ -z "${DEPENDENCYTRACK_API_KEY}" -o -z "${DEPENDENCYTRACK_API_URL}" -o -z "${DEPENDENCYTRACK_PROJECT}" ]; then
echo "Configure DEPENDENCYTRACK_API_KEY, DEPENDENCYTRACK_API_URL and DEPENDENCYTRACK_PROJECT to report to Dependency Track."
exit 1
fi

- composer global config --no-plugins allow-plugins.cyclonedx/cyclonedx-php-composer true
- composer global require cyclonedx/cyclonedx-php-composer
script:
# Generate an SBOM in XML format for submission.
- composer CycloneDX:make-sbom --output-format=XML --output-file="${CI_PROJECT_DIR}/composer-sbom.cdx.xml"
# JSON for submission requires DT project identifier and b64encoded BOM XML.
- >
echo "{
\"project\": \"${DEPENDENCYTRACK_PROJECT}\",
\"bom\": \"$( base64 --wrap=0 ${CI_PROJECT_DIR}/composer-sbom.cdx.xml )\"
}" > ${CI_PROJECT_DIR}/report-bom.json

# PUT the JSON to Dependency Track endpoint.
- >
curl -X "PUT" "${DEPENDENCYTRACK_API_URL}/api/v1/bom" \
-H "Content-Type: application/json" \
-H "X-API-Key: ${DEPENDENCYTRACK_API_KEY}" \
-d @${CI_PROJECT_DIR}/report-bom.json

artifacts:
paths:
- composer-sbom.cdx.xml
- report-bom.json
allow_failure: true

With this correctly configured, we should see output from the Gitlab CI job (job from Commerce Demo project mentioned above) which shows the report being submitted to our Dependency Track service.

$ composer CycloneDX:make-sbom --output-format=XML --output-file="${CI_PROJECT_DIR}/composer-sbom.cdx.xml"
$ echo "{ # collapsed multi-line command
$ curl -X "PUT" "${DEPENDENCYTRACK_API_URL}/api/v1/bom" \ # collapsed multi-line command
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  825k  100    48  100  825k      8   152k  0:00:06  0:00:05  0:00:01  151k
{"token":"9090c0d5-6257-4b23-ae14-64d05fb4f349"}

And then in Dependency Track, we should see our gathered data.

Vulnerabilities displayed for a project in Dependency Track

I'll return to "what can we do with this information" in a later post maybe - until now, enjoy exploring Dependency Track.

Related: Showing Composer changes from a Gitlab CI job