diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml new file mode 100644 index 000000000..f778dff7d --- /dev/null +++ b/.github/workflows/trivy.yml @@ -0,0 +1,129 @@ +name: Trivy + +on: + push: + branches: [ "main", "develop" ] + pull_request: + branches: [ "develop" ] + # New CVEs land in the database without any commit here, so the badge + # is refreshed against the current state of develop once a week. + schedule: + - cron: '0 4 * * 1' + workflow_dispatch: + +# Nothing by default; each job asks for exactly what it needs. +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + IMAGE: grandnode2:trivy + +jobs: + # NuGet (Directory.Packages.props) and npm (package-lock.json) dependencies, + # Dockerfile misconfiguration and committed secrets. + repository: + name: Scan repository + runs-on: ubuntu-latest + + permissions: + contents: read + security-events: write # upload SARIF to code scanning + + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + # Every finding goes to the Security tab; this step never fails the job. + - name: Trivy filesystem scan (SARIF) + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 + with: + scan-type: fs + scan-ref: . + scanners: vuln,misconfig,secret + format: sarif + output: trivy-fs.sarif + + # A pull request from a fork gets a read-only token and cannot upload. + - name: Upload SARIF + if: ${{ !cancelled() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3 + with: + sarif_file: trivy-fs.sarif + category: trivy-fs + + # The gate behind the badge: fixable HIGH and CRITICAL findings only. + - name: Trivy filesystem gate + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 + with: + scan-type: fs + scan-ref: . + scanners: vuln,misconfig,secret + severity: HIGH,CRITICAL + ignore-unfixed: true + format: table + exit-code: '1' + skip-setup-trivy: true + + # The image as the Dockerfile builds it: base OS packages plus the published app. + image: + name: Scan Docker image + runs-on: ubuntu-latest + + permissions: + contents: read + security-events: write # upload SARIF to code scanning + + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 + + - name: Build Docker image + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 + with: + context: . + load: true + push: false + build-args: | + GIT_COMMIT=${{ github.sha }} + GIT_BRANCH=${{ github.ref_name }} + tags: ${{ env.IMAGE }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Trivy image scan (SARIF) + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 + with: + scan-type: image + image-ref: ${{ env.IMAGE }} + scanners: vuln,secret + format: sarif + output: trivy-image.sarif + + - name: Upload SARIF + if: ${{ !cancelled() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3 + with: + sarif_file: trivy-image.sarif + category: trivy-image + + - name: Trivy image gate + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 + with: + scan-type: image + image-ref: ${{ env.IMAGE }} + scanners: vuln,secret + severity: HIGH,CRITICAL + ignore-unfixed: true + format: table + exit-code: '1' + skip-setup-trivy: true diff --git a/README.md b/README.md index 4bc782667..409f0d030 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ [![Tests on Linux, macOS and Windows](https://github.com/grandnode/grandnode2/actions/workflows/aspnetcore.yml/badge.svg)](https://github.com/grandnode/grandnode2/actions/workflows/aspnetcore.yml) [![Docker Image CI](https://github.com/grandnode/grandnode2/actions/workflows/docker-image.yml/badge.svg)](https://github.com/grandnode/grandnode2/actions/workflows/docker-image.yml) [![CodeQL Advanced](https://github.com/grandnode/grandnode2/actions/workflows/codeql.yml/badge.svg)](https://github.com/grandnode/grandnode2/actions/workflows/codeql.yml) +[![Trivy](https://github.com/grandnode/grandnode2/actions/workflows/trivy.yml/badge.svg?branch=develop)](https://github.com/grandnode/grandnode2/actions/workflows/trivy.yml)