Documentation menu

Guides

CI integration

Upload an SBOM from every build with an upload key and a single curl call.

The integration is deliberately boring: generate an SBOM in your pipeline, then POST it to boring.tools. There is no agent to install and no access to your repository required.

1. Create an upload key

Upload keys belong to your organization, not to a person, so they keep working when the colleague who created them leaves.

  • Project key — project → Integration → Upload keys for this project. The key can only upload into that project. Use this by default.
  • Organization key — Settings → SBOM upload keys, scope All organization projects. One key for every project, convenient for a shared pipeline template.

Keys start with bt_sbom_ and are shown once. Copy it and store it as a secret in your CI system, for example BORING_TOOLS_KEY. You can delete a key at any time; uploads with it fail immediately.

2. Find your project ID

The project ID is part of the project’s URL in the app (/projects/<project-id>). The Integration tab shows ready-made snippets with the ID already filled in.

3. Add the upload step

GitHub Actions

- name: Generate SBOM
  run: npx @cyclonedx/cdxgen -r --spec-version 1.6 -o sbom.json .

- name: Upload SBOM to boring.tools
  run: |
    curl --fail -X POST https://api.boring.tools/v1/sbom/upload \
      -H "x-api-key: ${{ secrets.BORING_TOOLS_KEY }}" \
      -F projectId=<project-id> \
      -F versionName=${{ github.ref_name }} \
      -F commit=${{ github.sha }} \
      -F file=@sbom.json

GitLab CI

upload-sbom:
  script:
    - npx @cyclonedx/cdxgen -r --spec-version 1.6 -o sbom.json .
    - |
      curl --fail -X POST https://api.boring.tools/v1/sbom/upload \
        -H "x-api-key: $BORING_TOOLS_KEY" \
        -F projectId=<project-id> \
        -F versionName=$CI_COMMIT_REF_NAME \
        -F commit=$CI_COMMIT_SHA \
        -F file=@sbom.json

Any other system

curl --fail -X POST https://api.boring.tools/v1/sbom/upload \
  -H "x-api-key: $BORING_TOOLS_KEY" \
  -F projectId=<project-id> \
  -F file=@sbom.json

cdxgen detects every language in the repository. To use Syft or an ecosystem-specific tool instead, replace the generator step — see Uploading SBOMs. The project’s Integration tab builds the snippet for each of them.

Choosing the version name

Without versionName, the version comes from the SBOM’s root component (for npm: the version in package.json). Passing the Git ref instead is often clearer:

  • Release tags (v2.4.0) give you one version per release. Set a support end when you stop supporting them.
  • Branch names (main) give you one continuously updated version — handy for “what’s in production right now”.

Use artifactName the same way when one version produces several deliverables, for example -F artifactName=api and -F artifactName=web.

Optional provenance fields

repository, commit, branch and pipelineUrl are stored with the upload so you can trace an SBOM back to the build that produced it.

Responses

The upload returns 202 Accepted as soon as the file is stored; analysis runs in the background, so the step adds no noticeable time to your pipeline. --fail makes curl exit non-zero on errors such as an invalid key (401) or a project key used for a different project (403). The full contract is in the Upload API.