From 16b104ad778ee4877491e76c55a5eaa598baa0ca Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 12:19:51 +0200 Subject: [PATCH 01/15] periodic sbom regeneration test --- .github/workflows/sbom-regenerate.yml | 48 +++++++++++++++++++++++++++ .github/workflows/sbom.yml | 26 ++++++++++----- 2 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/sbom-regenerate.yml diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml new file mode 100644 index 00000000..25aea1da --- /dev/null +++ b/.github/workflows/sbom-regenerate.yml @@ -0,0 +1,48 @@ +name: Periodic SBOM Regeneration + +on: + workflow_dispatch: + + # 2:00 AM UTC + schedule: + - cron: '0 2 * * *' + +jobs: + list-releases: + name: List Existing Releases + runs-on: [self-hosted, Linux, X64] + outputs: + releases: ${{ steps.get-releases.outputs.releases }} + steps: + - name: Get list of releases + id: get-releases + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # We use the GitHub CLI to list releases and 'jq' to format the output + # as a JSON array suitable for the job matrix. + RELEASES_JSON=$(gh release list --json tagName,uploadUrl --limit 2 | jq -c '[.[] | select(.tagName | startswith("v"))]') + echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT + + # This job will create a parallel run for each release found by the previous job. + regenerate-for-release: + name: Regenerate SBOM for Release + runs-on: [self-hosted, Linux, X64] + needs: list-releases + # Don't run this job if there are no releases to process + if: needs.list-releases.outputs.releases != '[]' + strategy: + fail-fast: false + # Dynamically create a matrix from the JSON output of the 'list-releases' job + matrix: + release: ${{ fromJson(needs.list-releases.outputs.releases) }} + # uses: ./.github/workflows/sbom.yml + # with: + # upload_url: ${{ matrix.release.uploadUrl }} + # tag: ${{ matrix.release.tagName }} + # secrets: inherit + steps: + - name: Show Variables + run: | + echo "Release Tag: ${{ matrix.release.tagName }}" + echo "Upload URL: ${{ matrix.release.uploadUrl }}" diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 6f0c7b52..27066220 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -7,30 +7,37 @@ on: description: "Release assets upload URL" required: true type: string + tag: + description: "The git tag to generate SBOM for - used in scheduled runs" + required: false + type: string jobs: create-sbom: runs-on: self-hosted steps: + - name: Determine release tag and version + # uses inputs.tag for scheduled runs, otherwise github.ref_name + run: | + TAG_NAME=${{ inputs.tag || github.ref_name }} + VERSION=${TAG_NAME#v} + echo "TAG_NAME=$TAG_NAME" >> $GITHUB_OUTPUT + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT + - name: Checkout uses: actions/checkout@v4 with: + ref: ${{ steps.vars.outputs.TAG_NAME }} submodules: recursive - # Store the version, stripping any v-prefix - - name: Write release version - run: | - VERSION=${GITHUB_REF_NAME#v} - echo Version: $VERSION - echo "VERSION=$VERSION" >> $GITHUB_ENV - name: Create SBOM with Trivy uses: aquasecurity/trivy-action@0.33.1 with: scan-type: 'fs' format: 'spdx-json' - output: "defguard-gateway-${{ env.VERSION }}.sbom.json" + output: "defguard-gateway-${{ steps.vars.outputs.VERSION }}.sbom.json" scan-ref: '.' severity: "CRITICAL,HIGH,MEDIUM,LOW" scanners: "vuln" @@ -38,10 +45,10 @@ jobs: - name: Create docker image SBOM with Trivy uses: aquasecurity/trivy-action@0.33.1 with: - image-ref: "ghcr.io/defguard/gateway:${{ env.VERSION }}" + image-ref: "ghcr.io/defguard/gateway:${{ steps.vars.outputs.VERSION }}" scan-type: 'image' format: 'spdx-json' - output: "defguard-gateway-${{ env.VERSION }}-docker.sbom.json" + output: "defguard-gateway-${{ steps.vars.outputs.VERSION }}-docker.sbom.json" severity: "CRITICAL,HIGH,MEDIUM,LOW" scanners: "vuln" @@ -53,3 +60,4 @@ jobs: upload_url: ${{ inputs.upload_url }} asset_path: "defguard-*.sbom.json" asset_content_type: application/octet-stream + overwrite: true From d46bc8508ddf2fc1ca88d990a1f86751d5393a5c Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 12:23:58 +0200 Subject: [PATCH 02/15] regenerate on push to branch --- .github/workflows/sbom-regenerate.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index 25aea1da..9a90617c 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -1,7 +1,9 @@ name: Periodic SBOM Regeneration on: - workflow_dispatch: + push: + branches: + - sbom-schedule # 2:00 AM UTC schedule: From a0fc25a9cfc140a0b390445bfad4a9a2d73711e9 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 12:25:32 +0200 Subject: [PATCH 03/15] run on ubuntu-latest --- .github/workflows/sbom-regenerate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index 9a90617c..148c9139 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -12,7 +12,7 @@ on: jobs: list-releases: name: List Existing Releases - runs-on: [self-hosted, Linux, X64] + runs-on: ubuntu-latest outputs: releases: ${{ steps.get-releases.outputs.releases }} steps: From e5dded504d6506aae6a09b6bf958e569ed292def Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 13:12:08 +0200 Subject: [PATCH 04/15] try to get uploadUrl with "gh api" command --- .github/workflows/sbom-regenerate.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index 148c9139..4b56305e 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -20,10 +20,14 @@ jobs: id: get-releases env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # run: | + # # We use the GitHub CLI to list releases and 'jq' to format the output + # # as a JSON array suitable for the job matrix. + # RELEASES_JSON=$(gh release list --json tagName,uploadUrl --limit 2 | jq -c '[.[] | select(.tagName | startswith("v"))]') + # echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT run: | - # We use the GitHub CLI to list releases and 'jq' to format the output - # as a JSON array suitable for the job matrix. - RELEASES_JSON=$(gh release list --json tagName,uploadUrl --limit 2 | jq -c '[.[] | select(.tagName | startswith("v"))]') + RELEASES_JSON=$(gh api repos/${{ github.repository }}/releases \ + --jq '[.[] | {tagName: .tag_name, uploadUrl: .upload_url}]') echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT # This job will create a parallel run for each release found by the previous job. From c09d715e701f6ad293aa24752dfe8cf2d5872118 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 13:14:44 +0200 Subject: [PATCH 05/15] limit to 3 latest releases --- .github/workflows/sbom-regenerate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index 4b56305e..16e10eec 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -27,7 +27,7 @@ jobs: # echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT run: | RELEASES_JSON=$(gh api repos/${{ github.repository }}/releases \ - --jq '[.[] | {tagName: .tag_name, uploadUrl: .upload_url}]') + --jq '[.[:3] | .[] | {tagName: .tag_name, uploadUrl: .upload_url}]') echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT # This job will create a parallel run for each release found by the previous job. From ab5a6f7cfd4e4372c724176f25d6c0d5e916adc5 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 13:17:05 +0200 Subject: [PATCH 06/15] only published releases --- .github/workflows/sbom-regenerate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index 16e10eec..9fda30bf 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -27,7 +27,7 @@ jobs: # echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT run: | RELEASES_JSON=$(gh api repos/${{ github.repository }}/releases \ - --jq '[.[:3] | .[] | {tagName: .tag_name, uploadUrl: .upload_url}]') + --jq '[.[] | select(.draft == false) | {tagName: .tag_name, uploadUrl: .upload_url}][:3]') echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT # This job will create a parallel run for each release found by the previous job. From e919cdd8389f3088a780a6609bf04013fc4deebe Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 13:27:29 +0200 Subject: [PATCH 07/15] test periodic sbom generation for latest releases --- .github/workflows/sbom-regenerate.yml | 28 +++++++++++---------------- .github/workflows/sbom.yml | 1 - 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index 9fda30bf..fc633d0c 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -20,20 +20,14 @@ jobs: id: get-releases env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # run: | - # # We use the GitHub CLI to list releases and 'jq' to format the output - # # as a JSON array suitable for the job matrix. - # RELEASES_JSON=$(gh release list --json tagName,uploadUrl --limit 2 | jq -c '[.[] | select(.tagName | startswith("v"))]') - # echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT run: | RELEASES_JSON=$(gh api repos/${{ github.repository }}/releases \ - --jq '[.[] | select(.draft == false) | {tagName: .tag_name, uploadUrl: .upload_url}][:3]') + --jq '[.[] | select(.draft == false) | {tagName: .tag_name, uploadUrl: .upload_url}][:1]') echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT # This job will create a parallel run for each release found by the previous job. regenerate-for-release: name: Regenerate SBOM for Release - runs-on: [self-hosted, Linux, X64] needs: list-releases # Don't run this job if there are no releases to process if: needs.list-releases.outputs.releases != '[]' @@ -42,13 +36,13 @@ jobs: # Dynamically create a matrix from the JSON output of the 'list-releases' job matrix: release: ${{ fromJson(needs.list-releases.outputs.releases) }} - # uses: ./.github/workflows/sbom.yml - # with: - # upload_url: ${{ matrix.release.uploadUrl }} - # tag: ${{ matrix.release.tagName }} - # secrets: inherit - steps: - - name: Show Variables - run: | - echo "Release Tag: ${{ matrix.release.tagName }}" - echo "Upload URL: ${{ matrix.release.uploadUrl }}" + uses: ./.github/workflows/sbom.yml + with: + upload_url: ${{ matrix.release.uploadUrl }} + tag: ${{ matrix.release.tagName }} + secrets: inherit + # steps: + # - name: Show Variables + # run: | + # echo "Release Tag: ${{ matrix.release.tagName }}" + # echo "Upload URL: ${{ matrix.release.uploadUrl }}" diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 27066220..1ea30d75 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -31,7 +31,6 @@ jobs: ref: ${{ steps.vars.outputs.TAG_NAME }} submodules: recursive - - name: Create SBOM with Trivy uses: aquasecurity/trivy-action@0.33.1 with: From eb7e17f51a8eaf8cdf197693081e2bf8c2972cd9 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 13:30:00 +0200 Subject: [PATCH 08/15] add step id --- .github/workflows/sbom.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 1ea30d75..7be4f587 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -18,6 +18,7 @@ jobs: steps: - name: Determine release tag and version + id: vars # uses inputs.tag for scheduled runs, otherwise github.ref_name run: | TAG_NAME=${{ inputs.tag || github.ref_name }} From fb901836a5be50307ddb0ce1b6d980a1ab1586c2 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 13:31:23 +0200 Subject: [PATCH 09/15] run sbom generation on linux --- .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 7be4f587..e081bb9e 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -14,7 +14,7 @@ on: jobs: create-sbom: - runs-on: self-hosted + runs-on: [self-hosted, Linux, X64] steps: - name: Determine release tag and version From 72ab23e0e9389663b1662109c1c3273de1fd57d9 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 13:35:55 +0200 Subject: [PATCH 10/15] test cron trigger --- .github/workflows/sbom-regenerate.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index fc633d0c..f72bcc13 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -1,13 +1,13 @@ name: Periodic SBOM Regeneration on: - push: - branches: - - sbom-schedule + # push: + # branches: + # - sbom-schedule # 2:00 AM UTC schedule: - - cron: '0 2 * * *' + - cron: '37 11 * * *' jobs: list-releases: From 039be8ec4bb66feed2cafd9f0a90b1127de86454 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 13:41:20 +0200 Subject: [PATCH 11/15] test sbom files re-upload --- .github/workflows/sbom-regenerate.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index f72bcc13..4d047726 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -1,13 +1,13 @@ name: Periodic SBOM Regeneration on: - # push: - # branches: - # - sbom-schedule + push: + branches: + - sbom-schedule - # 2:00 AM UTC + # 2:30 AM UTC schedule: - - cron: '37 11 * * *' + - cron: '30 2 * * *' jobs: list-releases: From c8b6bcfadddd0ca148e4bb4977512c566c27c455 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 14:11:55 +0200 Subject: [PATCH 12/15] (re)generate advisories files --- .github/workflows/sbom.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index e081bb9e..9e730430 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -52,12 +52,32 @@ jobs: severity: "CRITICAL,HIGH,MEDIUM,LOW" scanners: "vuln" - - name: Upload SBOM + - name: Create security advisory file with Trivy + uses: aquasecurity/trivy-action@0.33.1 + with: + scan-type: 'fs' + format: 'json' + output: "defguard-gateway-${{ steps.vars.outputs.VERSION }}.advisories.json" + scan-ref: '.' + severity: "CRITICAL,HIGH,MEDIUM,LOW" + scanners: "vuln" + + - name: Create docker image security advisory file with Trivy + uses: aquasecurity/trivy-action@0.33.1 + with: + image-ref: "ghcr.io/defguard/gateway:${{ steps.vars.outputs.VERSION }}" + scan-type: 'image' + format: 'json' + output: "defguard-gateway-${{ steps.vars.outputs.VERSION }}-docker.advisories.json" + severity: "CRITICAL,HIGH,MEDIUM,LOW" + scanners: "vuln" + + - name: Upload SBOMs and advisories uses: shogo82148/actions-upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ inputs.upload_url }} - asset_path: "defguard-*.sbom.json" + asset_path: "defguard-*.json" asset_content_type: application/octet-stream overwrite: true From 35f2face26f028de4f770c92bb8376b7988a0daf Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 14:21:33 +0200 Subject: [PATCH 13/15] cleanup, last 3 releases --- .github/workflows/sbom-regenerate.yml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index 4d047726..c76ce32c 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -1,13 +1,8 @@ name: Periodic SBOM Regeneration on: - push: - branches: - - sbom-schedule - - # 2:30 AM UTC schedule: - - cron: '30 2 * * *' + - cron: '30 2 * * *' # 2:30 AM UTC jobs: list-releases: @@ -22,7 +17,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | RELEASES_JSON=$(gh api repos/${{ github.repository }}/releases \ - --jq '[.[] | select(.draft == false) | {tagName: .tag_name, uploadUrl: .upload_url}][:1]') + --jq '[.[] | select(.draft == false) | {tagName: .tag_name, uploadUrl: .upload_url}][:3]') echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT # This job will create a parallel run for each release found by the previous job. @@ -41,8 +36,3 @@ jobs: upload_url: ${{ matrix.release.uploadUrl }} tag: ${{ matrix.release.tagName }} secrets: inherit - # steps: - # - name: Show Variables - # run: | - # echo "Release Tag: ${{ matrix.release.tagName }}" - # echo "Upload URL: ${{ matrix.release.uploadUrl }}" From 925416bd50d0e7fd5b5ca03c31744b7446e438b5 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 14:23:33 +0200 Subject: [PATCH 14/15] comments --- .github/workflows/sbom-regenerate.yml | 4 +--- .github/workflows/sbom.yml | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index c76ce32c..01a9d40a 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -20,15 +20,13 @@ jobs: --jq '[.[] | select(.draft == false) | {tagName: .tag_name, uploadUrl: .upload_url}][:3]') echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT - # This job will create a parallel run for each release found by the previous job. regenerate-for-release: name: Regenerate SBOM for Release needs: list-releases - # Don't run this job if there are no releases to process + # Don't run if no releases were found. if: needs.list-releases.outputs.releases != '[]' strategy: fail-fast: false - # Dynamically create a matrix from the JSON output of the 'list-releases' job matrix: release: ${{ fromJson(needs.list-releases.outputs.releases) }} uses: ./.github/workflows/sbom.yml diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 9e730430..9f2fc8bb 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Determine release tag and version id: vars - # uses inputs.tag for scheduled runs, otherwise github.ref_name + # Uses inputs.tag for scheduled runs, otherwise github.ref_name. run: | TAG_NAME=${{ inputs.tag || github.ref_name }} VERSION=${TAG_NAME#v} From f881843316cad83fb6078169021541b33f391644 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Mon, 29 Sep 2025 14:56:04 +0200 Subject: [PATCH 15/15] only generate sboms and advisories for the latest release --- .github/workflows/sbom-regenerate.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml index 01a9d40a..d6a1bbe1 100644 --- a/.github/workflows/sbom-regenerate.yml +++ b/.github/workflows/sbom-regenerate.yml @@ -6,7 +6,7 @@ on: jobs: list-releases: - name: List Existing Releases + name: List releases runs-on: ubuntu-latest outputs: releases: ${{ steps.get-releases.outputs.releases }} @@ -17,11 +17,11 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | RELEASES_JSON=$(gh api repos/${{ github.repository }}/releases \ - --jq '[.[] | select(.draft == false) | {tagName: .tag_name, uploadUrl: .upload_url}][:3]') + --jq '[.[] | select(.draft == false) | {tagName: .tag_name, uploadUrl: .upload_url}][:1]') echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT regenerate-for-release: - name: Regenerate SBOM for Release + name: Regenerate SBOM for release needs: list-releases # Don't run if no releases were found. if: needs.list-releases.outputs.releases != '[]'