diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 55350776..a10ebc14 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -69,7 +69,7 @@ jobs: cache-to: type=gha,mode=max - name: Scan image with Trivy - uses: aquasecurity/trivy-action@0.32.0 + uses: aquasecurity/trivy-action@0.33.1 with: image-ref: "${{ env.GHCR_REPO }}:${{ github.sha }}-${{ matrix.tag }}" format: "table" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a103012f..e744b49b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,6 +52,12 @@ jobs: draft: true generate_release_notes: true + create-sbom: + needs: [create-release, build-docker-release] + uses: ./.github/workflows/sbom.yml + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + build-binaries: needs: [create-release] runs-on: diff --git a/.github/workflows/sbom-regenerate.yml b/.github/workflows/sbom-regenerate.yml new file mode 100644 index 00000000..3ecb2e6e --- /dev/null +++ b/.github/workflows/sbom-regenerate.yml @@ -0,0 +1,37 @@ +name: Periodic SBOM Regeneration + +on: + schedule: + - cron: '30 2 * * *' # 2:30 AM UTC + +jobs: + list-releases: + name: List releases + runs-on: ubuntu-latest + outputs: + releases: ${{ steps.get-releases.outputs.releases }} + steps: + - name: Get list of releases + id: get-releases + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + RELEASES_JSON=$(gh api repos/${{ github.repository }}/releases \ + --jq '[.[] + | select(.draft == false and (.tag_name | test("^v[0-9]+\\.[0-9]+\\.[0-9]+$"))) + | {tagName: .tag_name, uploadUrl: .upload_url}][:1]') + echo "releases=$RELEASES_JSON" >> $GITHUB_OUTPUT + regenerate-for-release: + name: Regenerate SBOM for release + needs: list-releases + # Don't run if no releases were found. + if: needs.list-releases.outputs.releases != '[]' + strategy: + fail-fast: false + 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 diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml new file mode 100644 index 00000000..38d0bd5c --- /dev/null +++ b/.github/workflows/sbom.yml @@ -0,0 +1,83 @@ +name: Create SBOM files + +on: + workflow_call: + inputs: + upload_url: + 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, Linux, X64] + + 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 }} + 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 + + - name: Create SBOM with Trivy + uses: aquasecurity/trivy-action@0.33.1 + with: + scan-type: 'fs' + format: 'spdx-json' + output: "defguard-proxy-${{ steps.vars.outputs.VERSION }}.sbom.json" + scan-ref: '.' + severity: "CRITICAL,HIGH,MEDIUM,LOW" + scanners: "vuln" + + - name: Create docker image SBOM with Trivy + uses: aquasecurity/trivy-action@0.33.1 + with: + image-ref: "ghcr.io/defguard/defguard-proxy:${{ steps.vars.outputs.VERSION }}" + scan-type: 'image' + format: 'spdx-json' + output: "defguard-proxy-${{ steps.vars.outputs.VERSION }}-docker.sbom.json" + severity: "CRITICAL,HIGH,MEDIUM,LOW" + scanners: "vuln" + + - name: Create security advisory file with Trivy + uses: aquasecurity/trivy-action@0.33.1 + with: + scan-type: 'fs' + format: 'json' + output: "defguard-proxy-${{ 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/defguard-proxy:${{ steps.vars.outputs.VERSION }}" + scan-type: 'image' + format: 'json' + output: "defguard-proxy-${{ 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-*.json" + asset_content_type: application/octet-stream + overwrite: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fc24763b..ad533e66 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,6 +34,15 @@ jobs: uses: actions/checkout@v4 with: submodules: recursive + - name: Scan code with Trivy + uses: aquasecurity/trivy-action@0.33.1 + with: + scan-type: 'fs' + scan-ref: '.' + exit-code: "1" + ignore-unfixed: true + severity: "CRITICAL,HIGH,MEDIUM" + scanners: "vuln" - name: Cache uses: Swatinem/rust-cache@v2 - name: Install protoc