Skip to content

Commit f5c13b3

Browse files
CSHARP-5626: Add evergreen script to generate CycloneDX SBOM
Added a bash script to generate a 'build' lifecycle CycloneDX SBOM using the cyclonedx-dotnet tool. The script installed a fixed version of cyclonedx-dotnet, runs a versioned dotnet restore, and generates an SBOM for each of the 4 MongoDB.Driver Nuget packages. To ensure accurate results, two queries are run against each of the .csproj files to ensure all development packages are excluded and that any local <ProjectReference> items are marked in the SBOM as Nuget packages. Once all 4 SBOMs are created, they are merged into a single heirarchical SBOM file. The file is saved as sbom.cdx.json (as opposed to the current sbom.json) which is the preferred file extention for CycloneDX files. There is not yet any code to commit the new SBOM to the repo. This is to allow for evaluation of the new SBOM first without intefering with the current workflow to upload the current static sbom.json file to Kondukto. There is also a line added to download-augmented-sbom.sh to copy the augmented SBOM to ./vex.cdx.json (also not yet committed to repo) after it has been uploaded to the release artifacts bucket, as this is how we should be storing the augmented SBOM for public consumption. Once the SBOM generation process has been approved, I will add commit code for both of the cdx.json files, remove th sbom.json file and update download-augmented-sbom.sh to use the new sbom.cdx.json file.
1 parent c4cc5e3 commit f5c13b3

File tree

3 files changed

+106
-134
lines changed

3 files changed

+106
-134
lines changed

evergreen/download-augmented-sbom.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ echo "KONDUKTO_TOKEN=$kondukto_token" > ${PWD}/kondukto_credentials.env
2121
docker run --platform="linux/amd64" --rm -v ${PWD}:/pwd \
2222
--env-file ${PWD}/kondukto_credentials.env \
2323
artifactory.corp.mongodb.com/release-tools-container-registry-public-local/silkbomb:2.0 \
24-
augment --repo mongodb/mongo-csharp-driver --branch main --sbom-in /pwd/sbom.json --sbom-out /pwd/${SSDLC_PATH}/augmented-sbom.json
24+
augment --repo mongodb/mongo-csharp-driver --branch main --sbom-in /pwd/sbom.json --sbom-out /pwd/${SSDLC_PATH}/augmented-sbom.json
25+
26+
cp /pwd/${SSDLC_PATH}/augmented-sbom.json ./vex.cdx.json

evergreen/evergreen.yml

Lines changed: 16 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,9 @@ functions:
9898
install-dotnet:
9999
- command: shell.exec
100100
params:
101-
include_expansions_in_env:
102-
- "OS"
103-
- "DOTNET_SDK_VERSION"
104-
- "FRAMEWORK"
105101
script: |
106102
${PREPARE_SHELL}
107-
bash ${PROJECT_DIRECTORY}/evergreen/install-dotnet.sh
103+
OS=${OS} DOTNET_SDK_VERSION=${DOTNET_SDK_VERSION} bash ${PROJECT_DIRECTORY}/evergreen/install-dotnet.sh
108104
109105
prepare-resources:
110106
- command: shell.exec
@@ -280,6 +276,18 @@ functions:
280276
content_type: application/json
281277
display_name: augmented-sbom.json
282278

279+
generate-sbom:
280+
- command: shell.exec
281+
params:
282+
working_dir: "mongo-csharp-driver"
283+
env:
284+
GITHUB_USER: ${github_user}
285+
GITHUB_APIKEY: ${github_apikey}
286+
PACKAGE_VERSION: ${PACKAGE_VERSION}
287+
script: |
288+
${PREPARE_SHELL}
289+
./evergreen/generate-sbom.sh
290+
283291
generate-ssdlc-report:
284292
- command: shell.exec
285293
params:
@@ -318,10 +326,6 @@ functions:
318326
bootstrap-mongohoused:
319327
- command: shell.exec
320328
params:
321-
include_expansions_in_env:
322-
- "AWS_ACCESS_KEY_ID"
323-
- "AWS_SECRET_ACCESS_KEY"
324-
- "AWS_SESSION_TOKEN"
325329
script: |
326330
DRIVERS_TOOLS="${DRIVERS_TOOLS}" bash ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/pull-mongohouse-image.sh
327331
- command: shell.exec
@@ -360,18 +364,6 @@ functions:
360364
cd ${DRIVERS_TOOLS}/.evergreen
361365
DRIVERS_TOOLS=${DRIVERS_TOOLS} MONGODB_URI=${MONGODB_URI} bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh stop
362366
363-
run-unit-tests:
364-
- command: shell.exec
365-
type: test
366-
params:
367-
working_dir: mongo-csharp-driver
368-
shell: "bash"
369-
include_expansions_in_env:
370-
- "FRAMEWORK"
371-
script: |
372-
${PREPARE_SHELL}
373-
bash evergreen/run-unit-tests.sh
374-
375367
run-tests:
376368
- command: shell.exec
377369
type: test
@@ -459,10 +451,6 @@ functions:
459451
params:
460452
shell: "bash"
461453
working_dir: mongo-csharp-driver
462-
include_expansions_in_env:
463-
- "AWS_ACCESS_KEY_ID"
464-
- "AWS_SECRET_ACCESS_KEY"
465-
- "AWS_SESSION_TOKEN"
466454
script: |
467455
. ${DRIVERS_TOOLS}/.evergreen/secrets_handling/setup-secrets.sh drivers/atlas_connect
468456
. evergreen/run-atlas-connectivity-tests.sh
@@ -500,38 +488,9 @@ functions:
500488
script: |
501489
${PREPARE_SHELL}
502490
MONGODB_URI="${MONGODB_URI}" ../../evergreen/run-perf-tests.sh
503-
- command: shell.exec
491+
- command: perf.send
504492
params:
505-
script: |
506-
# We use the requester expansion to determine whether the data is from a mainline evergreen run or not
507-
if [ "${requester}" == "commit" ]; then
508-
is_mainline=true
509-
else
510-
is_mainline=false
511-
fi
512-
513-
# We parse the username out of the order_id as patches append that in and SPS does not need that information
514-
parsed_order_id=$(echo "${revision_order_id}" | awk -F'_' '{print $NF}')
515-
516-
# Submit the performance data to the SPS endpoint
517-
response=$(curl -s -w "\nHTTP_STATUS:%{http_code}" -X 'POST' \
518-
"https://performance-monitoring-api.corp.mongodb.com/raw_perf_results/cedar_report?project=${project_id}&version=${version_id}&variant=${build_variant}&order=$parsed_order_id&task_name=${task_name}&task_id=${task_id}&execution=${execution}&mainline=$is_mainline" \
519-
-H 'accept: application/json' \
520-
-H 'Content-Type: application/json' \
521-
-d @mongo-csharp-driver/benchmarks/MongoDB.Driver.Benchmarks/Benchmark.Artifacts/results/evergreen-results.json)
522-
523-
http_status=$(echo "$response" | grep "HTTP_STATUS" | awk -F':' '{print $2}')
524-
response_body=$(echo "$response" | sed '/HTTP_STATUS/d')
525-
526-
# We want to throw an error if the data was not successfully submitted
527-
if [ "$http_status" -ne 200 ]; then
528-
echo "Error: Received HTTP status $http_status"
529-
echo "Response Body: $response_body"
530-
exit 1
531-
fi
532-
533-
echo "Response Body: $response_body"
534-
echo "HTTP Status: $http_status"
493+
file: mongo-csharp-driver/benchmarks/MongoDB.Driver.Benchmarks/Benchmark.Artifacts/results/evergreen-results.json
535494

536495
assume-ec2-role:
537496
- command: ec2.assume_role
@@ -1055,36 +1014,6 @@ post:
10551014
- func: cleanup
10561015

10571016
tasks:
1058-
- name: unit-tests-net472
1059-
commands:
1060-
- command: expansions.update
1061-
params:
1062-
updates:
1063-
- key: 'FRAMEWORK'
1064-
value: 'net472'
1065-
- func: install-dotnet
1066-
- func: run-unit-tests
1067-
1068-
- name: unit-tests-netstandard21
1069-
commands:
1070-
- command: expansions.update
1071-
params:
1072-
updates:
1073-
- key: 'FRAMEWORK'
1074-
value: 'netstandard2.1'
1075-
- func: install-dotnet
1076-
- func: run-unit-tests
1077-
1078-
- name: unit-tests-net60
1079-
commands:
1080-
- command: expansions.update
1081-
params:
1082-
updates:
1083-
- key: 'FRAMEWORK'
1084-
value: 'net6.0'
1085-
- func: install-dotnet
1086-
- func: run-unit-tests
1087-
10881017
- name: test-net472
10891018
commands:
10901019
- func: setup-csfle-secrets
@@ -1266,7 +1195,6 @@ tasks:
12661195

12671196
- name: atlas-data-lake-test
12681197
commands:
1269-
- func: assume-ec2-role
12701198
- func: bootstrap-mongohoused
12711199
- func: run-atlas-data-lake-test
12721200

@@ -1679,7 +1607,7 @@ tasks:
16791607
- name: generate-release-notes
16801608
commands:
16811609
- func: generate-release-notes
1682-
1610+
16831611
- name: validate-apidocs
16841612
commands:
16851613
- func: install-dotnet
@@ -2052,14 +1980,9 @@ task_groups:
20521980
setup_group:
20531981
- func: fetch-source
20541982
- func: prepare-resources
2055-
- func: assume-ec2-role
20561983
- command: subprocess.exec
20571984
params:
20581985
binary: bash
2059-
include_expansions_in_env:
2060-
- "AWS_ACCESS_KEY_ID"
2061-
- "AWS_SECRET_ACCESS_KEY"
2062-
- "AWS_SESSION_TOKEN"
20631986
env:
20641987
LAMBDA_STACK_NAME: dbx-csharp-lambda
20651988
args:
@@ -2199,10 +2122,6 @@ task_groups:
21992122
binary: bash
22002123
env:
22012124
VAULT_NAME: ${VAULT_NAME}
2202-
include_expansions_in_env:
2203-
- "AWS_ACCESS_KEY_ID"
2204-
- "AWS_SECRET_ACCESS_KEY"
2205-
- "AWS_SESSION_TOKEN"
22062125
args:
22072126
- ${DRIVERS_TOOLS}/.evergreen/serverless/create-instance.sh
22082127
- command: expansions.update
@@ -2243,42 +2162,6 @@ task_groups:
22432162
- validate-apicompat
22442163

22452164
buildvariants:
2246-
- name: unit-tests-windows
2247-
display_name: Unit Tests on Windows
2248-
run_on: windows-64-vs2017-test
2249-
expansions:
2250-
OS: "windows-64"
2251-
tasks:
2252-
- name: unit-tests-net472
2253-
- name: unit-tests-netstandard21
2254-
- name: unit-tests-net60
2255-
2256-
- name: unit-tests-ubuntu
2257-
display_name: Unit Tests on Ubuntu
2258-
run_on: ubuntu2004-small
2259-
expansions:
2260-
OS: "ubuntu-2004"
2261-
tasks:
2262-
- name: unit-tests-netstandard21
2263-
- name: unit-tests-net60
2264-
2265-
- name: unit-tests-macos
2266-
display_name: Unit Tests on MacOs
2267-
run_on: macos-14
2268-
expansions:
2269-
OS: "macos-14"
2270-
tasks:
2271-
- name: unit-tests-netstandard21
2272-
- name: unit-tests-net60
2273-
2274-
- name: unit-tests-macos-arm
2275-
display_name: Unit Tests on MacOs Arm
2276-
run_on: macos-14-arm64
2277-
expansions:
2278-
OS: "macos-14-arm64"
2279-
tasks:
2280-
- name: unit-tests-net60
2281-
22822165
- matrix_name: stable-api-tests
22832166
matrix_spec: { version: ["5.0", "6.0", "7.0", "8.0", "rapid", "latest"], topology: "standalone", auth: "auth", ssl: "nossl", os: "windows-64" }
22842167
display_name: "Stable API ${version} ${topology} ${auth} ${ssl} ${os}"

evergreen/generate-sbom.sh

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env bash
2+
set -o errexit # Exit the script with error if any of the commands fail
3+
4+
# Accommodate Git Bash or MSYS2 on Windows
5+
export MSYS_NO_PATHCONV=1
6+
7+
echo -e "\n************************************************"
8+
9+
# Get Packages Version if variable is empty
10+
if [[ -z "$PACKAGE_VERSION" ]]; then
11+
PACKAGE_VERSION=$(bash ./evergreen/get-version.sh)
12+
fi
13+
14+
echo "Package Version: ${PACKAGE_VERSION}"
15+
16+
# Get array of Package Names
17+
source ./evergreen/packages.sh
18+
echo "Packages: ${PACKAGES[*]}"
19+
20+
# Run a restore that will set the package version in the Directory.Build.props file, otherwise it is set to "0.0.0-local"
21+
# This will also cause the Choose...When conditions in the .csproj files to use PackageReference instead of ProjectReference
22+
echo "Restoring solution with version set to ${PACKAGE_VERSION}"
23+
dotnet restore /p:Version=${PACKAGE_VERSION}
24+
25+
# Install cyclonedx-dotnet using latest version tested with this script
26+
echo "Installing cyclonedx-dotnet"
27+
dotnet tool install --global CycloneDX --version 5.3.1 --allow-downgrade
28+
29+
echo -e "\nGenerating SBOMs"
30+
echo "************************************************"
31+
32+
# Track SBOM file paths for merging
33+
SBOM_FILES=""
34+
35+
for package in ${PACKAGES[*]}; do
36+
echo -e "\n+++++++++++++++++++++++++++++++++++++"
37+
echo "Processing: ${package}"
38+
39+
SBOM_FILE="sbom.${package}.cdx.json"
40+
SBOM_FILES="${SBOM_FILES} /pwd/${SBOM_FILE}"
41+
42+
echo "SBOM file: ${SBOM_FILE}"
43+
44+
# There are nuances to how cyclonedx-dotnet handles <PackageReference> items in Directory.Build.props that lead to private packages being included in SBOM
45+
# results even when PrivateAssets is set to "All". As a safeguard, this command lists the PackageReferences and adds the references with PrivateAssets="All"
46+
# to an exclusion filter variable to be fed into cyclonedx-dotnet
47+
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(",")')
48+
echo "Excluded Private Package References: ${EXCLUDE_FILTER}"
49+
50+
# The ProjectReference items do not resolve as the Nuget packages they represent. This causes duplicate components when the SBOMs are merged. To address this
51+
# we add the Nuget PURL to the JSON. This command lists the ProjectReferences for processing.
52+
PURL_PATCHES=$(dotnet msbuild ./src/${package}/${package}.csproj -getItem:ProjectReference | jq -r '[.Items.ProjectReference[] | .Filename] | join(",")')
53+
echo "Project References requiring added PURL: ${PURL_PATCHES}"
54+
55+
echo "+++++++++++++++++++++++++++++++++++++"
56+
57+
## Run cyclonedx-dotnet
58+
# Attempt GitHub license resolution only if GITHUB_USER and GITHUB_APIKEY are both set
59+
if [[ -v GITHUB_USER && -v GITHUB_APIKEY ]]; then
60+
github_options=(--enable-github-licenses --github-username ${GITHUB_USER} --github-token ${GITHUB_APIKEY})
61+
fi
62+
63+
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[@]}"
64+
dotnet-CycloneDX src/${package}/${package}.csproj \
65+
--disable-package-restore --set-type library --set-nuget-purl --exclude-dev --include-project-references \
66+
--set-name ${package} --set-version ${PACKAGE_VERSION} --filename ${SBOM_FILE} \
67+
--exclude-filter "${EXCLUDE_FILTER}" \
68+
"${github_options[@]}"
69+
70+
# Patch JSON file with PURLs, as needed
71+
for patch in $PURL_PATCHES; do
72+
echo "Patching ${patch} with Nuget PURL"
73+
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})
74+
echo -E "${contents}" >${SBOM_FILE}
75+
done
76+
77+
done
78+
79+
echo -e "\n================================="
80+
echo "Merging SBOMs using cyclonedx-cli"
81+
echo "================================="
82+
83+
# Use cyclonedx-cli to merge the SBOMs into 1 hierarchical SBOM
84+
docker run --platform="linux/amd64" --rm -v ${PWD}:/pwd \
85+
cyclonedx/cyclonedx-cli:0.28.2 \
86+
merge --input-files ${SBOM_FILES} --output-file /pwd/sbom.cdx.json \
87+
--hierarchical --group mongodb --name mongo-csharp-driver --version ${PACKAGE_VERSION}

0 commit comments

Comments
 (0)