๐Ÿ“„ CycloneDX SBOM Generator Action

A comprehensive GitHub Action for generating Software Bill of Materials (SBOM) files using the CycloneDX .NET Global Tool with extensive configuration options and cross-platform support.

โœจ Features

  • ๐Ÿ“„ SBOM Generation - Creates CycloneDX-compliant Software Bill of Materials
  • ๐Ÿ”ง Multiple Formats - Supports XML, JSON, and UnsafeJSON output formats
  • ๐ŸŽฏ Smart Detection - Handles .sln, .csproj, packages.config, and directory scanning
  • ๐Ÿ” GitHub Integration - License resolution using GitHub API
  • ๐Ÿ“ฆ Dependency Management - Excludes dev/test dependencies with filtering options
  • ๐Ÿ›ก๏ธ Security-First - Automatic masking of sensitive tokens and passwords
  • โšก Performance Optimized - Configurable timeouts and restore options
  • ๐ŸŒ Cross-Platform - Works on Windows, Linux, and macOS runners

๐Ÿš€ Basic Usage

Minimal configuration to generate an SBOM:

- name: "Generate SBOM"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    path: "./src/MyProject.csproj"
- name: "Generate JSON SBOM"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    path: "./MySolution.sln"
    output-format: "Json"
- name: "Generate SBOM for entire directory"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    working-directory: "./src"
    recursive: "true"

๐Ÿ”ง Advanced Usage

Full configuration with all available options:

- name: "Advanced SBOM generation"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    path: "./src/MyApp/MyApp.csproj"
    working-directory: "./backend"
    framework: "net8.0"
    runtime: "linux-x64"
    output: "./sbom"
    filename: "software-bom.json"
    output-format: "Json"
    exclude-dev: "true"
    exclude-test-projects: "true"
    recursive: "true"
    enable-github-licenses: "true"
    github-bearer-token: "${{ secrets.GITHUB_TOKEN }}"
    set-name: "MyApplication"
    set-version: "1.2.3"
    set-type: "Application"
    exclude-filter: "TestFramework@1.0.0,MockLibrary@2.1.0"
    dotnet-command-timeout: "600000"
    global: "true"
    show-summary: "true"

๐Ÿ” Permissions Required

This action requires standard repository permissions:

permissions:
  contents: read  # Required to checkout repository code

For GitHub license resolution, add:

permissions:
  contents: read
  metadata: read  # Optional: for enhanced GitHub license resolution

Note: When using github-bearer-token, the GITHUB_TOKEN secret provides sufficient permissions for license resolution.

๐Ÿ—๏ธ CI/CD Example

Complete workflow for .NET SBOM generation:

name: "SBOM Generation Pipeline"

on:
  push:
    branches: ["main", "develop"]
  pull_request:
    branches: ["main"]

permissions:
  contents: read
  metadata: read

jobs:
  generate-sbom:
    runs-on: ubuntu-latest

    steps:
      - name: "๐Ÿ“ฅ Checkout repository"
        uses: actions/checkout@v4

      - name: "๐Ÿ”ง Setup .NET"
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "8.0.x"

      - name: "๐Ÿ“ฆ Restore dependencies"
        uses: laerdal/github_actions/dotnet@main
        with:
          command: "restore"

      - name: "๐Ÿ“„ Generate SBOM"
        id: generate-sbom
        uses: laerdal/github_actions/dotnet-cyclonedx@main
        with:
          path: "./src/MyApp.sln"
          output: "./artifacts/sbom"
          output-format: "Json"
          filename: "software-bill-of-materials.json"
          exclude-dev: "true"
          exclude-test-projects: "true"
          enable-github-licenses: "true"
          github-bearer-token: "${{ secrets.GITHUB_TOKEN }}"
          set-name: "${{ github.repository }}"
          set-version: "${{ github.ref_name }}"
          show-summary: "true"

      - name: "๐Ÿ“ค Upload SBOM artifact"
        uses: actions/upload-artifact@v4
        with:
          name: "software-bill-of-materials"
          path: ${{ steps.generate-sbom.outputs.sbom-path }}

      - name: "๐Ÿ” Validate SBOM generation"
        run: |
          echo "SBOM generated: ${{ steps.generate-sbom.outputs.is-sbom-generated }}"
          echo "SBOM location: ${{ steps.generate-sbom.outputs.sbom-path }}"
          ls -la ${{ steps.generate-sbom.outputs.sbom-path }}

๐Ÿ“‹ Inputs

Input Description Required Default Example
path Path to .sln, .csproj, packages.config file or directory โŒ No "" ./src/MyProject.csproj
working-directory Working directory for command execution โŒ No "." ./backend
framework Target framework to use โŒ No "" net8.0, net6.0
runtime Target runtime identifier โŒ No "" win-x64, linux-x64
output Directory to write the SBOM โŒ No "" ./sbom, ./artifacts
filename Custom filename for the SBOM โŒ No "" software-bom.xml, app-sbom.json
output-format SBOM output format โŒ No "Auto" Auto, Json, UnsafeJson, Xml
exclude-dev Exclude development dependencies โŒ No "false" true, false
exclude-test-projects Exclude test projects โŒ No "false" true, false
recursive Recursively scan project references โŒ No "false" true, false
no-serial-number Omit serial number from SBOM โŒ No "false" true, false
enable-github-licenses Enable GitHub license resolution โŒ No "false" true, false
github-username GitHub username for license resolution โŒ No "" myusername
github-token GitHub personal access token โŒ No "" ${{ secrets.GITHUB_TOKEN }}
github-bearer-token GitHub bearer token (recommended) โŒ No "" ${{ secrets.GITHUB_TOKEN }}
url Alternative NuGet repository URL โŒ No "" https://nuget.example.com/v3/index.json
baseUrlUsername Alternative NuGet repository username โŒ No "" nuget-user
baseUrlUserPassword Alternative NuGet repository password โŒ No "" ${{ secrets.NUGET_PASSWORD }}
isBaseUrlPasswordClearText NuGet password is cleartext โŒ No "false" true, false
disable-package-restore Disable package restore โŒ No "false" true, false
disable-hash-computation Disable hash computation โŒ No "false" true, false
dotnet-command-timeout Command timeout in milliseconds โŒ No "300000" 600000, 900000
include-project-references Include project references as components โŒ No "false" true, false
set-name Override BOM component name โŒ No "" MyApplication
set-version Override BOM component version โŒ No "" 1.0.0, 2.1.3
set-type Override BOM component type โŒ No "Application" Library, Framework
set-nuget-purl Override BOM ref and PURL as NuGet package โŒ No "false" true, false
exclude-filter Dependencies to exclude (name@version) โŒ No "" TestLib@1.0.0,MockFramework@2.0.0
base-intermediate-output-path Custom build environment folder โŒ No "" ./custom-obj
import-metadata-path Metadata template file path โŒ No "" ./templates/metadata.json
global Install CycloneDX global tool if needed โŒ No "true" true, false
show-summary Display action summary โŒ No "false" true, false

๐Ÿ“ค Outputs

Output Description Type Example
exit-code Exit code of the CycloneDX command string 0, 1
executed-command Full command that was executed string dotnet tool run CycloneDX ./src --output-format Json
sbom-path Path to the generated SBOM file string ./sbom/bom.json
is-sbom-generated Whether SBOM was successfully generated string true, false
Action Purpose Repository
๐Ÿš€ dotnet Execute .NET CLI commands laerdal/github_actions/dotnet
๐Ÿ”ง dotnet-tool-install Install .NET global tools laerdal/github_actions/dotnet-tool-install
๐Ÿงช dotnet-test Enhanced .NET testing laerdal/github_actions/dotnet-test

๐Ÿ’ก Examples

Different Output Formats

- name: "Generate XML SBOM"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    path: "./src/MyApp.csproj"
    output-format: "Xml"
    filename: "software-bom.xml"

- name: "Generate JSON SBOM"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    path: "./src/MyApp.csproj"
    output-format: "Json"
    filename: "software-bom.json"

Multi-Project Solution

- name: "Generate SBOM for entire solution"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    path: "./MySolution.sln"
    exclude-test-projects: "true"
    exclude-dev: "true"
    recursive: "true"
    output: "./artifacts/sbom"

Framework-Specific SBOM

strategy:
  matrix:
    framework: ["net6.0", "net8.0"]

steps:
  - name: "Generate SBOM for ${{ matrix.framework }}"
    uses: laerdal/github_actions/dotnet-cyclonedx@main
    with:
      path: "./src/MultiTarget.csproj"
      framework: ${{ matrix.framework }}
      filename: "sbom-${{ matrix.framework }}.json"
      output-format: "Json"

GitHub License Resolution

- name: "Generate SBOM with license information"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    path: "./src/MyApp.csproj"
    enable-github-licenses: "true"
    github-bearer-token: "${{ secrets.GITHUB_TOKEN }}"
    output-format: "Json"

Custom NuGet Repository

- name: "Generate SBOM from private NuGet"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    path: "./src/MyApp.csproj"
    url: "https://nuget.company.com/v3/index.json"
    baseUrlUsername: "${{ secrets.NUGET_USERNAME }}"
    baseUrlUserPassword: "${{ secrets.NUGET_PASSWORD }}"
    isBaseUrlPasswordClearText: "false"

Dependency Filtering

- name: "Generate filtered SBOM"
  uses: laerdal/github_actions/dotnet-cyclonedx@main
  with:
    path: "./src/MyApp.csproj"
    exclude-dev: "true"
    exclude-test-projects: "true"
    exclude-filter: "Microsoft.AspNetCore.App@8.0.0,System.Text.Json@7.0.0"
    output-format: "Json"

๐Ÿ”ง Output Format Support

Format Description File Extension Use Case
Auto Automatically detects based on filename .xml or .json Default, flexible
Xml CycloneDX XML format .xml Standards compliance
Json CycloneDX JSON format .json API integration
UnsafeJson JSON with relaxed escaping .json Special characters

๐ŸŽฏ Component Types

Type Description Example Use Case
Application Standalone application Web apps, desktop apps
Library Reusable library NuGet packages, class libraries
Framework Development framework ASP.NET Core, Entity Framework
Container Container image Docker containers
Operating_System OS components Linux distributions
Device Hardware device IoT devices
Firmware Device firmware Embedded systems

๐Ÿ› Troubleshooting

Common Issues

CycloneDX Tool Not Found

Problem: CycloneDX global tool is not installed

Solution: Ensure global: "true" (default) or install manually:

- name: "Install CycloneDX"
  run: dotnet tool install --global CycloneDX

Project File Not Found

Problem: Specified path does not exist

Solution: Verify the path and file existence:

- name: "Check project file"
  run: ls -la ./src/MyProject.csproj

GitHub API Rate Limiting

Problem: License resolution fails due to rate limits

Solution: Provide authentication token:

github-bearer-token: "${{ secrets.GITHUB_TOKEN }}"
enable-github-licenses: "true"

Large Project Timeouts

Problem: Command times out on large solutions

Solution: Increase timeout value:

dotnet-command-timeout: "900000"  # 15 minutes

Missing Dependencies in SBOM

Problem: Some dependencies not included

Solution: Ensure proper restore and disable selective restore:

disable-package-restore: "false"
recursive: "true"

Debug Tips

  1. Enable Summary: Set show-summary: "true" for detailed information
  2. Check Outputs: Use the sbom-path output to verify file location
  3. Validate Format: Ensure the generated SBOM is valid CycloneDX
  4. Review Exclusions: Check if dependencies are excluded by filters

๐Ÿ“ Requirements

  • GitHub Actions runner (Windows, Linux, or macOS)
  • .NET SDK installed (use actions/setup-dotnet)
  • Valid .NET project, solution, or packages.config structure
  • CycloneDX global tool (auto-installed by default)

๐Ÿ”’ Security Considerations

  • Token Masking: Sensitive tokens are automatically masked in logs
  • Private Repositories: Use appropriate authentication for private NuGet feeds
  • License Data: GitHub license resolution requires minimal read permissions
  • SBOM Content: Review generated SBOMs before publishing to ensure no sensitive data

๐Ÿ“‹ SBOM Standards Compliance

This action generates CycloneDX-compliant SBOMs that meet:

  • CycloneDX Specification: Follows official CycloneDX schema
  • SPDX Compatibility: Can be converted to SPDX format
  • NTIA Minimum Elements: Includes required SBOM components
  • Supply Chain Security: Supports vulnerability scanning integration

๐Ÿ“„ License

This action is part of the GitHub Actions collection by Francois Raminosona.


๐Ÿ’ก Tip: For complete SBOM workflows, combine this action with our signing and publishing actions in the Related Actions section.