diff --git a/.github/workflows/security-scans.yml b/.github/workflows/security-scans.yml index abd9607f..ad7649a6 100644 --- a/.github/workflows/security-scans.yml +++ b/.github/workflows/security-scans.yml @@ -70,20 +70,38 @@ jobs: fi exit $rc - container-scan: + image-scan: runs-on: ubuntu-latest timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + image: [backend, frontend] steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 with: persist-credentials: false # --pull so a cached base image cannot make the RUN layer a cache hit and - # silently skip the pinned security upgrade. - - run: docker build --pull --tag canary-backend:scan backend + # silently skip a pinned security upgrade. + - run: docker build --pull --tag canary-${{ matrix.image }}:scan ${{ matrix.image }} - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 with: - image-ref: canary-backend:scan + image-ref: canary-${{ matrix.image }}:scan format: table exit-code: '1' ignore-unfixed: true severity: CRITICAL,HIGH + + # The deployment gate requires a single check named container-scan. + container-scan: + needs: image-scan + if: always() + runs-on: ubuntu-latest + steps: + - env: + RESULT: ${{ needs.image-scan.result }} + run: | + if [ "$RESULT" != success ]; then + echo "::error::an image scan did not pass: $RESULT" + exit 1 + fi diff --git a/frontend/Dockerfile b/frontend/Dockerfile index dfafb401..42e95a69 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -39,6 +39,10 @@ ENV NODE_ENV=production RUN addgroup --system --gid 1001 nodejs && \ adduser --system --uid 1001 nextjs +# The base image's package managers never run here and bring their own vulnerable dependencies. +RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/lib/node_modules/corepack /opt/yarn-v* \ + /usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/corepack /usr/local/bin/yarn /usr/local/bin/yarnpkg + # Copy public assets COPY --from=builder /app/public ./public