How to Generate a CRA-Compliant SBOM: Tools, Formats, and CI/CD Integration

A hands-on guide to generating Software Bills of Materials for CRA compliance. Covers open-source tools, format selection, and automated pipeline integration.

CRA Evidence Team
Author
February 5, 2026
Updated February 25, 2026, 12:00:00 AM UTC
10 min read
How to Generate a CRA-Compliant SBOM: Tools, Formats, and CI/CD Integration
In this article

The CRA requires a Software Bill of Materials. Every competitor article tells you this. None show you how to generate one.

This guide covers open-source tools, format selection, and CI/CD integration with no vendor lock-in required.

Tip: Start with Syft or Trivy for SBOM generation — both support CycloneDX and SPDX output and integrate easily into CI/CD pipelines.

Summary

  • CRA requires machine-readable SBOMs covering "at least top-level dependencies"
  • Recommended formats: CycloneDX 1.4+ or SPDX 2.3+ (per BSI TR-03183)
  • Open-source tools: Syft (images/filesystems), Trivy (containers), cdxgen (source code)
  • Integrate SBOM generation into CI/CD for automatic updates
  • Quality matters: minimum fields include package name, version, supplier, hash, license

Important: The CRA requires machine-readable SBOMs covering all transitive dependencies. A simple package.json or requirements.txt is NOT sufficient.

CI/CD SBOM pipeline — Code, Build, Generate, Sign, Store, Monitor

What the CRA Actually Requires

Let's start with what the regulation says. Annex I, Part II of the CRA requires manufacturers to:

"identify and document vulnerabilities and components contained in the product, including by drawing up a software bill of materials in a commonly used and machine-readable format"

Key points:

  • Machine-readable format: Not a PDF, not a spreadsheet, but structured data
  • At least top-level dependencies: The minimum scope, though more is better
  • Not required to be public: Provided to authorities on request
  • Must be updated: With each release, patch, or component change

The CRA doesn't mandate a specific format, but standardization efforts point clearly to CycloneDX and SPDX.

Format Selection: CycloneDX vs SPDX

Two formats dominate the SBOM landscape. Both are acceptable for CRA compliance.

CycloneDX

Origin: OWASP project, security-focused Current version: 1.6 (1.4+ recommended for CRA) Best for: Security and vulnerability management

Strengths:

JSON example:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.5",
  "version": 1,
  "components": [
    {
      "type": "library",
      "name": "lodash",
      "version": "4.17.21",
      "purl": "pkg:npm/lodash@4.17.21",
      "hashes": [
        {
          "alg": "SHA-256",
          "content": "cc6d..."
        }
      ],
      "licenses": [
        {
          "license": {
            "id": "MIT"
          }
        }
      ]
    }
  ]
}

SPDX

Origin: Linux Foundation, license compliance-focused Current version: 2.3 (ISO/IEC 5962:2021 standard) Best for: License compliance and legal review

Strengths:

  • ISO international standard
  • Comprehensive license expression syntax
  • Strong in open source compliance contexts
  • Longer track record
  • Better for complex licensing scenarios

JSON example:

{
  "spdxVersion": "SPDX-2.3",
  "dataLicense": "CC0-1.0",
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": "my-application",
  "packages": [
    {
      "SPDXID": "SPDXRef-Package-lodash",
      "name": "lodash",
      "versionInfo": "4.17.21",
      "downloadLocation": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
      "licenseConcluded": "MIT",
      "checksums": [
        {
          "algorithm": "SHA256",
          "checksumValue": "cc6d..."
        }
      ]
    }
  ]
}

Which to Choose?

Use Case Recommendation
Primary focus is security/vulnerabilities CycloneDX
Primary focus is license compliance SPDX
Need VEX integration CycloneDX
Enterprise with existing SPDX tooling SPDX
German market (BSI TR-03183) Either (both recommended)
Starting fresh, no preference CycloneDX (simpler, security-focused)

For CRA compliance, either format works. Pick one and be consistent.

Open-Source SBOM Generation Tools

No vendor lock-in required. These tools are free, open-source, and production-ready.

Syft (Anchore)

Best for: Container images, filesystems, archives License: Apache 2.0 Output formats: CycloneDX, SPDX, Syft JSON

Installation:

# Linux/macOS
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

# Homebrew
brew install syft

# Docker
docker pull anchore/syft

Usage examples:

# Scan a container image
syft alpine:latest -o cyclonedx-json > sbom.cdx.json

# Scan a directory
syft dir:/path/to/project -o cyclonedx-json > sbom.cdx.json

# Scan an archive
syft /path/to/archive.tar.gz -o spdx-json > sbom.spdx.json

# Scan with specific catalogers (e.g., only Python)
syft dir:. -o cyclonedx-json --select-catalogers python

Supported ecosystems: Python, Node.js, Ruby, Java, Go, Rust, PHP, .NET, and more.

Trivy (Aqua Security)

Best for: Container images with built-in vulnerability context License: Apache 2.0 Output formats: CycloneDX, SPDX, plus vulnerability reports

Installation:

# Linux (Debian/Ubuntu)
sudo apt-get install trivy

# macOS
brew install trivy

# Docker
docker pull aquasec/trivy

Usage examples:

# Generate SBOM from container image
trivy image --format cyclonedx --output sbom.cdx.json alpine:latest

# Generate SBOM from filesystem
trivy fs --format cyclonedx --output sbom.cdx.json /path/to/project

# Generate SBOM with vulnerability info
trivy image --format cyclonedx --output sbom.cdx.json \
  --scanners vuln nginx:latest

Advantage: Trivy can generate SBOMs and scan for vulnerabilities in one pass.

cdxgen (CycloneDX)

Best for: Source code analysis across many languages License: Apache 2.0 Output format: CycloneDX

Installation:

# npm (requires Node.js)
npm install -g @cyclonedx/cdxgen

# Docker
docker pull ghcr.io/cyclonedx/cdxgen

Usage examples:

# Scan current directory
cdxgen -o sbom.json

# Scan specific project type
cdxgen -t python -o sbom.json

# Scan with deep dependency resolution
cdxgen --deep -o sbom.json

# Scan a specific directory
cdxgen -o sbom.json /path/to/project

Supported languages: JavaScript, Python, Java, Go, Rust, PHP, Ruby, .NET, C/C++, and more.

Tool Comparison

Feature Syft Trivy cdxgen
Container images Excellent Excellent Good
Source code Good Good Excellent
Filesystem scan Excellent Good Good
Vulnerability scanning No (use Grype) Yes No
CycloneDX output Yes Yes Yes
SPDX output Yes Yes No
Speed Fast Medium Medium
Language coverage Very broad Broad Very broad

Recommendation: Start with Syft for most use cases. Add Trivy if you need integrated vulnerability scanning. Use cdxgen for complex source code projects.

CI/CD Integration

Manual SBOM generation doesn't scale. Integrate it into your build pipeline.

GitHub Actions

name: SBOM Generation

on:
  push:
    branches: [main]
  release:
    types: [published]

jobs:
  sbom:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install Syft
        run: |
          curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

      - name: Generate SBOM
        run: |
          syft dir:. -o cyclonedx-json > sbom.cdx.json

      - name: Upload SBOM as artifact
        uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: sbom.cdx.json
          retention-days: 90

      # Optional: Upload to CRA Evidence
      - name: Upload to CRA Evidence
        if: github.event_name == 'release'
        env:
          CRA_EVIDENCE_TOKEN: ${{ secrets.CRA_EVIDENCE_TOKEN }}
        run: |
          curl -X POST https://app.craevidence.com/api/v1/ci/sbom \
            -H "Authorization: Bearer $CRA_EVIDENCE_TOKEN" \
            -F "file=@sbom.cdx.json" \
            -F "product_id=${{ vars.PRODUCT_ID }}" \
            -F "version=${{ github.ref_name }}"

GitLab CI

generate-sbom:
  stage: build
  image: anchore/syft:latest
  script:
    - syft dir:. -o cyclonedx-json > sbom.cdx.json
  artifacts:
    paths:
      - sbom.cdx.json
    expire_in: 90 days
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
    - if: $CI_COMMIT_TAG

Jenkins

pipeline {
    agent any

    stages {
        stage('Generate SBOM') {
            steps {
                sh '''
                    curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b .
                    ./syft dir:. -o cyclonedx-json > sbom.cdx.json
                '''
            }
        }

        stage('Archive SBOM') {
            steps {
                archiveArtifacts artifacts: 'sbom.cdx.json', fingerprint: true
            }
        }
    }
}

Docker Build Integration

Generate SBOM during Docker build:

# Multi-stage build with SBOM generation
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Generate SBOM in build stage
FROM anchore/syft:latest AS sbom
COPY --from=builder /app /app
RUN syft dir:/app -o cyclonedx-json > /sbom.cdx.json

# Final image
FROM node:20-slim
COPY --from=builder /app/dist /app
COPY --from=sbom /sbom.cdx.json /app/sbom.cdx.json
CMD ["node", "/app/index.js"]

SBOM Quality: Meeting TR-03183

The German BSI Technical Guideline TR-03183 extends the NTIA minimum elements. While not legally required across the EU, following TR-03183 ensures high-quality SBOMs.

Required Fields

Field Required By Notes
Component name NTIA + TR-03183 Package identifier
Version NTIA + TR-03183 Exact version string
Supplier NTIA + TR-03183 Vendor or maintainer
Unique identifier NTIA + TR-03183 PURL recommended
Dependency relationship NTIA + TR-03183 Direct vs transitive
Author of SBOM NTIA + TR-03183 Who created the SBOM
Timestamp NTIA + TR-03183 When SBOM was created
Hash values TR-03183 SHA-256 minimum
License TR-03183 SPDX license ID
Source repository TR-03183 VCS URL if available

Validating SBOM Quality

Use these tools to check your SBOM:

# Validate CycloneDX format
npm install -g @cyclonedx/cyclonedx-cli
cyclonedx validate --input-file sbom.cdx.json

# Check for minimum fields with jq
jq '.components[] | select(.version == null or .purl == null)' sbom.cdx.json

# Count components with hashes
jq '[.components[] | select(.hashes != null)] | length' sbom.cdx.json

Improving SBOM Quality

If your SBOM is missing data:

  1. Use lock files: package-lock.json, Pipfile.lock, go.sum contain more metadata
  2. Scan built artifacts: More complete than source-only scans
  3. Combine tools: Different tools find different components
  4. Add manual entries: For commercial or internal components

Keeping SBOMs Current

An SBOM is a snapshot. It must be updated to remain useful.

When to Regenerate

  • Every release (major, minor, patch)
  • After dependency updates
  • After security patches
  • When build configuration changes

Versioning Strategy

product-v1.0.0-sbom.cdx.json
product-v1.0.1-sbom.cdx.json
product-v1.1.0-sbom.cdx.json

Or use timestamps:

product-sbom-2026-01-15T10-30-00Z.cdx.json

Retention

The CRA requires 10-year retention. Store historical SBOMs:

  • In your artifact repository
  • In S3/cloud storage with lifecycle policies
  • In CRA Evidence for integrated compliance tracking

Common Pitfalls

One-time SBOM generation

Problem: Creating an SBOM once and never updating it.

Solution: Automate SBOM generation in CI/CD. Every build should produce a fresh SBOM.

Missing transitive dependencies

Problem: SBOM only lists direct dependencies, missing nested packages.

Solution: Use lock files, scan built artifacts, enable deep scanning options.

Wrong format version

Problem: Using CycloneDX 1.3 when TR-03183 recommends 1.4+.

Solution: Check your tool's output version. Update tools regularly.

No hash values

Problem: Components without cryptographic hashes can't be verified.

Solution: Ensure your tool includes hashes. Scan built artifacts rather than just source.

Manual creation

Problem: Hand-crafting SBOMs is error-prone and unsustainable.

Solution: Always automate. Manual entries only for components tools can't detect.

Ignoring internal components

Problem: Only documenting open-source dependencies, not proprietary code.

Solution: Internal components need documentation too. Add them manually or configure tools appropriately.

SBOM Implementation Checklist

SBOM IMPLEMENTATION CHECKLIST

FORMAT SELECTION:
[ ] CycloneDX 1.4+ or SPDX 2.3+ chosen
[ ] JSON format (machine-readable)
[ ] Decision documented

TOOLING:
[ ] Primary tool selected (Syft/Trivy/cdxgen)
[ ] Tool installed and tested locally
[ ] Output validated against schema

CI/CD INTEGRATION:
[ ] SBOM generation added to build pipeline
[ ] Artifacts stored with appropriate retention
[ ] Generation triggered on releases

QUALITY ASSURANCE:
[ ] All components have: name, version, supplier
[ ] Hash values present (SHA-256+)
[ ] License information included
[ ] Transitive dependencies captured
[ ] PURL identifiers used

OPERATIONS:
[ ] SBOM versioned alongside product releases
[ ] Historical SBOMs archived (10-year retention)
[ ] Process documented for team

OPTIONAL - CRA EVIDENCE INTEGRATION:
[ ] API token configured
[ ] Upload automated on release
[ ] Quality scoring enabled

Next Steps

With SBOM generation automated, you're ready for:

  1. Vulnerability scanning: Connect SBOMs to vulnerability databases
  2. License compliance: Analyze license obligations
  3. Technical file integration: Include SBOMs in CRA documentation
  4. ENISA reporting preparation: SBOMs enable rapid vulnerability identification

CRA Evidence automates this entire workflow:

  • Upload SBOMs via CLI or CI/CD
  • Automatic vulnerability scanning with Trivy
  • TR-03183 quality scoring
  • Technical file export with integrated SBOMs

Start generating compliant SBOMs at app.craevidence.com.

Requirements: Understand what the CRA requires for SBOMs in our SBOM requirements guide.

Quality: Validate your SBOM against the BSI TR-03183 standard.

VEX: Add vulnerability context to your SBOM with VEX documents.


This article is for informational purposes only and does not constitute legal advice. For specific compliance guidance, consult with qualified legal counsel familiar with EU product regulations.

Topics covered in this article

Share this article

Related Articles

Does the CRA apply to your product?

Answer 6 simple questions to find out if your product falls under the EU Cyber Resilience Act scope. Get your result in under 2 minutes.

Ready to achieve CRA compliance?

Start managing your SBOMs and compliance documentation with CRA Evidence.