chore: harden webapp docker image (#3845)
Hardens the webapp Docker image and adds a CVE scan of each published image. - Base image `bullseye-slim` → `bookworm-slim` (Debian 12), pinned by digest. Adds `apt-get upgrade` + `--no-install-recommends` + apt-cache cleanup across the build stages so OS packages are patched at build time. - Moves the `react-email` CLI to `devDependencies` in `internal-packages/emails` — only the `email dev` preview script uses it; the runtime render path is `@react-email/render` + `@react-email/components`. This also drops the bundled `esbuild` binary from the production image. - Bumps `goose` v3.26.0 → v3.27.1 and its Go builder image 1.23 → 1.26. - Adds a reusable Trivy image-scan workflow wired into `publish.yml`, so every published image (main builds and releases) is scanned for OS-package CVEs right after it's pushed to GHCR. Report-only (writes to the run summary), runs alongside the worker publishes so it never blocks a deploy. Verified locally: the image builds clean on the new base, and `@react-email/render` carries no `esbuild` dependency so email rendering is unaffected.
This commit is contained in:
@@ -14,6 +14,13 @@ on:
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
outputs:
|
||||
version:
|
||||
description: The published image tag
|
||||
value: ${{ jobs.publish.outputs.version }}
|
||||
short_sha:
|
||||
description: Short commit SHA of the published build
|
||||
value: ${{ jobs.publish.outputs.short_sha }}
|
||||
secrets:
|
||||
SENTRY_AUTH_TOKEN:
|
||||
required: false
|
||||
|
||||
@@ -96,3 +96,14 @@ jobs:
|
||||
uses: ./.github/workflows/publish-worker-v4.yml
|
||||
with:
|
||||
image_tag: ${{ inputs.image_tag }}
|
||||
|
||||
# OS-level CVE scan of the image just published above. Report-only (writes to
|
||||
# the run summary); runs alongside the worker publishes and never blocks them.
|
||||
scan-webapp:
|
||||
needs: [publish-webapp]
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read # pull the just-published image from GHCR
|
||||
uses: ./.github/workflows/trivy-image-webapp.yml
|
||||
with:
|
||||
image-ref: ghcr.io/triggerdotdev/trigger.dev:${{ needs.publish-webapp.outputs.version }}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
name: Trivy Image Scan (webapp)
|
||||
|
||||
# OS-level CVE scan of a published webapp image. Called by the publish pipeline
|
||||
# (publish.yml) to scan each build right after it's pushed to GHCR — so every
|
||||
# main build and every release is scanned, not rebuilt. Also runnable ad-hoc
|
||||
# via workflow_dispatch against any image ref.
|
||||
#
|
||||
# Report-only: writes a table to the run summary. No SARIF upload, no gate.
|
||||
# Library/dependency CVEs are covered by Dependabot, so this is restricted to
|
||||
# OS packages (`vuln-type: os`) to avoid double-reporting.
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
image-ref:
|
||||
description: "Full image ref to scan (e.g. ghcr.io/triggerdotdev/trigger.dev:main)"
|
||||
type: string
|
||||
required: true
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
image-ref:
|
||||
description: "Full image ref to scan"
|
||||
type: string
|
||||
required: false
|
||||
default: "ghcr.io/triggerdotdev/trigger.dev:main"
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: trivy-image-webapp-${{ inputs.image-ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
name: Scan
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read # pull the image from GHCR
|
||||
steps:
|
||||
# Authenticate to GHCR so the scan also works for private images
|
||||
# (GITHUB_TOKEN isn't forwarded to Docker automatically). Harmless for
|
||||
# public images. Pairs with the packages: read permission above.
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Run Trivy image scan
|
||||
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
||||
with:
|
||||
scan-type: image
|
||||
image-ref: ${{ inputs.image-ref }}
|
||||
# vuln-type maps to --pkg-types: OS packages only (library deps are
|
||||
# Dependabot's job). ignore-unfixed drops vulns with no patch yet.
|
||||
vuln-type: os
|
||||
ignore-unfixed: true
|
||||
severity: HIGH,CRITICAL
|
||||
format: table
|
||||
output: trivy-image-webapp.txt
|
||||
|
||||
- name: Job summary
|
||||
if: always()
|
||||
env:
|
||||
IMAGE_REF: ${{ inputs.image-ref }}
|
||||
run: |
|
||||
{
|
||||
echo "## Trivy Image Scan (webapp) — \`${IMAGE_REF}\`"
|
||||
echo '```'
|
||||
# GitHub step summary is capped at 1 MiB; truncate large reports.
|
||||
head -c 900000 trivy-image-webapp.txt 2>/dev/null || echo "(no report produced)"
|
||||
echo '```'
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
Reference in New Issue
Block a user