name: Nightly Code Security Scan on: schedule: - cron: '0 20 * * *' workflow_dispatch: env: GO_VERSION: 1.21.6 jobs: client-dependencies: name: Client Dependency Check runs-on: ubuntu-latest if: >- # only run for develop branch github.ref == 'refs/heads/develop' outputs: js: ${{ steps.set-matrix.outputs.js_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 develop artifact uses: actions/upload-artifact@v3 with: name: js-security-scan-develop-result path: snyk.json - name: develop scan report export to html run: | $(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest summary --report-type=snyk --path="/data/snyk.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-${{github.run_id}} path: js-result.html - name: analyse vulnerabilities id: set-matrix run: | result=$(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest summary --report-type=snyk --path="/data/snyk.json" --output-type=matrix) echo "js_result=${result}" >> $GITHUB_OUTPUT server-dependencies: name: Server Dependency Check runs-on: ubuntu-latest if: >- # only run for develop branch github.ref == 'refs/heads/develop' outputs: go: ${{ steps.set-matrix.outputs.go_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 develop artifact uses: actions/upload-artifact@v3 with: name: go-security-scan-develop-result path: snyk.json - name: develop scan report export to html run: | $(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest summary --report-type=snyk --path="/data/snyk.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-${{github.run_id}} path: go-result.html - name: analyse vulnerabilities id: set-matrix run: | result=$(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest summary --report-type=snyk --path="/data/snyk.json" --output-type=matrix) echo "go_result=${result}" >> $GITHUB_OUTPUT image-vulnerability: name: Image Vulnerability Check runs-on: ubuntu-latest if: >- github.ref == 'refs/heads/develop' outputs: image-trivy: ${{ steps.set-trivy-matrix.outputs.image_trivy_result }} image-docker-scout: ${{ steps.set-docker-scout-matrix.outputs.image_docker_scout_result }} steps: - 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 portainerci/portainer:develop - name: upload Trivy image security scan result as artifact uses: actions/upload-artifact@v3 with: name: image-security-scan-develop-result path: image-trivy.json - name: develop Trivy scan report export to html run: | $(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest summary --report-type=trivy --path="/data/image-trivy.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-${{github.run_id}} path: image-trivy-result.html - name: analyse vulnerabilities from Trivy id: set-trivy-matrix run: | result=$(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest summary --report-type=trivy --path="/data/image-trivy.json" --output-type=matrix) echo "image_trivy_result=${result}" >> $GITHUB_OUTPUT - name: scan vulnerabilities by Docker Scout uses: docker/scout-action@v1 continue-on-error: true with: command: cves image: portainerci/portainer:develop 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-develop-result path: image-docker-scout.json - name: develop Docker Scout scan report export to html run: | $(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest summary --report-type=docker-scout --path="/data/image-docker-scout.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-${{github.run_id}} path: image-docker-scout-result.html - name: analyse vulnerabilities from Docker Scout id: set-docker-scout-matrix run: | result=$(docker run --rm -v ${{ github.workspace }}:/data portainerci/code-security-report:latest summary --report-type=docker-scout --path="/data/image-docker-scout.json" --output-type=matrix) echo "image_docker_scout_result=${result}" >> $GITHUB_OUTPUT result-analysis: name: Analyse Scan Results needs: [client-dependencies, server-dependencies, image-vulnerability] runs-on: ubuntu-latest if: >- github.ref == 'refs/heads/develop' strategy: matrix: js: ${{fromJson(needs.client-dependencies.outputs.js)}} go: ${{fromJson(needs.server-dependencies.outputs.go)}} image-trivy: ${{fromJson(needs.image-vulnerability.outputs.image-trivy)}} image-docker-scout: ${{fromJson(needs.image-vulnerability.outputs.image-docker-scout)}} steps: - name: display the results of js, Go, and image scan run: | echo "${{ matrix.js.status }}" echo "${{ matrix.go.status }}" echo "${{ matrix.image-trivy.status }}" echo "${{ matrix.image-docker-scout.status }}" echo "${{ matrix.js.summary }}" echo "${{ matrix.go.summary }}" echo "${{ matrix.image-trivy.summary }}" echo "${{ matrix.image-docker-scout.summary }}" - name: send message to Slack if: >- matrix.js.status == 'failure' || matrix.go.status == 'failure' || matrix.image-trivy.status == 'failure' || matrix.image-docker-scout.status == 'failure' uses: slackapi/slack-github-action@v1.23.0 with: payload: | { "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "Code Scanning Result (*${{ github.repository }}*)\n*<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|GitHub Actions Workflow URL>*" } } ], "attachments": [ { "color": "#FF0000", "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "*JS dependency check*: *${{ matrix.js.status }}*\n${{ matrix.js.summary }}" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Go dependency check*: *${{ matrix.go.status }}*\n${{ matrix.go.summary }}" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Image Trivy vulnerability check*: *${{ matrix.image-trivy.status }}*\n${{ matrix.image-trivy.summary }}\n" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Image Docker Scout vulnerability check*: *${{ matrix.image-docker-scout.status }}*\n${{ matrix.image-docker-scout.summary }}\n" } } ] } ] } env: SLACK_WEBHOOK_URL: ${{ secrets.SECURITY_SLACK_WEBHOOK_URL }} SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK