Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a0af51a
GODRIVER-3599 Add task script to generate CycloneDX SBOM
jasonhills-mongodb Aug 4, 2025
4e52215
Update .evergreen/config.yml
jasonhills-mongodb Aug 14, 2025
10dd0cc
Merge branch 'master' into GODRIVER-3599/sbom_generation_using_cyclon…
matthewdale Dec 5, 2025
8d5d80f
Use correct file for pre-commit and correct comment in Taskfile.
matthewdale Dec 5, 2025
3aa5972
Add updated SBOM file.
matthewdale Dec 5, 2025
000be14
Merge branch 'master' into GODRIVER-3599/sbom_generation_using_cyclon…
jasonhills-mongodb Jun 9, 2026
be7bf18
Apply yamlfmt formatting
jasonhills-mongodb Jun 9, 2026
332ea9d
Add libmongocrypt as optional component to SBOM
jasonhills-mongodb Jun 9, 2026
248537c
Address code review feedback on generate-sbom.sh and sbom workflow
jasonhills-mongodb Jun 10, 2026
ec3acc8
Improve SBOM generation and address Copilot review feedback
jasonhills-mongodb Jun 10, 2026
717200d
Strip .version from workflow SBOM diff
jasonhills-mongodb Jun 10, 2026
c9c732b
Add go.sum to SBOM workflow paths trigger
jasonhills-mongodb Jun 10, 2026
dc9a947
Add etc/install-libmongocrypt.sh to SBOM workflow paths trigger
jasonhills-mongodb Jun 10, 2026
e8daade
Improve SBOM PR description and add SBOM section to CONTRIBUTING.md
jasonhills-mongodb Jun 10, 2026
2079344
Merge remote-tracking branch 'upstream/master' into GODRIVER-3599/sbo…
jasonhills-mongodb Jun 10, 2026
556bd8e
GODRIVER-3599: Normalize SBOM main component version to latest releas…
jasonhills-mongodb Jun 10, 2026
6153ece
Revert "GODRIVER-3599: Normalize SBOM main component version to lates…
jasonhills-mongodb Jun 10, 2026
7ac2edf
Merge branch 'master' into GODRIVER-3599/sbom_generation_using_cyclon…
jasonhills-mongodb Jun 15, 2026
e1810f1
Merge branch 'master' into GODRIVER-3599/sbom_generation_using_cyclon…
jasonhills-mongodb Jun 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,83 @@ tasks:
params:
binary: bash
args: [*task-runner, govulncheck]
- name: upload-sbom
tags: ["ssdlc"]
Comment thread
jasonhills-mongodb marked this conversation as resolved.
allowed_requesters: ["commit"]
exec_timeout_secs: 600
commands:
- func: setup-system
- command: expansions.update
params:
updates:
- {key: DOCKER_CONFIG, value: "${workdir}/.docker"}
- command: ec2.assume_role
display_name: Assume ECR readonly IAM role
params:
role_arn: arn:aws:iam::901841024863:role/ecr-role-evergreen-ro
- command: subprocess.exec
type: setup
display_name: Log in to ECR
params:
binary: bash
include_expansions_in_env:
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_SESSION_TOKEN
- DOCKER_CONFIG
args:
- -c
- aws ecr get-login-password --region us-east-1 | podman login --username AWS --password-stdin 901841024863.dkr.ecr.us-east-1.amazonaws.com
- command: ec2.assume_role
display_name: Assume Silkbomb IAM role
params:
role_arn: arn:aws:iam::901841024863:role/silkbomb
- command: subprocess.exec
type: test
display_name: Upload SBOM via Silkbomb
params:
binary: bash
working_dir: src/go.mongodb.org/mongo-driver
include_expansions_in_env:
- branch_name
- DOCKER_CONFIG
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
Comment thread
jasonhills-mongodb marked this conversation as resolved.
args:
- etc/sbom.sh
- command: s3.put
type: system
params:
display_name: Augmented SBOM (Old)
aws_key: ${aws_key}
aws_secret: ${aws_secret}
bucket: mciuploads
content_type: application/json
local_file: src/go.mongodb.org/mongo-driver/old.json
permissions: public-read
remote_file: mongo-go-driver/${build_variant}/${revision}/${version_id}/${build_id}/sbom/old.json
- command: s3.put
type: system
params:
display_name: Augmented SBOM (New)
aws_key: ${aws_key}
aws_secret: ${aws_secret}
bucket: mciuploads
content_type: application/json
local_file: src/go.mongodb.org/mongo-driver/new.json
permissions: public-read
remote_file: mongo-go-driver/${build_variant}/${revision}/${version_id}/${build_id}/sbom/new.json
- command: s3.put
type: system
params:
display_name: Augmented SBOM (Diff)
aws_key: ${aws_key}
aws_secret: ${aws_secret}
bucket: mciuploads
content_type: application/json
local_file: src/go.mongodb.org/mongo-driver/diff.txt
permissions: public-read
remote_file: mongo-go-driver/${build_variant}/${revision}/${version_id}/${build_id}/sbom/diff.txt
- name: pull-request-helpers
allowed_requesters: ["patch", "github_pr"]
commands:
Expand Down Expand Up @@ -2100,3 +2177,13 @@ buildvariants:
- name: testazureoidc_task_group
- name: testgcpoidc_task_group
- name: testk8soidc_task_group
- name: sbom
display_name: "SBOM"
allowed_requesters: ["commit"]
stepback: false
paths:
- sbom.json
run_on:
- rhel8.7-small
tasks:
- name: upload-sbom
66 changes: 66 additions & 0 deletions .github/workflows/sbom.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Generate SBOM
# Generates sbom.json using cyclonedx-gomod and opens a PR if it has changed.
# Triggered when go.mod changes on master, or manually.
# Internal documentation: go/sbom-scope
on:
workflow_dispatch: {}
push:
branches:
- master
paths:
- go.mod
permissions:
contents: write
pull-requests: write
jobs:
sbom:
name: Generate SBOM and Create PR
runs-on: ubuntu-latest
concurrency:
group: sbom-${{ github.ref }}
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Stash existing SBOM
run: |
# Strip nondeterministic fields before diffing
jq 'del(.metadata.timestamp, .version)' sbom.json > ${{ runner.temp }}/sbom.existing.json
Comment thread
jasonhills-mongodb marked this conversation as resolved.
- name: Generate SBOM
run: bash etc/generate-sbom.sh
- name: Download CycloneDX CLI
run: |
curl -L -s -o ${{ runner.temp }}/cyclonedx \
"https://github.com/CycloneDX/cyclonedx-cli/releases/download/v0.32.0/cyclonedx-linux-x64"
echo "454879e6a4a405c8a13bff49b8982adcb0596f3019b26b0811c66e4d7f0783e1 ${{ runner.temp }}/cyclonedx" | sha256sum --check
chmod +x ${{ runner.temp }}/cyclonedx
- name: Validate SBOM
run: ${{ runner.temp }}/cyclonedx validate --input-file sbom.json --fail-on-errors
- name: Check for SBOM changes
id: sbom_diff
run: |
jq 'del(.metadata.timestamp, .version)' sbom.json > ${{ runner.temp }}/sbom.generated.json
RESULT=$(diff --brief ${{ runner.temp }}/sbom.existing.json ${{ runner.temp }}/sbom.generated.json || true)
Comment thread
jasonhills-mongodb marked this conversation as resolved.
echo "result=$RESULT" | tee -a $GITHUB_OUTPUT
- name: Open Pull Request if SBOM has changed
if: steps.sbom_diff.outputs.result
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
add-paths: sbom.json
branch: auto-update-sbom-${{ github.ref_name }}
commit-message: "chore: Update SBOM after dependency changes"
delete-branch: true
labels: sbom
title: "Automation: Update SBOM [${{ github.ref_name }}]"
body: |
## Automated SBOM Update

This PR was automatically generated because `go.mod` changed.

### Triggered by
- Commit: ${{ github.sha }}
- Workflow run: [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
10 changes: 10 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ tasks:
- GOOS=linux GOARCH=ppc64le etc/golangci-lint.sh
- GOOS=linux GOARCH=s390x etc/golangci-lint.sh
govulncheck: bash etc/govulncheck.sh
generate-sbom:
desc: Generate a CycloneDX SBOM
summary: |
Generate a CycloneDX SBOM with the cyclonedx-gomod 'mod' subcommand
The SBOM includes the aggregate of modules required by packages in the mongo-go-driver library, excluding examples, tests and test packages.
Task will run only when go.mod is newer than sbom.json.
method: timestamp
sources: [go.mod]
generates: [sbom.json]
cmd: bash etc/generate-sbom.sh
Comment thread
jasonhills-mongodb marked this conversation as resolved.
update-notices: bash etc/generate_notices.pl > THIRD-PARTY-NOTICES
### Local testing tasks. ###
test: go test ${BUILD_TAGS} -timeout {{.TEST_TIMEOUT}}s -p 1 ./...
Expand Down
59 changes: 59 additions & 0 deletions etc/generate-sbom.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bash

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[blocking] CycloneDX notes that you can use as a library ( > v1.2.0). We should opt for this to avoid a CLI dependency in local dev and VM CI and convert etc/generate-sbom.sh to a go script at internal/cmd/generate-sbom/. Despite being more LoC, it's easier for the team to read, update, and bump.

Here is a gist: https://gist.github.com/prestonvasquez/04a194f2f0aff1ba010754e5e9057eb5

Typically, we would defer this work to a followup ticket, but I'm concerned that we could easily miss something with a de facto re-write. Let me know if this would work better if we wrote the Go code and you reviewed for correctness.

set -e
Comment thread
jasonhills-mongodb marked this conversation as resolved.
Outdated

CHECK_CURRENCY="false"

# Options are:
# -c : check currency of staged sbom.json versus go.mod.
while getopts "c" opt; do
case $opt in
c)
CHECK_CURRENCY="true"
;;
*)
echo "usage: $0 [-c]" >&2
echo " -c : (optional) check currency of staged sbom.json versus go.mod." >&2
exit 1
;;
esac
done
#shift $((OPTIND - 1))

if ! $CHECK_CURRENCY; then
Comment thread
jasonhills-mongodb marked this conversation as resolved.
Outdated
# The cyclonedx-gomod 'mod' subcommand is used to generate a CycloneDX SBOM with GOWORK=off to exclude example/test code.

## The pipe to jq is a temporary workaround until this issue is resolved: https://github.com/CycloneDX/cyclonedx-gomod/issues/662.
## When resolved, bump version and replace with commented line below.
# GOWORK=off go run github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@[UPDATED VERSION] mod -type library -licenses -assert-licenses -output-version 1.5 -json -output sbom.json .
GOWORK=off go run github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@v1.10.0 mod -type library -licenses -assert-licenses -output-version 1.5 -json . | jq '.metadata.component.purl |= split("?")[0]' | jq '.components[].purl |= split("?")[0]' > sbom.json

# Derive the libmongocrypt version from the install script and inject it as an optional component.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIBMONGOCRYPT_VERSION=$(grep 'LIBMONGOCRYPT_TAG=' "${SCRIPT_DIR}/install-libmongocrypt.sh" | head -1 | cut -d'"' -f2)
LIBMONGOCRYPT_PURL="pkg:github/mongodb/libmongocrypt@${LIBMONGOCRYPT_VERSION}"

jq --arg version "$LIBMONGOCRYPT_VERSION" --arg purl "$LIBMONGOCRYPT_PURL" '
.metadata.component."bom-ref" as $main_ref |
.components += [{
"type": "library",
"bom-ref": $purl,
"supplier": {"name": "MongoDB, Inc.", "url": ["https://mongodb.com"]},
"author": "MongoDB, Inc.",
"group": "mongodb",
"name": "libmongocrypt",
"version": $version,
"description": "Required C library for Client Side and Queryable Encryption in MongoDB",
"scope": "optional",
"licenses": [{"license": {"id": "Apache-2.0"}}],
"copyright": "Copyright 2019-present MongoDB, Inc.",
"cpe": ("cpe:2.3:a:mongodb:libmongocrypt:" + $version + ":*:*:*:*:*:*:*"),
"purl": $purl,
"externalReferences": [{"url": "https://github.com/mongodb/libmongocrypt.git", "type": "distribution"}]
}] |
(.dependencies[] | select(.ref == $main_ref) | .dependsOn) += [$purl] |
.dependencies += [{"ref": $purl, "dependsOn": []}]
' sbom.json > sbom.tmp.json && mv sbom.tmp.json sbom.json

elif [[ $(git diff --name-only --cached go.mod) && ! $(git diff --name-only --cached sbom.json) ]]; then
echo "'go.mod' has changed. 'sbom.json' must be re-generated (run 'task generate-sbom' or 'etc/generate-sbom.sh') and staged." && exit 1
Comment thread
jasonhills-mongodb marked this conversation as resolved.
Outdated
fi
57 changes: 57 additions & 0 deletions etc/sbom.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[blocking] Same with generate-sbom.sh, this could be a Go script that leverages the docker API. Here is a gist: https://gist.github.com/prestonvasquez/7d83b6bd919fbcb133bcbcc053e4a2ed


set -o errexit
set -o pipefail

: "${branch_name:?}"
: "${DOCKER_CONFIG:?}"
: "${AWS_ACCESS_KEY_ID:?}"
: "${AWS_SECRET_ACCESS_KEY:?}"
Comment thread
jasonhills-mongodb marked this conversation as resolved.

command -v podman >/dev/null || {
echo "missing required program podman" 1>&2
exit 1
}

command -v jq >/dev/null || {
echo "missing required program jq" 1>&2
exit 1
}

silkbomb="901841024863.dkr.ecr.us-east-1.amazonaws.com/release-infrastructure/silkbomb:2.0"

podman pull "${silkbomb:?}"
Comment thread
jasonhills-mongodb marked this conversation as resolved.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[blocking] Is there a reason we use podman over docker? Docker is preferred by the team. If it needs to be agnostic, we should make this an env variable. E.g.


silkbomb_augment_flags=(
--repo mongodb/mongo-go-driver
--branch "${branch_name:?}"
--sbom-in /pwd/sbom.json
--sbom-out /pwd/augmented.sbom.json.new

# Any notable updates to the Augmented SBOM version should be done manually after careful inspection.
# Otherwise, it should be equal to the existing SBOM version.
--no-update-sbom-version
)

podman run -it --rm -v "$(pwd):/pwd" --env 'AWS_ACCESS_KEY_ID' --env 'AWS_SECRET_ACCESS_KEY' \
Comment thread
jasonhills-mongodb marked this conversation as resolved.
Outdated
Comment thread
jasonhills-mongodb marked this conversation as resolved.
Outdated
"${silkbomb:?}" augment "${silkbomb_augment_flags[@]:?}"

[[ -f ./augmented.sbom.json.new ]] || {
echo "failed to download Augmented SBOM" 1>&2
exit 1
}

echo "Comparing Augmented SBOM..."

jq -S 'del(.metadata.timestamp)' ./augmented.sbom.json >|old.json
jq -S 'del(.metadata.timestamp)' ./augmented.sbom.json.new >|new.json

if ! diff -sty --left-column -W 200 old.json new.json >|diff.txt; then
Comment thread
jasonhills-mongodb marked this conversation as resolved.
declare status
status='{"status":"failed", "type":"test", "should_continue":true, "desc":"detected significant changes in Augmented SBOM"}'
curl -sS -d "${status:?}" -H "Content-Type: application/json" -X POST localhost:2285/task_status || true
fi

cat diff.txt

echo "Comparing Augmented SBOM... done."
Loading
Loading