-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CSHARP-5626 Add evergreen script to generate CycloneDX SBOM #1718
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,87 @@ | ||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||
| set -o errexit # Exit the script with error if any of the commands fail | ||||||||||||||
|
|
||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Add a comment block to describe variables used in the script. |
||||||||||||||
| # Accommodate Git Bash or MSYS2 on Windows | ||||||||||||||
| export MSYS_NO_PATHCONV=1 | ||||||||||||||
|
|
||||||||||||||
| echo -e "\n************************************************" | ||||||||||||||
|
|
||||||||||||||
| # Get Packages Version if variable is empty | ||||||||||||||
| if [[ -z "$PACKAGE_VERSION" ]]; then | ||||||||||||||
| PACKAGE_VERSION=$(bash ./evergreen/get-version.sh) | ||||||||||||||
| fi | ||||||||||||||
|
|
||||||||||||||
| echo "Package Version: ${PACKAGE_VERSION}" | ||||||||||||||
|
|
||||||||||||||
| # Get array of Package Names | ||||||||||||||
| source ./evergreen/packages.sh | ||||||||||||||
| echo "Packages: ${PACKAGES[*]}" | ||||||||||||||
|
|
||||||||||||||
| # Run a restore that will set the package version in the Directory.Build.props file, otherwise it is set to "0.0.0-local" | ||||||||||||||
| # This will also cause the Choose...When conditions in the .csproj files to use PackageReference instead of ProjectReference | ||||||||||||||
| echo "Restoring solution with version set to ${PACKAGE_VERSION}" | ||||||||||||||
| dotnet restore /p:Version=${PACKAGE_VERSION} | ||||||||||||||
|
|
||||||||||||||
| # Install cyclonedx-dotnet using latest version tested with this script | ||||||||||||||
| echo "Installing cyclonedx-dotnet" | ||||||||||||||
| dotnet tool install --global CycloneDX --version 5.3.1 --allow-downgrade | ||||||||||||||
|
|
||||||||||||||
| echo -e "\nGenerating SBOMs" | ||||||||||||||
| echo "************************************************" | ||||||||||||||
|
|
||||||||||||||
| # Track SBOM file paths for merging | ||||||||||||||
| SBOM_FILES="" | ||||||||||||||
|
|
||||||||||||||
| for package in ${PACKAGES[*]}; do | ||||||||||||||
| echo -e "\n+++++++++++++++++++++++++++++++++++++" | ||||||||||||||
| echo "Processing: ${package}" | ||||||||||||||
|
|
||||||||||||||
| SBOM_FILE="sbom.${package}.cdx.json" | ||||||||||||||
| SBOM_FILES="${SBOM_FILES} /pwd/${SBOM_FILE}" | ||||||||||||||
|
|
||||||||||||||
| echo "SBOM file: ${SBOM_FILE}" | ||||||||||||||
|
|
||||||||||||||
| # There are nuances to how cyclonedx-dotnet handles <PackageReference> items in Directory.Build.props that lead to private packages being included in SBOM | ||||||||||||||
| # results even when PrivateAssets is set to "All". As a safeguard, this command lists the PackageReferences and adds the references with PrivateAssets="All" | ||||||||||||||
| # to an exclusion filter variable to be fed into cyclonedx-dotnet | ||||||||||||||
| EXCLUDE_FILTER=$(dotnet msbuild ./src/${package}/${package}.csproj -getItem:PackageReference | jq -r '[.Items.PackageReference[] | select(.PrivateAssets != null) | select(.PrivateAssets | test ("All"; "i")) | .Identity + "@" + .Version] | join(",")') | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the option |
||||||||||||||
| echo "Excluded Private Package References: ${EXCLUDE_FILTER}" | ||||||||||||||
|
|
||||||||||||||
| # The ProjectReference items do not resolve as the Nuget packages they represent. This causes duplicate components when the SBOMs are merged. To address this | ||||||||||||||
| # we add the Nuget PURL to the JSON. This command lists the ProjectReferences for processing. | ||||||||||||||
| PURL_PATCHES=$(dotnet msbuild ./src/${package}/${package}.csproj -getItem:ProjectReference | jq -r '[.Items.ProjectReference[] | .Filename] | join(",")') | ||||||||||||||
| echo "Project References requiring added PURL: ${PURL_PATCHES}" | ||||||||||||||
|
|
||||||||||||||
| echo "+++++++++++++++++++++++++++++++++++++" | ||||||||||||||
|
|
||||||||||||||
| ## Run cyclonedx-dotnet | ||||||||||||||
| # Attempt GitHub license resolution only if GITHUB_USER and GITHUB_APIKEY are both set | ||||||||||||||
| if [[ -v GITHUB_USER && -v GITHUB_APIKEY ]]; then | ||||||||||||||
| github_options=(--enable-github-licenses --github-username ${GITHUB_USER} --github-token ${GITHUB_APIKEY}) | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add some echo messages to indicate whether github license resolution is enabled or not |
||||||||||||||
| fi | ||||||||||||||
|
|
||||||||||||||
| echo "dotnet-CycloneDX src/${package}/${package}.csproj --disable-package-restore --set-type library --set-nuget-purl --exclude-dev --include-project-references --set-name ${package} --set-version ${PACKAGE_VERSION} --filename ${SBOM_FILE} --exclude-filter ${EXCLUDE_FILTER} ${github_options[@]}" | ||||||||||||||
| dotnet-CycloneDX src/${package}/${package}.csproj \ | ||||||||||||||
| --disable-package-restore --set-type library --set-nuget-purl --exclude-dev --include-project-references \ | ||||||||||||||
| --set-name ${package} --set-version ${PACKAGE_VERSION} --filename ${SBOM_FILE} \ | ||||||||||||||
| --exclude-filter "${EXCLUDE_FILTER}" \ | ||||||||||||||
| "${github_options[@]}" | ||||||||||||||
|
|
||||||||||||||
| # Patch JSON file with PURLs, as needed | ||||||||||||||
| for patch in $PURL_PATCHES; do | ||||||||||||||
| echo "Patching ${patch} with Nuget PURL" | ||||||||||||||
| contents=$(jq --arg package "$patch" --arg version "$PACKAGE_VERSION" '.components |= map(if [.name | startswith("MongoDB.")] and has("purl") == false then .purl = "pkg:nuget/\($package)@\($version)" else . end)' ${SBOM_FILE}) | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: If a package has multiple ProjectReferences (e.g., MongoDB.Driver references both MongoDB.Bson and MongoDB.Driver.Core), won't this logic:
Should the condition be .name == $package instead of .name | startswith("MongoDB.")? |
||||||||||||||
| echo -E "${contents}" >${SBOM_FILE} | ||||||||||||||
| done | ||||||||||||||
|
|
||||||||||||||
| done | ||||||||||||||
|
|
||||||||||||||
| echo -e "\n=================================" | ||||||||||||||
| echo "Merging SBOMs using cyclonedx-cli" | ||||||||||||||
| echo "=================================" | ||||||||||||||
|
|
||||||||||||||
| # Use cyclonedx-cli to merge the SBOMs into 1 hierarchical SBOM | ||||||||||||||
| docker run --platform="linux/amd64" --rm -v ${PWD}:/pwd \ | ||||||||||||||
| cyclonedx/cyclonedx-cli:0.28.2 \ | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if we should be using latest here or not. But if we use a specific version as now, should we include the digest as well for security? |
||||||||||||||
| merge --input-files ${SBOM_FILES} --output-file /pwd/sbom.cdx.json \ | ||||||||||||||
| --hierarchical --group mongodb --name mongo-csharp-driver --version ${PACKAGE_VERSION} | ||||||||||||||
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.
I don't think /pwd/ is available in this context since we are outside the docker command. I think it should be ${PWD}