Skip to content

Conversation

@dborgards
Copy link
Owner

  1. Vollständiges MSBuild Targets Package
    • Projekt-Struktur mit build/ und buildMultiTargeting/ Ordnern
    • Korrekte NuGet Package-Konfiguration
    • Development Dependency Markierung
  2. Korrekte CycloneDX Tool Parameter
    • ✅ -o statt --output-directory
    • ✅ -fn statt --output-filename
    • ✅ -F Json/Xml statt --output-format json/xml
    • ✅ -ed, -t, -ns für Optionen
    • ✅ Entfernt: --spec-version, --include-license-text
    • ✅ Hinzugefügt: GitHub Lizenz-Resolution (-egl, -gu, -gt)
  3. Multi-Targeting Support
    • ✅ 8.0 im MultiTargetProject
    • ✅ Korrekte Behandlung: SBOM wird nur einmal generiert, nicht pro Framework
  4. Drei Test-Projekte
    • SimpleProject (Single-Target)
    • MultiTargetProject (Multi-Target mit .NET 6, 8, Standard 2.0)
    • DisabledProject (SBOM deaktiviert)
  5. Vollständige Dokumentation
    • README.md mit korrekten Konfigurationsbeispielen
    • CONTRIBUTING.md mit Development Guidelines
    • .editorconfig und .gitattributes
  6. Security by Design
    • Sandboxed Execution
    • Input Validation
    • Fail-Safe Defaults
    • Dependency Pinning

@dborgards dborgards requested a review from Copilot November 30, 2025 20:14
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a complete MSBuild NuGet package for automatic CycloneDX SBOM generation with corrected CLI parameters, multi-targeting support, and comprehensive testing infrastructure. The implementation follows security-by-design principles and clean code practices.

Key Changes:

  • Corrected CycloneDX tool parameters (using short flags like -o, -fn, -F instead of long-form options)
  • Multi-targeting support with proper handling to generate SBOMs once per project
  • Three integration test projects covering single-target, multi-target, and disabled scenarios

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/CycloneDX.MSBuild/CycloneDX.MSBuild.csproj Package definition with metadata and build configuration
src/CycloneDX.MSBuild/build/CycloneDX.MSBuild.props Configurable MSBuild properties with defaults
src/CycloneDX.MSBuild/build/CycloneDX.MSBuild.targets Build targets for SBOM generation workflow
src/CycloneDX.MSBuild/buildMultiTargeting/*.{props,targets} Multi-targeting support to prevent per-framework generation
tests/Integration.Tests/SimpleProject/* Single-target test project
tests/Integration.Tests/MultiTargetProject/* Multi-targeting test project
tests/Integration.Tests/DisabledProject/* Test project with SBOM generation disabled
README.md Comprehensive documentation with usage examples
CONTRIBUTING.md Development guidelines and contribution process
.editorconfig, .gitattributes Code style and Git configuration
CycloneDX.MSBuild.sln Solution file organizing projects

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

This commit fixes the SBOM generation issue by correcting command-line
parameters to match the official CycloneDX .NET tool API.

Changes:
1. Fixed command-line parameters in CycloneDX.MSBuild.targets:
   - Changed --output-directory to -o
   - Changed --output-filename to -fn
   - Changed --output-format to -F with capitalized values (Json/Xml)
   - Removed unsupported --spec-version parameter
   - Removed unsupported --include-license-text parameter
   - Removed unsupported --serial-number parameter
   - Updated optional flags: --exclude-dev to -ed, --exclude-test-projects to -t
   - Added -ns for disabling serial numbers
   - Added GitHub license resolution: -egl, -gu, -gt

2. Updated MSBuild properties in CycloneDX.MSBuild.props:
   - Removed CycloneDxSpecVersion (not supported by tool)
   - Removed CycloneDxIncludeLicenseText (not supported)
   - Replaced CycloneDxSerialNumber with CycloneDxDisableSerialNumber
   - Added GitHub license resolution properties:
     * CycloneDxEnableGitHubLicenses
     * CycloneDxGitHubUsername
     * CycloneDxGitHubToken

3. Simplified validation in CycloneDX.MSBuild.targets:
   - Removed spec version validation
   - Kept simplified output format validation

4. Fixed MultiTargetProject test project:
   - Added <LangVersion>8.0</LangVersion> as required

These changes ensure SBOM generation works correctly by using the
proper command-line syntax documented at:
https://github.com/CycloneDX/cyclonedx-dotnet
@dborgards dborgards force-pushed the claude/cyclonedx-nuget-package-01EkX7VTfBKakXEbsnQoSXCb branch from c10bc91 to 3ae48ea Compare November 30, 2025 20:21
- Changed LangVersion from 8.0 to 10.0 (required for ImplicitUsings)
- Made ImplicitUsings and Nullable conditional for .NET 6+ only
- This prevents compilation errors with netstandard2.0 target
Aligned all license references with the actual MIT License in LICENSE file:
- README.md: Changed Apache 2.0 to MIT (badge and license section)
- CycloneDX.MSBuild.csproj: Changed PackageLicenseExpression to MIT
- CONTRIBUTING.md: Updated contributor license agreement to MIT

The LICENSE file contains MIT License, so all references should be consistent.
Removed outdated documentation for properties that are no longer supported:
- Removed CycloneDxSpecVersion section (tool auto-selects version)
- Removed CycloneDxIncludeLicenseText (not supported by tool)
- Removed CycloneDxSerialNumber (replaced with CycloneDxDisableSerialNumber)

Added documentation for newly supported properties:
- CycloneDxDisableSerialNumber (control serial number generation)
- CycloneDxEnableGitHubLicenses (enable GitHub license resolution)
- CycloneDxGitHubUsername and CycloneDxGitHubToken (GitHub credentials)

Updated specification version section to clarify automatic version selection.
MSBuild only auto-imports .props and .targets from NuGet packages, not from
ProjectReference. For local development and testing, we need to explicitly
import the targets files.

Changes:
- SimpleProject: Added manual imports to build/*.props and build/*.targets
- MultiTargetProject: Added manual imports to buildMultiTargeting/*.props and *.targets
- DisabledProject: Added manual imports to build/*.props and build/*.targets

This allows the targets to execute during local builds, showing messages like
'SBOM generated successfully' and actually generating the SBOM files.

Note: When the package is consumed as a NuGet PackageReference (the normal use case),
these manual imports are not needed - MSBuild handles it automatically.
Problem: $(OutputPath) is not available when .props file is evaluated,
resulting in empty -o "" parameter causing 'The path is empty' error.

Solution: Move CycloneDxOutputDirectory default from .props to .targets,
setting it just before use when $(OutputPath) is available.

Changes:
- Removed CycloneDxOutputDirectory default from .props
- Added PropertyGroup in .targets to set default before command building
- Added comment explaining why default is set in .targets

This fixes the error:
'System.ArgumentException: The path is empty. (Parameter 'path')'
Fixes command-line quote escaping issue where trailing backslash
in $(OutputPath) like "bin\Debug\net8.0\" would escape the closing
quote in -o "path\" argument, causing invalid syntax error.

The fix uses TrimEnd to remove trailing backslashes and forward
slashes before passing the path to the CycloneDX tool.
MSBuild property functions require backslash to be escaped as '\\'
instead of '\'. This should now properly remove trailing slashes
from the output directory path.
- Changed CycloneDxOutputFilename default from "bom" to "sbom"
- Updated documentation to reflect new default
- Results in sbom.json or sbom.xml instead of bom.json or bom.xml
The -fn parameter requires the full filename including extension.
Now constructs full filename (sbom.json or sbom.xml) based on
the output format before passing to CycloneDX tool.
@dborgards dborgards requested a review from Copilot December 1, 2025 05:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Added defensive fallbacks for _CycloneDxFullFilename and
_CycloneDxOutputFormat to default to JSON format if the
CycloneDxOutputFormat property contains an invalid value.

This prevents undefined variables from being passed to the
CycloneDX tool command line.
@dborgards dborgards merged commit 89f3429 into main Dec 1, 2025
@dborgards dborgards deleted the claude/cyclonedx-nuget-package-01EkX7VTfBKakXEbsnQoSXCb branch December 1, 2025 06:04
dborgards pushed a commit that referenced this pull request Dec 2, 2025
Add -maxcpucount:1 (-m:1) to dotnet build commands in CI to prevent
solution-level parallel building. This is the root cause of persistent
file locking issues on CycloneDX.MSBuild files.

Problem Analysis:
- The solution contains 3 projects: CycloneDX.MSBuild, Tests, Benchmarks
- Solution has ProjectDependencies declaring Tests and Benchmarks depend
  on CycloneDX.MSBuild
- However, MSBuild by default builds these dependencies in parallel
- Both Tests and Benchmarks try to build CycloneDX.MSBuild simultaneously
- This causes file locking on:
  * deps.json (GenerateDepsFile task)
  * .editorconfig (Roslyn compiler)
  * Reference assemblies in _references/ directory

Previous fixes addressed:
- Project-level parallel builds (BuildInParallel=false)
- Configuration propagation (Configuration=$(Configuration))
- Removing Integration.Tests from solution
- Test collection serialization

But none of these controlled solution-level parallelism.

Solution:
The -m:1 flag forces MSBuild to build all projects sequentially at the
solution level, eliminating all parallel access to shared CycloneDX.MSBuild
files.

Build order will now be:
1. CycloneDX.MSBuild (builds once)
2. Tests (sequential, waits for #1)
3. Benchmarks (sequential, waits for #2)

This trades some build performance for reliability. The CI builds complete
in ~5-7 seconds anyway, so the impact is minimal.

Changes:
- .github/workflows/ci.yml: Add -m:1 to both build commands
  * Line 44: Build and Test job
  * Line 96: Code Quality job
github-actions bot pushed a commit that referenced this pull request Dec 3, 2025
## [1.3.0](v1.2.1...v1.3.0) (2025-12-03)

### ✨ Features

* implement comprehensive project improvements ([f77d85a](f77d85a))

### 🐛 Bug Fixes

* add detailed diagnostics to failing tests ([bbad9d3](bbad9d3))
* add detailed SBOM structure validation diagnostics ([1cd0d92](1cd0d92))
* add GetTargetPath target to MultiTargetProject for tooling compatibility ([a5ce1e9](a5ce1e9))
* add Integration.Tests projects as build dependencies ([9d6276f](9d6276f))
* add new test projects to solution file ([39f24f5](39f24f5))
* add project dependencies and prevent parallel builds for benchmarks and integration tests ([86e07f3](86e07f3))
* code formatting - add braces to single-line if statements ([cacc977](cacc977))
* disable package generation in test project references ([78e2723](78e2723))
* disable parallel builds at solution level with -m:1 ([7be6b47](7be6b47)), closes [#1](#1) [#2](#2)
* disable parallel builds for all Integration.Tests projects ([c367c05](c367c05))
* enable SBOM copy to publish directory for multi-target inner builds ([4a26668](4a26668))
* enhance test diagnostics to identify missing SBOM fields ([7ebf344](7ebf344))
* improve test reliability and publish SBOM functionality ([8c27290](8c27290))
* improve version field detection regex to handle any field order ([6a9f7af](6a9f7af))
* isolate project outputs and prevent file locking during builds ([0cba86c](0cba86c))
* pass Configuration property to all ProjectReferences ([ed9b2bd](ed9b2bd))
* prevent parallel builds of MultiTargetProject inner frameworks ([03598ed](03598ed))
* prevent parallel builds of shared CycloneDX.MSBuild dependency ([74cadd1](74cadd1))
* properly calculate CycloneDxOutputPath in targets instead of props ([e3f723b](e3f723b))
* remove Integration.Tests projects from solution to prevent parallel builds ([c83a316](c83a316))
* remove invalid dotnet_diagnostic properties from MSBuild file ([d66e5e2](d66e5e2))
* remove invalid return statement from MSBuild inline task ([2cc6d4d](2cc6d4d))
* rename XUnit collection classes to avoid CA1711 warning ([c2d5d48](c2d5d48))
* replace System.Text.Json with regex-based approach for MSBuild task compatibility ([04e50b0](04e50b0))
* serialize integration tests to prevent file locking ([0a392a9](0a392a9))
* specify target framework for multi-target project publish test ([9e1d02f](9e1d02f))
* suppress code analysis warnings for test projects ([92dd8b0](92dd8b0))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants