From f1ec9ac74242fff27c3461f0ea59652fe15a18b8 Mon Sep 17 00:00:00 2001
From: Philippe Scorsolini
Date: Thu, 16 Mar 2023 17:37:41 +0100
Subject: [PATCH] ci: add trivy scan reusable workflow
Signed-off-by: Philippe Scorsolini
---
.github/workflows/scan.yml | 152 +++++++++++++++++++++++++++++++++++++
1 file changed, 152 insertions(+)
create mode 100644 .github/workflows/scan.yml
diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml
new file mode 100644
index 0000000..e6c4786
--- /dev/null
+++ b/.github/workflows/scan.yml
@@ -0,0 +1,152 @@
+name: Trivy Scan
+on:
+ workflow_call:
+ inputs:
+ images:
+ description: 'Comma separated list of images to scan, should be only image names without tags'
+ required: true
+ type: string
+ supported_releases:
+ description: 'Number of supported releases'
+ type: number
+ default: 1
+
+env:
+ DOCKER_USR: ${{ secrets.DOCKER_USR }}
+
+jobs:
+ generate-matrix:
+ runs-on: ubuntu-latest
+ outputs:
+ versions: ${{ steps.get-releases.outputs.versions}}
+ supported_releases: ${{ steps.get-releases.outputs.supported_releases }}
+ images: ${{ steps.split-images.outputs.images }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
+ with:
+ fetch-depth: 0
+
+ - name: Get Last Release
+ id: get-releases
+ shell: bash
+ ## find the 3 latest supported releases and their latest patch releases, storing them in the steps' outputs
+ run: |
+ # get the last 3 releases in "vX.Y" form
+ supported_releases="$(git for-each-ref --sort='-committerdate' --format='%(refname:short)' --count=${{ inputs.supported_releases }} 'refs/remotes/origin/release-*' | sed 's/.*release-/v/g')"
+ if [ -z "$supported_releases" ]
+ then
+ echo "DEBUG: No supported releases found"
+ echo "DEBUG: $(git for-each-ref 'refs/remotes')"
+ exit 1
+ fi
+
+ echo "DEBUG: ${supported_releases}"
+
+ # get the latest non-rc tag for each release
+ tags=""
+ while IFS= read -r version; do
+ tag="$(git for-each-ref --sort=-taggerdate --count=1 'refs/tags/'${version}'.[\!-rc.*]' --format='%(tag)')"
+ if [ -z "$tag" ]
+ then
+ echo "No tags found for version ${version}, ${tag}"
+ echo "DEBUG: $(git for-each-ref 'refs/tags')"
+ exit 1
+ fi
+ tags="${tags} ${version}=${tag}"
+ done <<< "${supported_releases}"
+
+ echo "DEBUG: ${tags}"
+
+ # build a JSON formatted list of all the supported releases for crossplane/crossplane
+ supported_releases=$(echo $supported_releases | jq -R .| jq -s -c '.[] | split(" ")')
+ ## build a map of all the supported releases and their latest tags for later usage
+ versions=$(echo $tags | jq -R .| jq -s -c '.[] | split(" ") | [.[] | select(length > 0) | [split("=")] | map({key: .[0], value: .[1]}) | .[] ] | from_entries' )
+
+ # store everything as outputs
+ echo "versions=${versions}" >> $GITHUB_OUTPUT
+ echo "supported_releases=${supported_releases}" >> $GITHUB_OUTPUT
+
+ echo "DEBUG: GITHUB_OUTPUT:"
+ cat $GITHUB_OUTPUT
+
+ - name: Split Images
+ id: split-images
+ shell: bash
+ run: |
+ images="${{ inputs.images }}"
+ if [ -z "$images" ]
+ then
+ echo "no images defined"
+ exit 1
+ fi
+ images=$(echo $images | jq -R -c 'split(",")')
+ echo "images=${images}" >> $GITHUB_OUTPUT
+
+ check-matrix:
+ # this job is just to check the matrix definition is valid and helps debugging it if not valid
+ runs-on: ubuntu-latest
+ needs:
+ - generate-matrix
+ steps:
+ - name: Check Matrix Definition
+ shell: bash
+ run: |
+ supported_releases='${{ needs.generate-matrix.outputs.supported_releases }}'
+ echo $supported_releases
+ echo $supported_releases | jq .
+ images='${{ needs.generate-matrix.outputs.images }}'
+ echo $images
+ echo $images | jq .
+
+ scan:
+ needs:
+ - check-matrix
+ - generate-matrix
+ strategy:
+ fail-fast: false
+ matrix:
+ release: ${{ fromJSON(needs.generate-matrix.outputs.supported_releases) }}
+ image: ${{ fromJSON(needs.generate-matrix.outputs.images) }}
+
+ runs-on: ubuntu-latest
+ steps:
+ - name: Get Release Tag
+ run: |
+ echo "${{ matrix.release }}"
+ tag="$(echo '${{ needs.generate-matrix.outputs.versions }}' | jq --raw-output ".[\"${{ matrix.release }}\"]")"
+ echo "tag=${tag}" >> $GITHUB_ENV
+ echo "escaped_filename=$(echo ${{ matrix.image }}/$tag | sed 's/[\/.:]/_/g')" >> $GITHUB_ENV
+
+ # we log to DockerHub to avoid rate limiting
+ - name: Login To DockerHub
+ uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2
+ if: env.DOCKER_USR != ''
+ with:
+ username: ${{ secrets.DOCKER_USR }}
+ password: ${{ secrets.DOCKER_PSW }}
+
+ # we pull the image to be sure we're scanning the latest sha available
+ - name: Pull Latest Image
+ run: docker pull ${{ matrix.image }}:${{ env.tag }}
+
+ - name: Run Trivy Vulnerability Scanner
+ uses: aquasecurity/trivy-action@8bd2f9fbda2109502356ff8a6a89da55b1ead252 # 0.9.1
+ with:
+ image-ref: ${{ matrix.image }}:${{ env.tag }}
+ format: 'sarif'
+ output: 'trivy-results.sarif'
+
+ - name: Upload Artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: trivy-${{ env.escaped_filename }}.sarif
+ path: trivy-results.sarif
+ retention-days: 3
+
+ - name: Upload Trivy Scan Results To GitHub Security Tab
+ uses: github/codeql-action/upload-sarif@v2
+ with:
+ sarif_file: 'trivy-results.sarif'
+ category: ${{ matrix.image }}:${{ env.tag }}
+