To raise the security awareness of our development team, we've integrated a mechanism into our CI using GitHub Actions to conduct security scans on Docker images and automatically add those results as comments to pull requests (PRs).
Overview of the scan-and-comment
Job
This job automates a series of steps: checking out the code, building the Docker image, performing the security scan, formatting the results, and finally, posting comments to the PR. We use Trivy for scanning vulnerabilities in Docker images. More details about Trivy can be found in a separate article.
Read about Trivy's vulnerability scanning
Details of the scan-and-comment
Job
Below is the complete CI workflow after adding the scan-and-comment
job:
name: backend-ci
on:
push:
branches:
- main
- staging
- develop
pull_request:
types:
- opened
paths:
- "backend/**"
workflow_dispatch: # For manual execution
jobs:
setup:
# Details omitted for brevity
test:
# Details omitted for brevity
lint:
# Details omitted for brevity
tsc:
# Details omitted for brevity
scan-and-comment:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' && github.event.action == 'opened'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker Image
run: docker build --build-arg ENV=prod -t local-image:latest -f ./backend/Dockerfile.ecs ./backend
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@0.24.0
with:
image-ref: local-image:latest
format: "table"
severity: "CRITICAL,HIGH"
output: trivy-result.txt
- name: Check Trivy result file
run: cat trivy-result.txt
- name: Format Trivy Scan Result
run: |
if [ -s trivy-result.txt ]; then
echo -e "## Vulnerability Scan Results\n<details><summary>Details</summary>\n\n\`\`\`\n$(cat trivy-result.txt)\n\`\`\`\n</details>" > formatted-trivy-result.md
else
echo -e "## Vulnerability Scan Results\nNo vulnerabilities were detected." > formatted-trivy-result.md
fi
- name: Comment PR with Trivy scan results
uses: marocchino/sticky-pull-request-comment@v2
with:
path: formatted-trivy-result.md
- name: Clean up Trivy result file
run: rm -f trivy-result.txt formatted-trivy-result.md
1. Code Checkout
This job is executed only when a PR is newly created (if: github.event_name == 'pull_request' && github.event.action == 'opened'
), ensuring that it does not trigger on syncs or reopens.
scan-and-comment:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' && github.event.action == 'opened'
steps:
- name: Checkout code
uses: actions/checkout@v4
2. Docker Image Build
The Docker image is built using the same settings as the production environment, enhancing the precision of the security scans.
- name: Build Docker Image
run: docker build --build-arg ENV=prod -t local-image:latest -f ./backend/Dockerfile.ecs ./backend
Below is the Dockerfile
used for the build. It's configured for production builds, specifying the ENV=prod
parameter to improve security scan accuracy.
FROM node:20.15.0 AS builder
WORKDIR /app
COPY package*.json ./
COPY yarn.lock ./
# Install dependencies ignoring Husky
# Do not use production mode here for yarn build
RUN yarn install --frozen-lockfile --ignore-scripts
COPY . .
RUN yarn build
ARG ENV
# If staging or production environment, remove node_modules and reinstall in production mode
RUN if [ "$ENV" = "prod" ] || [ "$ENV" = "stg" ]; then \
rm -rf node_modules && yarn install --frozen-lockfile --ignore-scripts --production; \
fi
FROM node:20.15.0-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
EXPOSE 8080
CMD ["node", "dist/main"]
3. Image Scan with Trivy
Trivy is used to perform the security scan, and the results are saved in a text file.
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@0.24.0
with:
image-ref: local-image:latest
format: "table"
severity: "CRITICAL,HIGH"
output: trivy-result.txt
- name: Check Trivy result file
run: cat trivy-result.txt
https://github.com/aquasecurity/trivy-action/tree/master/
4. Format Trivy Scan Results
Based on the scan results, a detailed comment format is created.
- name: Format Trivy Scan Result
run: |
if [ -s trivy-result.txt ]; then
echo -e "## Vulnerability Scan Results\n<details><summary>Details</summary>\n\n```\n$(cat trivy-result.txt)\n```\n</details>" > formatted-trivy-result.md
else
echo -e "## Vulnerability Scan Results\nNo vulnerabilities were detected." > formatted-trivy-result.md
fi
- Comment on PR with Trivy Scan Results
The formatted scan results are posted as a comment on the PR.
- name: Comment PR with Trivy scan results
uses: marocchino/sticky-pull-request-comment@v2
with:
path: formatted-trivy-result.md
- Cleanup
Finally, the used files are deleted to maintain a clean environment.
- name: Clean up Trivy result file
run: rm -f trivy-result.txt formatted-trivy-result.md
Conclusion
In conclusion, integrating the scan-and-comment
job within our CI pipeline using GitHub Actions enhances our security posture by ensuring Docker images are scanned for vulnerabilities at every critical PR juncture. This automation not only streamlines our security checks but also fosters an environment where security consciousness is an integral part of the development process, maintaining high standards across all deployments.
Top comments (0)