From 91aea4d53562b36b99e63e096b501afe69a558a5 Mon Sep 17 00:00:00 2001 From: Borislav Traykov Date: Mon, 3 Aug 2026 10:11:52 +0300 Subject: [PATCH 1/4] SBOM generation - initial implementation --- .github/workflows/sbom.yml | 77 +++++++++++++++++++ .../IgniteUI.Blazor.GridLite.csproj | 5 ++ 2 files changed, 82 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 0000000..77ea203 --- /dev/null +++ b/.github/workflows/sbom.yml @@ -0,0 +1,77 @@ +name: Generate SBOM + +# Runs only when the 'generate sbom' label is added to a PR. +on: + pull_request: + types: [labeled] + +permissions: + contents: read + +concurrency: + group: sbom-${{ github.event.pull_request.number }} + cancel-in-progress: true + +env: + BUILD_CONFIGURATION: Release + PACKAGE_VERSION: 0.0.0-pr.${{ github.event.pull_request.number }} + +jobs: + sbom: + if: github.event.label.name == 'generate sbom' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v7 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: "10.0.x" + + - uses: actions/setup-node@v6.4.0 + with: + node-version: '22' + + - run: npm ci + working-directory: src/IgniteUI.Blazor.GridLite + + - run: npm run build + working-directory: src/IgniteUI.Blazor.GridLite + + # GenerateSBOM=true pulls in Microsoft.Sbom.Targets (conditional PackageReference) + # and embeds _manifest/spdx_2.2 into the nupkg after Pack. + - name: Pack with SBOM + run: > + dotnet pack src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj + --configuration ${{ env.BUILD_CONFIGURATION }} + -p:RunNodeBuild=false + -p:GeneratePackageOnBuild=false + -p:GenerateSBOM=true + -p:Version=${{ env.PACKAGE_VERSION }} + -o ./artifacts + + - name: Extract and verify SBOM + run: | + set -euo pipefail + nupkg=(artifacts/*.nupkg) + unzip -q "${nupkg[0]}" "_manifest/*" -d extracted + test -s extracted/_manifest/spdx_2.2/manifest.spdx.json + test -s extracted/_manifest/spdx_2.2/manifest.spdx.json.sha256 + echo "SBOM verified in ${nupkg[0]}" + + - name: Upload NuGet package (with embedded SBOM) + uses: actions/upload-artifact@v7 + with: + name: nupkg-with-sbom + path: artifacts/*.nupkg + retention-days: 1 + if-no-files-found: error + + - name: Upload SBOM files + uses: actions/upload-artifact@v7 + with: + name: sbom-spdx_2.2 + path: extracted/_manifest/spdx_2.2 + retention-days: 1 + if-no-files-found: error diff --git a/src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj b/src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj index f91c101..b6bf022 100644 --- a/src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj +++ b/src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj @@ -53,6 +53,11 @@ + + + + + From c3de9438a5c27cc752486a0a412d9be147ed468b Mon Sep 17 00:00:00 2001 From: Borislav Traykov Date: Mon, 3 Aug 2026 12:42:57 +0300 Subject: [PATCH 2/4] use the sbom-tool as a dotnet tool instead --- .config/sbom-tool/dotnet-tools.json | 13 ++++ .github/workflows/sbom.yml | 75 ++++++++++++++----- .../IgniteUI.Blazor.GridLite.csproj | 5 -- 3 files changed, 71 insertions(+), 22 deletions(-) create mode 100644 .config/sbom-tool/dotnet-tools.json diff --git a/.config/sbom-tool/dotnet-tools.json b/.config/sbom-tool/dotnet-tools.json new file mode 100644 index 0000000..eabcff8 --- /dev/null +++ b/.config/sbom-tool/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "microsoft.sbom.dotnettool": { + "version": "4.1.5", + "commands": [ + "sbom-tool" + ], + "rollForward": true + } + } +} diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 77ea203..631c713 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -1,24 +1,28 @@ name: Generate SBOM -# Runs only when the 'generate sbom' label is added to a PR. +# Runs when the 'generate sbom' label is added to a PR, or when a release is published. +# Uses the sbom-tool CLI (version pinned in .config/sbom-tool/dotnet-tools.json) +# so the NuGet package is never modified and no SBOM is embedded in it. on: pull_request: types: [labeled] + release: + types: [published] permissions: contents: read concurrency: - group: sbom-${{ github.event.pull_request.number }} + group: sbom-${{ github.event_name == 'release' && github.ref_name || github.event.pull_request.number }} cancel-in-progress: true env: BUILD_CONFIGURATION: Release - PACKAGE_VERSION: 0.0.0-pr.${{ github.event.pull_request.number }} + PACKAGE_VERSION: ${{ github.event_name == 'release' && github.ref_name || format('0.0.0-pr.{0}', github.event.pull_request.number) }} jobs: sbom: - if: github.event.label.name == 'generate sbom' + if: github.event_name == 'release' || github.event.label.name == 'generate sbom' runs-on: ubuntu-latest steps: @@ -39,31 +43,44 @@ jobs: - run: npm run build working-directory: src/IgniteUI.Blazor.GridLite - # GenerateSBOM=true pulls in Microsoft.Sbom.Targets (conditional PackageReference) - # and embeds _manifest/spdx_2.2 into the nupkg after Pack. - - name: Pack with SBOM + - name: Pack NuGet package run: > dotnet pack src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj --configuration ${{ env.BUILD_CONFIGURATION }} -p:RunNodeBuild=false -p:GeneratePackageOnBuild=false - -p:GenerateSBOM=true -p:Version=${{ env.PACKAGE_VERSION }} -o ./artifacts - - name: Extract and verify SBOM + # Dedicated nested manifest keeps sbom-tool out of the root 'dotnet tool restore' used by publish.yml + - name: Restore sbom-tool (pinned) + run: dotnet tool restore --tool-manifest .config/sbom-tool/dotnet-tools.json + + # -b: the shipped artifact (nupkg) gets listed with its hash in the SBOM's files section + # -bc: dependency detection scans the project dir (NuGet + npm) + - name: Generate SBOM + working-directory: .config/sbom-tool + run: > + dotnet tool run sbom-tool -- generate + -b ${{ github.workspace }}/artifacts + -bc ${{ github.workspace }}/src/IgniteUI.Blazor.GridLite + -pn IgniteUI.Blazor.GridLite + -pv ${{ env.PACKAGE_VERSION }} + -ps Infragistics + -nsb http://spdx.org/spdxdocs/IgniteUI.Blazor.GridLite + -V Information + + - name: Verify SBOM run: | set -euo pipefail - nupkg=(artifacts/*.nupkg) - unzip -q "${nupkg[0]}" "_manifest/*" -d extracted - test -s extracted/_manifest/spdx_2.2/manifest.spdx.json - test -s extracted/_manifest/spdx_2.2/manifest.spdx.json.sha256 - echo "SBOM verified in ${nupkg[0]}" + test -s artifacts/_manifest/spdx_2.2/manifest.spdx.json + test -s artifacts/_manifest/spdx_2.2/manifest.spdx.json.sha256 + echo "SBOM generated successfully." - - name: Upload NuGet package (with embedded SBOM) + - name: Upload NuGet package uses: actions/upload-artifact@v7 with: - name: nupkg-with-sbom + name: nupkg path: artifacts/*.nupkg retention-days: 1 if-no-files-found: error @@ -72,6 +89,30 @@ jobs: uses: actions/upload-artifact@v7 with: name: sbom-spdx_2.2 - path: extracted/_manifest/spdx_2.2 + path: artifacts/_manifest/spdx_2.2 retention-days: 1 if-no-files-found: error + + attach-to-release: + if: github.event_name == 'release' + needs: sbom + runs-on: ubuntu-latest + permissions: + contents: write # required to upload release assets + + steps: + - name: Download SBOM artifact + uses: actions/download-artifact@v8 + with: + name: sbom-spdx_2.2 + path: spdx_2.2 + + - name: Attach SBOM to release + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + run: | + set -euo pipefail + asset="IgniteUI.Blazor.GridLite.${TAG}.spdx_2.2.zip" + (cd spdx_2.2 && zip -r "../${asset}" .) + gh release upload "$TAG" "$asset" --clobber -R "${{ github.repository }}" diff --git a/src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj b/src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj index b6bf022..f91c101 100644 --- a/src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj +++ b/src/IgniteUI.Blazor.GridLite/IgniteUI.Blazor.GridLite.csproj @@ -53,11 +53,6 @@ - - - - - From f8cafc4b9aaf335d9b654df18ea7c3072a8cacdd Mon Sep 17 00:00:00 2001 From: Borislav Traykov Date: Tue, 4 Aug 2026 15:17:05 +0300 Subject: [PATCH 3/4] Use pinned SHAs for all github actions instead of release versions - for improved security (we hope) --- .github/workflows/sbom.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 631c713..5856090 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -26,14 +26,14 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Setup .NET - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 with: dotnet-version: "10.0.x" - - uses: actions/setup-node@v6.4.0 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '22' @@ -78,7 +78,7 @@ jobs: echo "SBOM generated successfully." - name: Upload NuGet package - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: nupkg path: artifacts/*.nupkg @@ -86,7 +86,7 @@ jobs: if-no-files-found: error - name: Upload SBOM files - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: sbom-spdx_2.2 path: artifacts/_manifest/spdx_2.2 @@ -102,7 +102,7 @@ jobs: steps: - name: Download SBOM artifact - uses: actions/download-artifact@v8 + uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: name: sbom-spdx_2.2 path: spdx_2.2 From 16b3990a51f05467a19043ac759bcbbb4a6de12f Mon Sep 17 00:00:00 2001 From: Borislav Traykov Date: Wed, 5 Aug 2026 14:55:07 +0300 Subject: [PATCH 4/4] Generate SPDX 3.0 SBOM as it's the newer standard --- .github/workflows/sbom.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 5856090..7c73d2d 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -58,6 +58,7 @@ jobs: # -b: the shipped artifact (nupkg) gets listed with its hash in the SBOM's files section # -bc: dependency detection scans the project dir (NuGet + npm) + # -mi SPDX:3.0: emit the SBOM in SPDX 3.0 format (output goes to _manifest/spdx_3.0) - name: Generate SBOM working-directory: .config/sbom-tool run: > @@ -68,13 +69,14 @@ jobs: -pv ${{ env.PACKAGE_VERSION }} -ps Infragistics -nsb http://spdx.org/spdxdocs/IgniteUI.Blazor.GridLite + -mi SPDX:3.0 -V Information - name: Verify SBOM run: | set -euo pipefail - test -s artifacts/_manifest/spdx_2.2/manifest.spdx.json - test -s artifacts/_manifest/spdx_2.2/manifest.spdx.json.sha256 + test -s artifacts/_manifest/spdx_3.0/manifest.spdx.json + test -s artifacts/_manifest/spdx_3.0/manifest.spdx.json.sha256 echo "SBOM generated successfully." - name: Upload NuGet package @@ -88,8 +90,8 @@ jobs: - name: Upload SBOM files uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: sbom-spdx_2.2 - path: artifacts/_manifest/spdx_2.2 + name: sbom-spdx_3.0 + path: artifacts/_manifest/spdx_3.0 retention-days: 1 if-no-files-found: error @@ -104,8 +106,8 @@ jobs: - name: Download SBOM artifact uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: - name: sbom-spdx_2.2 - path: spdx_2.2 + name: sbom-spdx_3.0 + path: spdx_3.0 - name: Attach SBOM to release env: @@ -113,6 +115,6 @@ jobs: TAG: ${{ github.ref_name }} run: | set -euo pipefail - asset="IgniteUI.Blazor.GridLite.${TAG}.spdx_2.2.zip" - (cd spdx_2.2 && zip -r "../${asset}" .) + asset="IgniteUI.Blazor.GridLite.${TAG}.spdx_3.0.zip" + (cd spdx_3.0 && zip -r "../${asset}" .) gh release upload "$TAG" "$asset" --clobber -R "${{ github.repository }}"