Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
88 changes: 88 additions & 0 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,84 @@ tasks:
params:
binary: bash
args: [*task-runner, govulncheck]
- name: upload-sbom
tags: ["ssdlc"]
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.
- AWS_SESSION_TOKEN
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 +2178,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
76 changes: 76 additions & 0 deletions .github/workflows/sbom.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
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
- go.sum
- etc/install-libmongocrypt.sh
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
- name: Generate SBOM
run: bash etc/generate-sbom.sh
- name: Download CycloneDX CLI
run: |
curl -fsSL -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)
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 a change to `go.mod`, `go.sum`, or
`etc/install-libmongocrypt.sh` was merged into `${{ github.ref_name }}`.

`sbom.json` has been regenerated to reflect the current module dependency graph
and `libmongocrypt` version. The SBOM serial number is stable; the `.version`
field has been incremented to reflect this update.

Once merged, an Evergreen CI task will upload the updated SBOM to the internal
tracking system.

### 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, go.sum, etc/install-libmongocrypt.sh]
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
12 changes: 12 additions & 0 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,18 @@ using enterprise auth, run:
TOPOLOGY=sharded_cluster task run-docker -- evg-test-enterprise-auth
```

## Software Bill of Materials (SBOM)

The repository maintains a CycloneDX SBOM at `sbom.json` in the repository root. It captures the full module dependency graph along with `libmongocrypt` as an optional component.

**You do not need to update `sbom.json` manually.** When a pull request that changes `go.mod`, `go.sum`, or `etc/install-libmongocrypt.sh` is merged into `master`, the "Generate SBOM" GitHub Actions workflow will automatically regenerate `sbom.json` and open a follow-up pull request with the updated file. Simply review and merge that PR.

To regenerate the SBOM locally (e.g. to preview changes), run:

```bash
task generate-sbom
```

## Talk To Us

If you want to work on the driver, write documentation, or have questions/complaints, please reach out to us either via [MongoDB Community Forums](https://www.mongodb.com/community/forums/tag/go-driver) or by creating a Question issue in [Jira](https://jira.mongodb.org/secure/CreateIssue!default.jspa).
52 changes: 52 additions & 0 deletions etc/generate-sbom.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/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 -eo pipefail

SERIAL_NUMBER="urn:uuid:b7adcdf8-bafc-43c5-a529-a73130697171"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Generate the base SBOM. -short-purls strips ?type=module query strings from PURLs,
# resolving https://github.com/CycloneDX/cyclonedx-gomod/issues/662.
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 \
-serial "$SERIAL_NUMBER" -std=true -short-purls=true . > sbom.tmp.json

# Inject libmongocrypt as an optional component.
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.tmp.json > sbom.new.json
rm sbom.tmp.json

# Increment .version only when meaningful content has changed.
CURRENT_VERSION=$(jq -r '.version // 0' sbom.json 2>/dev/null || echo 0)
NEW_CONTENT=$(jq -S 'del(.version, .metadata.timestamp)' sbom.new.json)
OLD_CONTENT=$(jq -S 'del(.version, .metadata.timestamp)' sbom.json 2>/dev/null || echo '{}')

if [ "$NEW_CONTENT" = "$OLD_CONTENT" ]; then
NEW_VERSION=$CURRENT_VERSION
else
NEW_VERSION=$((CURRENT_VERSION + 1))
fi

jq --argjson v "$NEW_VERSION" '.version = $v' sbom.new.json > sbom.json
rm sbom.new.json
59 changes: 59 additions & 0 deletions etc/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] 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.
: "${AWS_SESSION_TOKEN:?}"

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 --rm -v "$(pwd):/pwd" \
--env 'AWS_ACCESS_KEY_ID' --env 'AWS_SECRET_ACCESS_KEY' --env 'AWS_SESSION_TOKEN' \
"${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