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 }} +