name: PR Code Security Scan on: pull_request_review: types: - submitted - edited paths: - 'package.json' - 'go.mod' - 'build/linux/Dockerfile' - 'build/linux/alpine.Dockerfile' - 'build/windows/Dockerfile' - '.github/workflows/pr-security.yml' env: GO_VERSION: 1.21.6 NODE_VERSION: 18.x jobs: client-dependencies: name: Client Dependency Check runs-on: ubuntu-latest if: >- github.event.pull_request && github.event.review.body == '/scan' && github.event.pull_request.draft == false outputs: jsdiff: ${{ steps.set-diff-matrix.outputs.js_diff_result }} steps: - name: checkout repository uses: actions/checkout@master - name: scan vulnerabilities by Snyk uses: snyk/actions/node@master continue-on-error: true # To make sure that artifact upload gets called env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: json: true - name: upload scan result as pull-request artifact uses: actions/upload-artifact@v3 with: name: js-security-scan-feat-result path: snyk.json - name: download artifacts from develop branch built by nightly 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: pr vs develop scan report comparison export to html run: | $(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest diff --report-type=snyk --path="/data/js-snyk-feature.json" --compare-to="/data/js-snyk-develop.json" --output-type=table --export --export-filename="/data/js-result") - name: upload html file as artifact uses: actions/upload-artifact@v3 with: name: html-js-result-compare-to-develop-${{github.run_id}} path: js-result.html - name: analyse different vulnerabilities against develop branch id: set-diff-matrix run: | result=$(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest diff --report-type=snyk --path="/data/js-snyk-feature.json" --compare-to="/data/js-snyk-develop.json" --output-type=matrix) echo "js_diff_result=${result}" >> $GITHUB_OUTPUT server-dependencies: name: Server Dependency Check runs-on: ubuntu-latest if: >- github.event.pull_request && github.event.review.body == '/scan' && github.event.pull_request.draft == false outputs: godiff: ${{ steps.set-diff-matrix.outputs.go_diff_result }} steps: - name: checkout repository uses: actions/checkout@master - name: install Go uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} - name: download Go modules run: cd ./api && go get -t -v -d ./... - name: scan vulnerabilities by Snyk continue-on-error: true # To make sure that artifact upload gets called env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} run: | yarn global add snyk snyk test --file=./go.mod --json-file-output=snyk.json 2>/dev/null || : - name: upload scan result as pull-request artifact uses: actions/upload-artifact@v3 with: name: go-security-scan-feature-result path: snyk.json - name: download artifacts from develop branch built by nightly 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: pr vs develop scan report comparison export to html run: | $(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest diff --report-type=snyk --path="/data/go-snyk-feature.json" --compare-to="/data/go-snyk-develop.json" --output-type=table --export --export-filename="/data/go-result") - name: upload html file as artifact uses: actions/upload-artifact@v3 with: name: html-go-result-compare-to-develop-${{github.run_id}} path: go-result.html - name: analyse different vulnerabilities against develop branch id: set-diff-matrix run: | result=$(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest diff --report-type=snyk --path="/data/go-snyk-feature.json" --compare-to="/data/go-snyk-develop.json" --output-type=matrix) echo "go_diff_result=${result}" >> $GITHUB_OUTPUT image-vulnerability: name: Image Vulnerability Check runs-on: ubuntu-latest if: >- github.event.pull_request && github.event.review.body == '/scan' && github.event.pull_request.draft == false outputs: imagediff-trivy: ${{ steps.set-diff-trivy-matrix.outputs.image_diff_trivy_result }} imagediff-docker-scout: ${{ steps.set-diff-docker-scout-matrix.outputs.image_diff_docker_scout_result }} steps: - name: checkout code uses: actions/checkout@master - name: install Go uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} - name: install Node.js uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} - name: Install packages run: yarn --frozen-lockfile - name: build run: make build-all - name: set up docker buildx uses: docker/setup-buildx-action@v2 - name: build and compress image uses: docker/build-push-action@v4 with: context: . file: build/linux/Dockerfile tags: local-portainer:${{ github.sha }} outputs: type=docker,dest=/tmp/local-portainer-image.tar - name: load docker image run: | docker load --input /tmp/local-portainer-image.tar - name: scan vulnerabilities by Trivy uses: docker://docker.io/aquasec/trivy:latest continue-on-error: true with: args: image --ignore-unfixed=true --vuln-type="os,library" --exit-code=1 --format="json" --output="image-trivy.json" --no-progress local-portainer:${{ github.sha }} - name: upload Trivy image security scan result as artifact uses: actions/upload-artifact@v3 with: name: image-security-scan-feature-result path: image-trivy.json - name: download Trivy artifacts from develop branch built by nightly 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: pr vs develop Trivy scan report comparison export to html run: | $(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest diff --report-type=trivy --path="/data/image-trivy-feature.json" --compare-to="/data/image-trivy-develop.json" --output-type=table --export --export-filename="/data/image-trivy-result") - name: upload html file as Trivy artifact uses: actions/upload-artifact@v3 with: name: html-image-result-compare-to-develop-${{github.run_id}} path: image-trivy-result.html - name: analyse different vulnerabilities against develop branch by Trivy id: set-diff-trivy-matrix run: | result=$(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest diff --report-type=trivy --path="/data/image-trivy-feature.json" --compare-to="/data/image-trivy-develop.json" --output-type=matrix) echo "image_diff_trivy_result=${result}" >> $GITHUB_OUTPUT - name: scan vulnerabilities by Docker Scout uses: docker/scout-action@v1 continue-on-error: true with: command: cves image: local-portainer:${{ github.sha }} sarif-file: image-docker-scout.json dockerhub-user: ${{ secrets.DOCKER_HUB_USERNAME }} dockerhub-password: ${{ secrets.DOCKER_HUB_PASSWORD }} - name: upload Docker Scout image security scan result as artifact uses: actions/upload-artifact@v3 with: name: image-security-scan-feature-result path: image-docker-scout.json - name: download Docker Scout artifacts from develop branch built by nightly scan env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | mv ./image-docker-scout.json ./image-docker-scout-feature.json (gh run download -n image-security-scan-develop-result -R ${{ github.repository }} 2>&1 >/dev/null) || : if [[ -e ./image-docker-scout.json ]]; then mv ./image-docker-scout.json ./image-docker-scout-develop.json else echo "null" > ./image-docker-scout-develop.json fi - name: pr vs develop Docker Scout scan report comparison export to html run: | $(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest diff --report-type=docker-scout --path="/data/image-docker-scout-feature.json" --compare-to="/data/image-docker-scout-develop.json" --output-type=table --export --export-filename="/data/image-docker-scout-result") - name: upload html file as Docker Scout artifact uses: actions/upload-artifact@v3 with: name: html-image-result-compare-to-develop-${{github.run_id}} path: image-docker-scout-result.html - name: analyse different vulnerabilities against develop branch by Docker Scout id: set-diff-docker-scout-matrix run: | result=$(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest diff --report-type=docker-scout --path="/data/image-docker-scout-feature.json" --compare-to="/data/image-docker-scout-develop.json" --output-type=matrix) echo "image_diff_docker_scout_result=${result}" >> $GITHUB_OUTPUT result-analysis: name: Analyse Scan Result Against develop Branch needs: [client-dependencies, server-dependencies, image-vulnerability] runs-on: ubuntu-latest if: >- github.event.pull_request && github.event.review.body == '/scan' && github.event.pull_request.draft == false strategy: matrix: jsdiff: ${{fromJson(needs.client-dependencies.outputs.jsdiff)}} godiff: ${{fromJson(needs.server-dependencies.outputs.godiff)}} imagediff-trivy: ${{fromJson(needs.image-vulnerability.outputs.imagediff-trivy)}} imagediff-docker-scout: ${{fromJson(needs.image-vulnerability.outputs.imagediff-docker-scout)}} steps: - name: check job status of diff result if: >- matrix.jsdiff.status == 'failure' || matrix.godiff.status == 'failure' || matrix.imagediff-trivy.status == 'failure' || matrix.imagediff-docker-scout.status == 'failure' run: | echo "${{ matrix.jsdiff.status }}" echo "${{ matrix.godiff.status }}" echo "${{ matrix.imagediff-trivy.status }}" echo "${{ matrix.imagediff-docker-scout.status }}" echo "${{ matrix.jsdiff.summary }}" echo "${{ matrix.godiff.summary }}" echo "${{ matrix.imagediff-trivy.summary }}" echo "${{ matrix.imagediff-docker-scout.summary }}" exit 1