CI/CD Integration

A manually maintained SBOM is outdated the moment you create it. The multi-arch Docker image (amd64/arm64) drops kunnus into any pipeline so every release ships with a current SBOM.

GitHub Actions

.github/workflows/sbom.yml
- name: Generate SBOM
  run: |
    docker run --rm -v ${{ github.workspace }}:/src \
      ghcr.io/think-ahead-technologies/kunnus-scanner:latest \
      sbom repo /src --output /src/sbom.cdx.json

- name: Upload to kunnus platform
  env:
    KUNNUS_API_KEY: ${{ secrets.KUNNUS_API_KEY }}
    KUNNUS_COMPONENT_ID: ${{ vars.KUNNUS_COMPONENT_ID }}
  run: |
    docker run --rm -v ${{ github.workspace }}:/src \
      -e KUNNUS_API_KEY -e KUNNUS_COMPONENT_ID \
      ghcr.io/think-ahead-technologies/kunnus-scanner:latest \
      upload /src/sbom.cdx.json

GitLab CI

.gitlab-ci.yml
sbom:
  image:
    name: ghcr.io/think-ahead-technologies/kunnus-scanner:latest
    entrypoint: [""]
  script:
    - /kunnus sbom repo . --output sbom.cdx.json
    - /kunnus upload sbom.cdx.json
  variables:
    KUNNUS_API_KEY: $KUNNUS_API_KEY
    KUNNUS_COMPONENT_ID: $KUNNUS_COMPONENT_ID
  artifacts:
    paths: [sbom.cdx.json]

Exit codes: complete vs. degraded SBOMs

Exit 0 means every extractor ran clean. If the scan finishes but some plugins failed, the SBOM is still written and kunnus exits 1 with a summary of the failed plugins — so a pipeline can tell a complete SBOM from one with gaps instead of silently shipping the latter. Re-run with --verbosity info (or KUNNUS_VERBOSITY=info) for per-plugin detail.

Upload configuration

kunnus upload reads its flags from environment variables — KUNNUS_API_KEY (required), KUNNUS_COMPONENT_ID, and KUNNUS_UPLOAD_URL — which is the natural fit for CI secrets. The server response is printed to stdout.

Supply-chain hardening: release images are signed with cosign and carry SLSA Build L3 provenance. Pin the image by digest and verify it — SECURITY.md in the repository shows how.