From bb7fbeb36c9165d6ec09e2bffac1706d1a79d827 Mon Sep 17 00:00:00 2001 From: Oscar Zhou Date: Wed, 20 Apr 2022 16:06:37 +1200 Subject: [PATCH] feat/ce-220-security-scan --- .github/workflows/pr-security.yml | 312 +++++++++++++++++++++++++----- 1 file changed, 261 insertions(+), 51 deletions(-) diff --git a/.github/workflows/pr-security.yml b/.github/workflows/pr-security.yml index 70e5afdbf..19382fe87 100644 --- a/.github/workflows/pr-security.yml +++ b/.github/workflows/pr-security.yml @@ -1,58 +1,167 @@ -on: - pull_request: - branches: [develop, release/**] - workflow_dispatch: +name: Code Security Scan +on: + push: + branches: + - develop + pull_request: + branches: + - develop + - feat/ce-220-security-scan + schedule: + - cron: '30 * * * *' + jobs: client-dependencies: name: Client dependency check runs-on: ubuntu-latest + outputs: + js: ${{ steps.set-matrix.outputs.js_result }} + jsdiff: ${{ steps.set-diff-matrix.outputs.js_diff_result }} steps: - uses: actions/checkout@master - name: Run Snyk to check for vulnerabilities uses: snyk/actions/node@master - continue-on-error: true # To make sure that SARIF upload gets called + continue-on-error: true # To make sure that artifact upload gets called env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: - args: --severity-threshold=high --fail-on=upgradable --sarif-file-output=snyk.sarif + json: true - - name: Upload result to GitHub Code Scanning - uses: github/codeql-action/upload-sarif@v1 + - name: Upload js security scan result as artifact on develop + uses: actions/upload-artifact@v3 + if: >- + github.ref == 'refs/heads/develop' || + github.head_ref == 'feat/ce-220-security-scan' with: - sarif_file: snyk.sarif + name: js-security-scan-develop-result + path: snyk.json + + - name: Upload js security scan result as artifact + uses: actions/upload-artifact@v3 + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + with: + name: js-security-scan-feat-result + path: snyk.json + + - name: Analyse the js result + if: >- + github.ref == 'refs/heads/develop' || + github.head_ref == 'feat/ce-220-security-scan' + id: set-matrix + run: | + result=$(docker run --rm -v /home/runner/work/${{ github.event.repository.name}}/${{ github.event.repository.name}}:/data oscarzhou/scan-report:0.1.6 summary -report-type=snyk -path="/data/snyk.json" -output-type=matrix) + echo "::set-output name=js_result::${result}" + + - name: Download artifacts from develop branch + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv ./snyk.json ./js-snyk-feature.json + (gh run download -n js-security-scan-develop-result -R ${{ github.repository }} 2>&1 >/dev/null) || : + if [[ -e ./snyk.json ]]; then + mv ./snyk.json ./js-snyk-develop.json + else + echo "null" > ./js-snyk-develop.json + fi + + - name: Analyse the js diff result + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + id: set-diff-matrix + run: | + result=$(docker run --rm -v /home/runner/work/${{ github.event.repository.name}}/${{ github.event.repository.name}}:/data oscarzhou/scan-report:0.1.6 diff -report-type=snyk -path="/data/js-snyk-feature.json" -compare-to="./data/js-snyk-develop.json" -output-type=matrix) + echo "::set-output name=js_diff_result::${result}" server-dependencies: name: Server dependency check runs-on: ubuntu-latest - defaults: - run: - working-directory: ./api + outputs: + go: ${{ steps.set-matrix.outputs.go_result }} + godiff: ${{ steps.set-diff-matrix.outputs.go_diff_result }} steps: - uses: actions/checkout@master - name: Download dependencies - run: go get -v -d + run: | + cd ./api && go get -v -d - name: Run Snyk to check for vulnerabilities uses: snyk/actions/golang@master - continue-on-error: true # To make sure that SARIF upload gets called + continue-on-error: true # To make sure that artifact upload gets called env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: - args: --severity-threshold=high --sarif-file-output=snyk.sarif --file=./api/go.mod + args: --severity-threshold=high --file=./api/go.mod + json: true - - name: Upload result to GitHub Code Scanning - uses: github/codeql-action/upload-sarif@v1 + - name: Upload go security scan result as artifact on develop + uses: actions/upload-artifact@v3 + if: >- + github.ref == 'refs/heads/develop' || + github.head_ref == 'feat/ce-220-security-scan' with: - sarif_file: snyk.sarif + name: go-security-scan-develop-result + path: snyk.json - build_app: - name: Build app and api and docker image + - name: Upload go security scan result as artifact + uses: actions/upload-artifact@v3 + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + with: + name: go-security-scan-feature-result + path: snyk.json + + - name: Analyse the go result + if: >- + github.ref == 'refs/heads/develop' || + github.head_ref == 'feat/ce-220-security-scan' + id: set-matrix + run: | + result=$(docker run --rm -v /home/runner/work/${{ github.event.repository.name}}/${{ github.event.repository.name}}:/data oscarzhou/scan-report:0.1.6 summary -report-type=snyk -path="/data/snyk.json" -output-type=matrix) + echo "::set-output name=go_result::${result}" + + - name: Download artifacts from develop branch + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv ./snyk.json ./go-snyk-feature.json + (gh run download -n go-security-scan-develop-result -R ${{ github.repository }} 2>&1 >/dev/null) || : + if [[ -e ./snyk.json ]]; then + mv ./snyk.json ./go-snyk-develop.json + else + echo "null" > ./go-snyk-develop.json + fi + + - name: Analyse the go diff result + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + id: set-diff-matrix + run: | + result=$(docker run --rm -v /home/runner/work/${{ github.event.repository.name}}/${{ github.event.repository.name}}:/data oscarzhou/scan-report:0.1.6 diff -report-type=snyk -path="/data/go-snyk-feature.json" -compare-to="./data/go-snyk-develop.json" -output-type=matrix) + echo "::set-output name=go_diff_result::${result}" + + image-vulnerability: + name: Build docker image and Image vulnerability check runs-on: ubuntu-latest + outputs: + image: ${{ steps.set-matrix.outputs.image_result }} + imagediff: ${{ steps.set-diff-matrix.outputs.image_diff_result }} steps: - - uses: actions/checkout@master + - name: Checkout code + uses: actions/checkout@master - name: Use golang 1.17.x uses: actions/setup-go@v3 @@ -65,7 +174,8 @@ jobs: node-version: 12.x - name: Install packages and build - run: yarn install && yarn build + run: | + yarn install && yarn build - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 @@ -78,40 +188,140 @@ jobs: tags: trivy-portainer:${{ github.sha }} outputs: type=docker,dest=/tmp/trivy-portainer-image.tar - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: image-artifact - path: /tmp/trivy-portainer-image.tar - - image-vulnerability: - name: Image vulnerability check - needs: [build_app] - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@master - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Download image artifact - uses: actions/download-artifact@v3 - with: - name: image-artifact - path: /tmp - - name: Load docker image run: | docker load --input /tmp/trivy-portainer-image.tar - name: Run Trivy vulnerability scanner uses: docker://docker.io/aquasec/trivy:latest - continue-on-error: true # To make sure that SARIF upload gets called + continue-on-error: true with: - args: image --ignore-unfixed=true --vuln-type="os,library" --severity="CRITICAL,HIGH,MEDIUM" --exit-code=1 --format="sarif" --output="trivy-results.sarif" --no-progress trivy-portainer:${{ github.sha }} - - - name: Upload Trivy scan results to GitHub Code Scanning - uses: github/codeql-action/upload-sarif@v1 + args: image --ignore-unfixed=true --vuln-type="os,library" --severity="CRITICAL,HIGH,MEDIUM" --exit-code=1 --format="json" --output="image-trivy.json" --no-progress trivy-portainer:${{ github.sha }} + + - name: Upload image security scan result as artifact on develop + uses: actions/upload-artifact@v3 + if: >- + github.ref == 'refs/heads/develop' || + github.head_ref == 'feat/ce-220-security-scan' with: - sarif_file: 'trivy-results.sarif' \ No newline at end of file + name: image-security-scan-develop-result + path: image-trivy.json + + - name: Upload image security scan result as artifact + uses: actions/upload-artifact@v3 + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + with: + name: image-security-scan-feature-result + path: image-trivy.json + + - name: Analyse the trivy result + if: >- + github.ref == 'refs/heads/develop' || + github.head_ref == 'feat/ce-220-security-scan' + id: set-matrix + run: | + result=$(docker run --rm -v /home/runner/work/${{ github.event.repository.name}}/${{ github.event.repository.name}}:/data oscarzhou/scan-report:0.1.6 summary -report-type=trivy -path="/data/image-trivy.json" -output-type=matrix) + echo "::set-output name=image_result::${result}" + + - name: Download artifacts from develop branch + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv ./image-trivy.json ./image-trivy-feature.json + (gh run download -n image-security-scan-develop-result -R ${{ github.repository }} 2>&1 >/dev/null) || : + if [[ -e ./image-trivy.json ]]; then + mv ./image-trivy.json ./image-trivy-develop.json + else + echo "null" > ./image-trivy-develop.json + fi + + - name: Analyse the image diff result + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + id: set-diff-matrix + run: | + result=$(docker run --rm -v /home/runner/work/${{ github.event.repository.name}}/${{ github.event.repository.name}}:/data oscarzhou/scan-report:0.1.6 diff -report-type=trivy -path="/data/image-trivy-feature.json" -compare-to="./data/image-trivy-develop.json" -output-type=matrix) + echo "::set-output name=image_diff_result::${result}" + + result-analysis-compared-to-develop: + name: Analyse scan result compared to develop + needs: [client-dependencies, server-dependencies, image-vulnerability] + runs-on: ubuntu-latest + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' + strategy: + matrix: + jsdiff: ${{fromJson(needs.client-dependencies.outputs.jsdiff)}} + godiff: ${{fromJson(needs.server-dependencies.outputs.godiff)}} + imagediff: ${{fromJson(needs.image-vulnerability.outputs.imagediff)}} + steps: + + - name: Check job status of diff result + if: >- + github.ref != 'refs/heads/develop' && + github.head_ref != 'feat/ce-220-security-scan' && + (matrix.jsdiff.status == 'failure' || + matrix.godiff.status == 'failure' || + matrix.imagediff.status == 'failure') + run: | + echo ${{ matrix.jsdiff.summary }} + echo ${{ matrix.godiff.summary }} + echo ${{ matrix.imagediff.summary }} + exit 1 + + result-analysis: + name: Analyse scan result + needs: [client-dependencies, server-dependencies, image-vulnerability] + runs-on: ubuntu-latest + if: >- + github.ref == 'refs/heads/develop' || + github.head_ref == 'feat/ce-220-security-scan' + strategy: + matrix: + js: ${{fromJson(needs.client-dependencies.outputs.js)}} + go: ${{fromJson(needs.server-dependencies.outputs.go)}} + image: ${{fromJson(needs.image-vulnerability.outputs.image)}} + steps: + - name: Display the results of js, go and image + run: | + echo ${{ matrix.js.summary }} + echo ${{ matrix.go.summary }} + echo ${{ matrix.image.summary }} + + - name: Post the result to a Slack channel + if: >- + (github.ref == 'refs/heads/develop' || + github.head_ref == 'feat/ce-220-security-scan') && + (matrix.js.status == 'failure' || + matrix.go.status == 'failure' || + matrix.image.status == 'failure') + uses: slackapi/slack-github-action@v1.18.0 + with: + # Slack channel id, channel name, or user id to post message. + # See also: https://api.slack.com/methods/chat.postMessage#channels + channel-id: 'C03B2CVR49L' + # For posting a rich message using Block Kit + payload: | + { + "text": "Code Scanning Result:\nJS dependency check: ${{ matrix.js.status }} ${{ matrix.js.summary }}\nGo dependency check: ${{ matrix.go.status }} ${{ matrix.go.summary }}\nImage vulnerability check: ${{ matrix.image.status }} ${{ matrix.image.summary }}\n${{ github.event.pull_request._links.html.href }}", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Code Scanning Result:\nJS dependency check: ${{ matrix.js.status }} ${{ matrix.js.summary }}\nGo dependency check: ${{ matrix.go.status }} ${{ matrix.go.summary }}\nImage vulnerability check: ${{ matrix.image.status }} ${{ matrix.image.summary }}\n${{ github.event.pull_request._links.html.href }}" + } + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + +