From 9f57d681f27d0d4abe39476e1837a1acc36df10d Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Fri, 21 Nov 2025 17:03:13 +0000 Subject: [PATCH 1/9] Add workflow to generate SBOM and create PR on dependency changes --- .github/workflows/sbom.yml | 88 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 .github/workflows/sbom.yml diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml new file mode 100644 index 000000000..a80ccf380 --- /dev/null +++ b/.github/workflows/sbom.yml @@ -0,0 +1,88 @@ +name: Generate SBOM + +# This workflow uses cdxgen and publishes an sbom.json artifact. +# It runs on manual trigger or when package files change on main branch, +# and creates a PR with the updated SBOM. +# Internal documentation: go/sbom-scope + +on: + workflow_dispatch: {} + push: + branches: ['master'] + paths: + - 'pyproject.toml' + - 'requirements.txt' + +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 + with: + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Generate SBOM + run: | + python -m venv .venv + source .venv/bin/activate + pip install -r requirements.txt + pip install . + npx @cyclonedx/cdxgen -t python --json-pretty -o sbom.json + env: + FETCH_LICENSE: true + + - name: Upload SBOM artifact + uses: actions/upload-artifact@v4 + with: + name: sbom + path: sbom.json + if-no-files-found: error + + - name: Create Pull Request + uses: peter-evans/create-pull-request@b4733b9419fd47bbfa1807b15627e17cd70b5b22 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: 'chore: Update SBOM after dependency changes' + branch: auto-update-sbom-${{ github.run_id }} + delete-branch: true + title: 'chore: Update SBOM' + body: | + ## Automated SBOM Update + + This PR was automatically generated because dependency manifest files changed. + + ### Changes + - Updated `sbom.json` to reflect current dependencies + + ### Verification + The SBOM was generated using cdxgen with the current Python environment. + + ### Triggered by + - Commit: ${{ github.sha }} + - Workflow run: ${{ github.run_id }} + + --- + _This PR was created automatically by the [SBOM workflow](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})_ + labels: | + sbom + automated + dependencies + + - name: Cleanup + if: always() + run: rm -rf .venv From 56db3e508890f43b186e1a407af38f320ede05be Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Fri, 21 Nov 2025 17:04:26 +0000 Subject: [PATCH 2/9] updated to main --- .github/workflows/sbom.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index a80ccf380..59b5e5f45 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -8,7 +8,7 @@ name: Generate SBOM on: workflow_dispatch: {} push: - branches: ['master'] + branches: ['main'] paths: - 'pyproject.toml' - 'requirements.txt' From d171d2ed6ef53cf7e60d5920bf1688bcc14cf685 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Fri, 21 Nov 2025 23:04:18 +0000 Subject: [PATCH 3/9] changed param cdx spec to 1.5 --- .github/workflows/sbom.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 59b5e5f45..f7ece2d50 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -42,7 +42,8 @@ jobs: source .venv/bin/activate pip install -r requirements.txt pip install . - npx @cyclonedx/cdxgen -t python --json-pretty -o sbom.json + npx @cyclonedx/cdxgen@11.0.0 -t python --spec-version 1.5 -o sbom.json + jq . sbom.json > sbom.json.tmp && mv sbom.json.tmp sbom.json env: FETCH_LICENSE: true From 0c36d554cf21583134812035aeeca80b3c150c5a Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Mon, 24 Nov 2025 16:12:00 +0000 Subject: [PATCH 4/9] Updated to use cyclonedx-python --- .github/workflows/sbom.yml | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index f7ece2d50..c6b228057 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -1,6 +1,6 @@ name: Generate SBOM -# This workflow uses cdxgen and publishes an sbom.json artifact. +# This workflow uses cyclonedx-py and publishes an sbom.json artifact. # It runs on manual trigger or when package files change on main branch, # and creates a PR with the updated SBOM. # Internal documentation: go/sbom-scope @@ -42,10 +42,26 @@ jobs: source .venv/bin/activate pip install -r requirements.txt pip install . - npx @cyclonedx/cdxgen@11.0.0 -t python --spec-version 1.5 -o sbom.json - jq . sbom.json > sbom.json.tmp && mv sbom.json.tmp sbom.json - env: - FETCH_LICENSE: true + pip uninstall -y pip setuptools + deactivate + python -m venv .venv-sbom + source .venv-sbom/bin/activate + pip install cyclonedx-bom==7.2.1 + cyclonedx-py environment --spec-version 1.5 --output-format JSON --output-file sbom.json .venv + # Add PURL for django-mongodb-backend (local package doesn't get PURL automatically) + jq '(.components[] | select(.name == "django-mongodb-backend" and .purl == null)) |= (. + {purl: ("pkg:pypi/django-mongodb-backend@" + .version)})' sbom.json > sbom.tmp.json && mv sbom.tmp.json sbom.json + + - name: Download CycloneDX CLI + run: | + curl -L -s -o /tmp/cyclonedx "https://github.com/CycloneDX/cyclonedx-cli/releases/download/v0.29.1/cyclonedx-linux-x64" + chmod +x /tmp/cyclonedx + + - name: Validate SBOM + run: /tmp/cyclonedx validate --input-file sbom.json --fail-on-errors + + - name: Cleanup + if: always() + run: rm -rf .venv .venv-sbom - name: Upload SBOM artifact uses: actions/upload-artifact@v4 @@ -71,7 +87,7 @@ jobs: - Updated `sbom.json` to reflect current dependencies ### Verification - The SBOM was generated using cdxgen with the current Python environment. + The SBOM was generated using cyclonedx-py v7.2.1 with the current Python environment. ### Triggered by - Commit: ${{ github.sha }} @@ -82,8 +98,4 @@ jobs: labels: | sbom automated - dependencies - - - name: Cleanup - if: always() - run: rm -rf .venv + dependencies \ No newline at end of file From 3ead9990b64cb6ab82285d13997ec03463db80a3 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Mon, 24 Nov 2025 16:14:10 +0000 Subject: [PATCH 5/9] linter fix --- .github/workflows/sbom.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index c6b228057..a2c6120f5 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -98,4 +98,4 @@ jobs: labels: | sbom automated - dependencies \ No newline at end of file + dependencies From 5e9c29eaece4edbadba73b85aee16a9c42ebf8c1 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Wed, 3 Dec 2025 18:39:38 +0000 Subject: [PATCH 6/9] Update actions to use latest versions and linting --- .github/workflows/sbom.yml | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index a2c6120f5..c9092b420 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -27,15 +27,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false - - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.10" - - name: Generate SBOM run: | python -m venv .venv @@ -50,34 +48,29 @@ jobs: cyclonedx-py environment --spec-version 1.5 --output-format JSON --output-file sbom.json .venv # Add PURL for django-mongodb-backend (local package doesn't get PURL automatically) jq '(.components[] | select(.name == "django-mongodb-backend" and .purl == null)) |= (. + {purl: ("pkg:pypi/django-mongodb-backend@" + .version)})' sbom.json > sbom.tmp.json && mv sbom.tmp.json sbom.json - - name: Download CycloneDX CLI run: | curl -L -s -o /tmp/cyclonedx "https://github.com/CycloneDX/cyclonedx-cli/releases/download/v0.29.1/cyclonedx-linux-x64" chmod +x /tmp/cyclonedx - - name: Validate SBOM run: /tmp/cyclonedx validate --input-file sbom.json --fail-on-errors - - name: Cleanup if: always() run: rm -rf .venv .venv-sbom - - name: Upload SBOM artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: sbom path: sbom.json if-no-files-found: error - - name: Create Pull Request - uses: peter-evans/create-pull-request@b4733b9419fd47bbfa1807b15627e17cd70b5b22 + uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GITHUB_TOKEN }} - commit-message: 'chore: Update SBOM after dependency changes' + commit-message: 'Update SBOM after dependency changes' branch: auto-update-sbom-${{ github.run_id }} delete-branch: true - title: 'chore: Update SBOM' + title: 'Update SBOM' body: | ## Automated SBOM Update @@ -87,7 +80,7 @@ jobs: - Updated `sbom.json` to reflect current dependencies ### Verification - The SBOM was generated using cyclonedx-py v7.2.1 with the current Python environment. + The SBOM was generated using cyclonedx-py with the current Python environment. ### Triggered by - Commit: ${{ github.sha }} From 4c17faf242f7a4de50da4ecef2f3e9bea79fc2e7 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Wed, 3 Dec 2025 18:43:04 +0000 Subject: [PATCH 7/9] version pinned --- .github/workflows/sbom.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index c9092b420..50a90d70a 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -64,7 +64,7 @@ jobs: path: sbom.json if-no-files-found: error - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 + uses: peter-evans/create-pull-request@b4733b9419fd47bbfa1807b15627e17cd70b5b22 # v7.0.9 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: 'Update SBOM after dependency changes' From f36203fc6c4e41e96dee62fb01e421183ef094b7 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Wed, 3 Dec 2025 18:47:08 +0000 Subject: [PATCH 8/9] update hash --- .github/workflows/sbom.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 50a90d70a..0afffdf27 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -64,7 +64,7 @@ jobs: path: sbom.json if-no-files-found: error - name: Create Pull Request - uses: peter-evans/create-pull-request@b4733b9419fd47bbfa1807b15627e17cd70b5b22 # v7.0.9 + uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7.0.9 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: 'Update SBOM after dependency changes' From 67deeee5274cbbc6bfbd680982a5bbc62791356f Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Fri, 5 Dec 2025 15:33:58 +0000 Subject: [PATCH 9/9] Add check for changes before adding file to push for PR & change python to latest version --- .github/workflows/sbom.yml | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 0afffdf27..19ca3b916 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -33,7 +33,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 with: - python-version: "3.10" + python-version: "3.x" - name: Generate SBOM run: | python -m venv .venv @@ -45,15 +45,38 @@ jobs: python -m venv .venv-sbom source .venv-sbom/bin/activate pip install cyclonedx-bom==7.2.1 - cyclonedx-py environment --spec-version 1.5 --output-format JSON --output-file sbom.json .venv + cyclonedx-py environment --spec-version 1.5 --output-format JSON --output-file sbom-new.json .venv # Add PURL for django-mongodb-backend (local package doesn't get PURL automatically) - jq '(.components[] | select(.name == "django-mongodb-backend" and .purl == null)) |= (. + {purl: ("pkg:pypi/django-mongodb-backend@" + .version)})' sbom.json > sbom.tmp.json && mv sbom.tmp.json sbom.json + jq '(.components[] | select(.name == "django-mongodb-backend" and .purl == null)) |= (. + {purl: ("pkg:pypi/django-mongodb-backend@" + .version)})' sbom-new.json > sbom.tmp.json && mv sbom.tmp.json sbom-new.json - name: Download CycloneDX CLI run: | curl -L -s -o /tmp/cyclonedx "https://github.com/CycloneDX/cyclonedx-cli/releases/download/v0.29.1/cyclonedx-linux-x64" chmod +x /tmp/cyclonedx - name: Validate SBOM - run: /tmp/cyclonedx validate --input-file sbom.json --fail-on-errors + run: /tmp/cyclonedx validate --input-file sbom-new.json --fail-on-errors + - name: Check for changes + id: check_changes + run: | + if [ -f sbom.json ]; then + echo "Comparing new SBOM with existing sbom.json..." + # Use cyclonedx diff to check for component changes + DIFF_OUTPUT=$(/tmp/cyclonedx diff sbom.json sbom-new.json --component-versions) + + # Check if there are meaningful changes (output contains more than just "None") + if echo "$DIFF_OUTPUT" | grep -q "^None$"; then + echo "No component changes detected (only metadata differs)" + echo "Keeping existing sbom.json" + rm sbom-new.json + else + echo "Component changes detected:" + echo "$DIFF_OUTPUT" + echo "Updating sbom.json" + mv sbom-new.json sbom.json + fi + else + echo "No existing sbom.json found, creating initial version" + mv sbom-new.json sbom.json + fi - name: Cleanup if: always() run: rm -rf .venv .venv-sbom