-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Implement CycloneDX.MSBuild NuGet package with corrected parameters #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Implement CycloneDX.MSBuild NuGet package with corrected parameters #2
Conversation
There was a problem hiding this 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,-Finstead 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
c10bc91 to
3ae48ea
Compare
- 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.
There was a problem hiding this 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.
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
## [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))
• Projekt-Struktur mit build/ und buildMultiTargeting/ Ordnern
• Korrekte NuGet Package-Konfiguration
• Development Dependency Markierung
• ✅ -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)
• ✅ 8.0 im MultiTargetProject
• ✅ Korrekte Behandlung: SBOM wird nur einmal generiert, nicht pro Framework
• SimpleProject (Single-Target)
• MultiTargetProject (Multi-Target mit .NET 6, 8, Standard 2.0)
• DisabledProject (SBOM deaktiviert)
• README.md mit korrekten Konfigurationsbeispielen
• CONTRIBUTING.md mit Development Guidelines
• .editorconfig und .gitattributes
• Sandboxed Execution
• Input Validation
• Fail-Safe Defaults
• Dependency Pinning