Display scan vulnerabilities in Actions summary on failure #303
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: BUILD-SCAN-PUSH | |
| on: | |
| push: | |
| branches: [ '**' ] | |
| workflow_dispatch: | |
| jobs: | |
| get-matrix-values: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| image: ${{ steps.set-var.outputs.image }} | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - id: set-var | |
| run: | | |
| echo 'image<<EOF' >> $GITHUB_OUTPUT | |
| cat ./image-matrix.json >> $GITHUB_OUTPUT | |
| echo 'EOF' >> $GITHUB_OUTPUT | |
| build-images: | |
| runs-on: ubuntu-latest | |
| needs: get-matrix-values | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| target: ["development", "production"] | |
| image: ${{fromJSON(needs.get-matrix-values.outputs.image)}} | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - id: setEnv | |
| name: Set Job env vars | |
| run: | | |
| cat JOB.env >> $GITHUB_ENV | |
| - id: setImageDetails | |
| name: Set image name and latest tag | |
| run: | | |
| if [ ${{matrix.target}} = "production" ] | |
| then | |
| DOCKER_REPO_NAME="defradigital/$IMAGE_NAME" | |
| else | |
| DOCKER_REPO_NAME="defradigital/$IMAGE_NAME-${{matrix.target}}" | |
| fi | |
| echo "dockerRepoName=$DOCKER_REPO_NAME" >> $GITHUB_OUTPUT | |
| echo "fullImageName=$DOCKER_REPO_NAME:$DEFRA_VERSION-dotnet${{matrix.image.netVersion}}" >> $GITHUB_OUTPUT | |
| DOCKERTAGS="$DOCKER_REPO_NAME:dotnet${{matrix.image.netVersion}}" | |
| if [ ${{matrix.image.latest}} = true ] | |
| then | |
| DOCKERTAGS="$DOCKERTAGS $DOCKER_REPO_NAME:latest" | |
| fi | |
| echo "dockerTags=$DOCKERTAGS" >> $GITHUB_OUTPUT | |
| - name: Set up Docker | |
| uses: docker/setup-docker-action@e43656e248c0bd0647d3f5c195d116aacf6fcaf4 # v4 | |
| with: | |
| daemon-config: | | |
| { | |
| "debug": true, | |
| "features": { | |
| "containerd-snapshotter": true | |
| } | |
| } | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 | |
| - name: Build the Docker image | |
| run: | | |
| docker buildx build . --file Dockerfile --no-cache \ | |
| --platform linux/amd64,linux/arm64 \ | |
| --load \ | |
| --target=${{matrix.target}} \ | |
| --build-arg DEFRA_VERSION=$DEFRA_VERSION \ | |
| --build-arg BASE_VERSION=${{matrix.image.netVersion}}-alpine${{matrix.image.alpineVersion}} \ | |
| --tag ${{steps.setImageDetails.outputs.fullImageName}} | |
| docker images | |
| - name: Save image to archive | |
| if: ${{ matrix.target == 'production' }} | |
| run: | | |
| docker save ${{steps.setImageDetails.outputs.fullImageName}} -o image-${{ matrix.image.netVersion }}.tar | |
| ls -lh image-${{ matrix.image.netVersion }}.tar | |
| - name: Tag image | |
| run: | | |
| echo "Tags are ${{steps.setImageDetails.outputs.dockerTags}}" | |
| for TAG in ${{steps.setImageDetails.outputs.dockerTags}} | |
| do | |
| echo "creating tag $TAG" | |
| docker image tag ${{steps.setImageDetails.outputs.fullImageName}} $TAG | |
| done | |
| - name: Run Anchore Grype scan | |
| id: grype-scan | |
| if: ${{ matrix.target == 'production' }} | |
| uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7 | |
| with: | |
| image: docker-archive:image-${{ matrix.image.netVersion }}.tar | |
| fail-build: true | |
| severity-cutoff: "medium" | |
| continue-on-error: true | |
| - name: Run Aqua Trivy scan | |
| id: trivy-scan | |
| if: ${{ matrix.target == 'production' }} | |
| uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0 | |
| with: | |
| input: image-${{ matrix.image.netVersion }}.tar | |
| scan-type: image | |
| format: sarif | |
| output: trivy-reports-dotnet-${{ matrix.image.netVersion }} | |
| exit-code: 1 | |
| vuln-type: os,library | |
| severity: CRITICAL,HIGH,MEDIUM | |
| continue-on-error: true | |
| - name: Upload Grype SARIF report | |
| if: ${{ steps.grype-scan.outcome == 'failure' && matrix.target == 'production' }} | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: grype-reports-dotnet-${{ matrix.image.netVersion }} | |
| path: ${{ steps.grype-scan.outputs.sarif }} | |
| - name: Upload Trivy SARIF report | |
| if: ${{ steps.trivy-scan.outcome == 'failure' && matrix.target == 'production' }} | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: trivy-reports-dotnet-${{ matrix.image.netVersion }} | |
| path: trivy-reports-dotnet-${{ matrix.image.netVersion }} | |
| - name: Fail build if scans failed | |
| if: ${{ (steps.grype-scan.outcome == 'failure' || steps.trivy-scan.outcome == 'failure') && matrix.target == 'production' && github.ref != 'refs/heads/main' }} | |
| run: | | |
| echo "## Scan Results" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ steps.grype-scan.outcome }}" == "failure" ]; then | |
| echo "### Grype Vulnerabilities" >> $GITHUB_STEP_SUMMARY | |
| echo "| Severity | CVE | Package | Details |" >> $GITHUB_STEP_SUMMARY | |
| echo "|----------|-----|---------|---------|" >> $GITHUB_STEP_SUMMARY | |
| jq -r '.runs[].results[] | "| \(.level) | \(.ruleId) | \(.message.text | split("\n")[0]) | \(.message.text | split("\n")[1:3] | join(", ")) |"' \ | |
| "${{ steps.grype-scan.outputs.sarif }}" >> $GITHUB_STEP_SUMMARY | |
| echo "::group::Grype Vulnerabilities" | |
| jq -r '.runs[].results[] | "\(.level)\t\(.ruleId)\t\(.message.text)"' \ | |
| "${{ steps.grype-scan.outputs.sarif }}" | |
| echo "::endgroup::" | |
| fi | |
| if [ "${{ steps.trivy-scan.outcome }}" == "failure" ]; then | |
| echo "### Trivy Vulnerabilities" >> $GITHUB_STEP_SUMMARY | |
| echo "| Severity | CVE | Package | Details |" >> $GITHUB_STEP_SUMMARY | |
| echo "|----------|-----|---------|---------|" >> $GITHUB_STEP_SUMMARY | |
| jq -r '.runs[].results[] | "| \(.level) | \(.ruleId) | \(.message.text | split("\n")[0]) | \(.message.text | split("\n")[1:3] | join(", ")) |"' \ | |
| "trivy-reports-dotnet-${{ matrix.image.netVersion }}" >> $GITHUB_STEP_SUMMARY | |
| echo "::group::Trivy Vulnerabilities" | |
| jq -r '.runs[].results[] | "\(.level)\t\(.ruleId)\t\(.message.text)"' \ | |
| "trivy-reports-dotnet-${{ matrix.image.netVersion }}" | |
| echo "::endgroup::" | |
| fi | |
| exit 1 | |
| - name: Login to DockerHub | |
| uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2 | |
| if: github.ref == 'refs/heads/main' | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_TOKEN }} | |
| - id: pushImage | |
| name: push docker image | |
| if: github.ref == 'refs/heads/main' | |
| run: | | |
| docker image push ${{steps.setImageDetails.outputs.fullImageName}} | |
| for TAG in ${{steps.setImageDetails.outputs.dockerTags}} | |
| do | |
| docker image push $TAG | |
| done | |
| create-release: | |
| runs-on: ubuntu-latest | |
| needs: build-images | |
| steps: | |
| - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 | |
| - name: Create GitHub release | |
| if: github.ref == 'refs/heads/main' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| current_defra_version=$(grep -oP 'DEFRA_VERSION=\K[\d.]+' JOB.env) | |
| if gh release view $current_defra_version &>/dev/null; then | |
| echo "Tag $current_defra_version already exists. Skipping release." | |
| else | |
| gh release create $current_defra_version \ | |
| --title ".NET $current_defra_version" \ | |
| --generate-notes | |
| fi |