Skip to main content

Upload SBOMs from your CI pipeline

Set up a CI/CD integration and upload SBOMs automatically: the Threat Detective GitHub Action for GitHub users, or an OIDC-authenticated API call from any other pipeline. No API keys to manage.

Written by Alan Parkinson

The most reliable SBOM is the one your build produces on every release. Threat Detective's CI integration lets your pipeline upload SBOMs automatically, authenticated with short-lived identity tokens (OIDC) that your CI provider issues for each run. There are no API keys or secrets to store or rotate.

Step 1: create the integration

  1. Open your project's Settings tab and click Manage CI/CD Integrations, then New CI/CD Integration.

  2. Choose your CI provider: GitHub Actions, GitLab CI, CircleCI, Bitbucket Pipelines, or Custom for any other OIDC-capable system.

  3. Connect your repository: give the integration a name, enter the repository in owner/repository format, and optionally restrict it to a branch (leave blank to allow any branch).

  4. Click Save Integration.

Uploads are only accepted when the CI token's issuer, repository and (if set) branch match the integration. A token from any other repository is rejected. The advanced settings let you tighten this further with an audience, subject filter or claim conditions.

Step 2 (GitHub): use the official action

For GitHub Actions, the easiest path is our published action, threatdetective/upload-sbom-action. It requests the OIDC token, uploads the file, and reports the result as step outputs. Two things to set up in your workflow:

permissions:
  id-token: write   # lets the action request an OIDC token
  contents: read
steps:
  - uses: actions/checkout@v4
  - name: Generate SBOM
    uses: anchore/sbom-action@v0
    with:
      format: cyclonedx-json
      output-file: sbom.json
  - name: Upload SBOM
    uses: threatdetective/upload-sbom-action@v1
    with:
      project-id: YOUR_PROJECT_ID
      sbom-file: sbom.json

Without id-token: write the action can't request a token and will fail; that permission is the whole authentication story. Your project ID appears on the integration's Pipeline Setup panel, which shows this snippet with the real values filled in.

Useful options: version and software-item-name override what's read from the SBOM's metadata (handy for tagging uploads with the branch or tag name), and wait-for-completion: true makes the step poll until the import finishes, exposing status, component-count and the created version's ID as outputs for later steps. auto-create is on by default, so new software items are created from the SBOM automatically.

Step 2 (other providers): call the API

For GitLab CI, CircleCI, Bitbucket and custom systems, the integration's Pipeline Setup panel shows a ready-made snippet with your project URL and audience filled in: obtain the OIDC token from your CI provider, then POST the SBOM to /api/v1/projects/YOUR_PROJECT_ID/sbom with the token as a bearer credential in the request's authorisation header.

The endpoint accepts CycloneDX and SPDX (2.2/2.3 JSON and tag-value, 3.0.x JSON-LD), up to 50 MB.

How uploads behave

  • The API responds 202 Accepted with an import_id, and a status endpoint lets your pipeline poll until the import completes (the GitHub Action's wait-for-completion does this for you).

  • Re-uploading the same CycloneDX document (same serial number) returns an "already been imported" response instead of creating a duplicate, so re-runs of a workflow are safe.

  • Rate limit: 60 requests per minute per integration.

Uploads appear in the project's Imports page and on the integration's Recent Imports table, and run through exactly the same pipeline as a manual upload, including the vulnerability scan.

Trial plans include one CI integration; paid plans are unlimited.

Did this answer your question?