diff --git a/.github/failed-vuln-check.md b/.github/failed-vuln-check.md new file mode 100644 index 0000000..65ac1d3 --- /dev/null +++ b/.github/failed-vuln-check.md @@ -0,0 +1,12 @@ +--- +title: Container Vulnerability Scanner Failed +labels: dls-work-cycle, security +--- +Trivy Vulnerability Scan failed. + +URL: {{ env.WORKFLOW_URL }} +Output: + +``` +{{ env.SCANNER_OUTPUTS }} +``` diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml new file mode 100644 index 0000000..fb0dc1a --- /dev/null +++ b/.github/workflows/build-docker-image.yml @@ -0,0 +1,150 @@ +name: Create and publish a Docker image +permissions: + issues: write + pull-requests: write + discussions: write + +on: + push: + branches: + - main + pull_request: + branches: + - main + +# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. +jobs: + build-and-push-image: + runs-on: ubuntu-latest + # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. + permissions: + contents: read + packages: write + # + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=sha + env: + DOCKER_METADATA_PR_HEAD_SHA: true + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. + - name: Build and push Docker image + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + file: Dockerfile + container-vuln-scan: + needs: build-and-push-image + runs-on: ubuntu-latest + if: + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=sha + env: + DOCKER_METADATA_PR_HEAD_SHA: true + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@0.20.0 + id: runscanner + continue-on-error: true + env: + TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2 + with: + image-ref: 'ghcr.io/pulibrary/abid:${{ steps.meta.outputs.version }}' + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os' + severity: 'CRITICAL,HIGH' + output: 'vulnerabilities.table' + - name: Set variables + id: scanner + if: ${{ always() }} + run: | + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + echo "results<<$EOF" >> $GITHUB_OUTPUT + echo "$(cat vulnerabilities.table)" >> $GITHUB_OUTPUT + echo "$EOF" >> $GITHUB_OUTPUT + - name: Output variable + if: ${{ always() }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: echo "${{ steps.scanner.outputs.results }}" + - name: Find Comment for scan + if: github.event_name == 'pull_request' + uses: peter-evans/find-comment@v3 + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: 'Container Scanning Status: ' + - name: Create or update comment + if: github.event_name == 'pull_request' + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: | + ## Container Scanning Status: ${{ steps.runscanner.outcome != 'success' && '❌ Failure' || '✅ Success' }} + ``` + ${{ steps.scanner.outputs.results }} + ``` + edit-mode: replace + - name: Create issue + if: steps.runscanner.outcome != 'success' && github.event_name != 'pull_request' + uses: JasonEtco/create-an-issue@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + SCANNER_OUTPUTS: ${{ steps.scanner.outputs.results }} + with: + filename: .github/failed-vuln-check.md + update_existing: true + - name: Find existing security issue + id: issues + if: steps.runscanner.outcome == 'success' && github.event_name != 'pull_request' + uses: lee-dohm/select-matching-issues@v1 + with: + query: 'Container Vulnerability Scanner Failed is:open ' + token: ${{ secrets.GITHUB_TOKEN }} + - name: Close found issues + continue-on-error: true + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: steps.runscanner.outcome == 'success' && github.event_name != 'pull_request' + run: cat ${{ steps.issues.outputs.path }} | xargs gh issue close -c 'Container Scan Passing on Merge to Main' diff --git a/.github/workflows/nightly-vuln-scanning.yml b/.github/workflows/nightly-vuln-scanning.yml new file mode 100644 index 0000000..4b2b680 --- /dev/null +++ b/.github/workflows/nightly-vuln-scanning.yml @@ -0,0 +1,73 @@ +name: Run nightly vulnerability check +permissions: + issues: write + pull-requests: write + discussions: write + +on: + schedule: + - cron: '0 0 * * *' + +# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. +jobs: + container-vuln-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@0.20.0 + id: runscanner + continue-on-error: true + env: + TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2 + with: + image-ref: 'ghcr.io/pulibrary/imagecat-rails:main' + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os' + severity: 'CRITICAL,HIGH' + output: 'vulnerabilities.table' + - name: Set variables + id: scanner + if: job.steps.runscanner.status == failure() + run: | + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + echo "results<<$EOF" >> $GITHUB_OUTPUT + echo "$(cat vulnerabilities.table)" >> $GITHUB_OUTPUT + echo "$EOF" >> $GITHUB_OUTPUT + - name: Output variable + if: job.steps.runscanner.status == failure() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: echo "${{ steps.scanner.outputs.results }}" + - name: Create issue + if: steps.runscanner.outcome != 'success' + uses: JasonEtco/create-an-issue@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + SCANNER_OUTPUTS: ${{ steps.scanner.outputs.results }} + with: + filename: .github/failed-vuln-check.md + update_existing: true + - name: Find existing security issue + id: issues + if: steps.runscanner.outcome == 'success' + uses: lee-dohm/select-matching-issues@v1 + with: + query: 'Container Vulnerability Scanner Failed is:open ' + token: ${{ secrets.GITHUB_TOKEN }} + - name: Close found issues + continue-on-error: true + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: steps.runscanner.outcome == 'success' + run: cat ${{ steps.issues.outputs.path }} | xargs gh issue close -c 'Container Scan Passing on Merge to Main'