Using renovate-to-sbom
with the GitHub Dependency Submission API
Built into GitHub repositories - if enabled - is the Dependency Graph which gives insight into the dependencies that you use, as well as dependencies that use packages that the given repository produces, too.
Like many things, it's only as good as the supported ecosystems which cover some of the key ecosystems, but still miss out on a number of popular ecosystems, for instance Docker or Elixir.
So if we wanted to add support for ecosystems not supported by GitHub, how would we do that? Fortunately, GitHub have made it possible to provide your own data via the Dependency submission API, and a big thanks to James Eastwood for this idea, via this GitHub discussion thread!
To be able to submit to this API, however, we need to be able to understand all the dependencies our project supports, which is no small feat. When looking to understand the dependencies within a given repository, I will reach for the excellent Renovate, as it has a tonne of community-sourced ecosystems, and using my wrapper, renovate-graph
, we can output the discovered package data as a JSON blob.
We can then take this JSON export, and use another tool I've built, renovate-to-sbom
to convert this to an SPDX or CycloneDX Software Bill of Materials (SBOM) which can then be consumed by GitHub's tooling to add these dependencies to the Dependency Graph.
So what does this actually look like? Below you can see the GitHub Actions workflow you'd need to perform the scanning + submission:
name: Discover dependencies via `renovate-graph` and upload via the Dependency Submission API
on:
workflow_dispatch:
push:
branches:
- main
jobs:
SBOM-upload:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: stable
- name: Install `renovate-to-sbom`
run: |
go install dmd.tanna.dev/cmd/renovate-to-sbom@latest
- name: Retrieve package data with renovate-graph
run: |
# `--platform local` and the `RG_LOCAL_` environment variables are
# further documented in
# https://www.jvt.me/posts/2023/10/13/renovate-graph-local/ and improve
# the speed of dependency scanning
npx @jamietanna/renovate-graph@latest --platform local
env:
# As well as looking for pending updates, this also resolves version
# constraints such as `~= 0.3` to `0.3.1`
RG_INCLUDE_UPDATES: true
# variables for `--platform local`
RG_LOCAL_PLATFORM: github
RG_LOCAL_ORGANISATION: dagger
RG_LOCAL_REPO: dagger
- name: Generate SBOM
run: |
renovate-to-sbom out/github-dagger-dagger.json --out-format spdx2.3+json --only-include-known-purl-types
- uses: actions/upload-artifact@v3
with:
name: out
path: out
- name: SBOM upload
uses: advanced-security/spdx-dependency-submission-action@v0.0.1
with:
filePath: out
filePattern: github-dagger-dagger.json.spdx2.3.json
With this, we're doing a few key things:
- Using
renovate-graph
to perform the dependency analysis, taking care to use the--platform local
to improve performance - Using
renovate-to-sbom
to convert that data export to an SBOM (in this case, SPDX v2.3 format)- Note the
--only-include-known-purl-types
flag, which is due to the GitHub Dependency Submission API being a bit more restrictive of pURL types that are accepted as noted in this issue and this discussion
- Note the
- Using the official GitHub Action to upload the SPDX SBOM to GitHub's API
Once complete, GitHub's dependency graph is now a little more fleshed out, and detects:
- the
composer/composer:2-bin
Docker image that can now be seen in the Dependency Graph - the Elixir dependency,
absinthe_client
that can now be seen in the Dependency Graph.
That wasn't too difficult, was it?
As noted above, GitHub's only got support for some package types, so you may receive errors like:
{
"message": "invalid package url: in manifest \"github/dagger/dagger\" decoding \"pkg:foo/...\": invalid package url type: foo",
"documentation_url": "https://docs.github.com/rest/dependency-graph/dependency-submission#create-a-snapshot-of-dependencies-for-a-repository"
}
If you are, make sure you're running with --only-include-known-purl-types
, and if not please raise an issue, and I can try and resolve it!
Aside: I'd be remiss to not mention the Open Source project I've been working on for the last year, dependency-management-data, which allows you to take data like this, and get insight into end-of-life, unmaintained or deprecated versions of software, as well as giving you SQL and GraphQL access to query the data!