Skip to content

Commit c8b4cfd

Browse files
NotYuShengclaude
andauthored
feat: add GHCR publish and Trivy image scan workflows (#185)
- publish-ghcr.yml: builds and pushes tracepcap-backend and tracepcap-nginx images to GHCR on push to main, release, or manual dispatch; tags with latest and latest-<sha> - trivy-scan.yml: manual-dispatch workflow that scans both images for CRITICAL/HIGH/MEDIUM unfixed CVEs; uploads SARIF to the GitHub Security tab and writes a table summary to the job summary Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 612b207 commit c8b4cfd

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

.github/workflows/publish-ghcr.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: Publish to GHCR
2+
3+
on:
4+
# Triggers minor version ( vX.Y.Z-ShortHash )
5+
push:
6+
branches:
7+
- main
8+
# Triggers major version ( vX.Y.Z )
9+
release:
10+
types: [created]
11+
12+
workflow_dispatch:
13+
14+
jobs:
15+
build-and-push:
16+
runs-on: ubuntu-latest
17+
permissions:
18+
contents: read
19+
packages: write
20+
21+
strategy:
22+
matrix:
23+
include:
24+
- name: tracepcap-backend
25+
context: ./backend
26+
dockerfile: ./backend/Dockerfile
27+
- name: tracepcap-nginx
28+
context: .
29+
dockerfile: ./nginx/Dockerfile
30+
31+
steps:
32+
- name: Checkout repository
33+
uses: actions/checkout@v4
34+
35+
- name: Set up Docker Buildx
36+
uses: docker/setup-buildx-action@v3
37+
38+
- name: Extract metadata
39+
id: meta
40+
run: |
41+
SHORT_SHA=$(git rev-parse --short HEAD)
42+
echo "SHORT_SHA=$SHORT_SHA" >> $GITHUB_ENV
43+
44+
# Convert repository owner to lowercase for Docker image naming
45+
REPO_OWNER_LOWER=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
46+
echo "REPO_OWNER_LOWER=$REPO_OWNER_LOWER" >> $GITHUB_ENV
47+
48+
# Use the input tag or default to 'latest'
49+
TAG="${{ github.event.inputs.tag }}"
50+
if [ -z "$TAG" ]; then
51+
TAG="latest"
52+
fi
53+
echo "IMAGE_TAG=$TAG" >> $GITHUB_ENV
54+
55+
# Also create a tag with the commit SHA
56+
echo "SHA_TAG=${TAG}-${SHORT_SHA}" >> $GITHUB_ENV
57+
58+
- name: Log in to GitHub Container Registry
59+
uses: docker/login-action@v3
60+
with:
61+
registry: ghcr.io
62+
username: ${{ github.actor }}
63+
password: ${{ secrets.GITHUB_TOKEN }}
64+
65+
- name: Build and push Docker image
66+
uses: docker/build-push-action@v5
67+
with:
68+
context: ${{ matrix.context }}
69+
file: ${{ matrix.dockerfile }}
70+
push: true
71+
platforms: linux/amd64
72+
tags: |
73+
ghcr.io/${{ env.REPO_OWNER_LOWER }}/${{ matrix.name }}:${{ env.IMAGE_TAG }}
74+
ghcr.io/${{ env.REPO_OWNER_LOWER }}/${{ matrix.name }}:${{ env.SHA_TAG }}
75+
cache-from: type=gha
76+
cache-to: type=gha,mode=max
77+
78+
- name: Log out of GitHub Container Registry
79+
if: always()
80+
run: docker logout ghcr.io

.github/workflows/trivy-scan.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Trivy Image Scan
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
image_tag:
7+
description: "Image tag to scan (default: latest)"
8+
required: false
9+
default: "latest"
10+
11+
jobs:
12+
scan:
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
16+
packages: read
17+
actions: read # required for SARIF upload in private repos
18+
security-events: write # required for SARIF upload to Security tab
19+
20+
strategy:
21+
matrix:
22+
include:
23+
- name: tracepcap-backend
24+
- name: tracepcap-nginx
25+
26+
steps:
27+
- name: Resolve image reference
28+
run: |
29+
REPO_OWNER_LOWER=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
30+
IMAGE="ghcr.io/${REPO_OWNER_LOWER}/${{ matrix.name }}:${{ github.event.inputs.image_tag }}"
31+
echo "IMAGE=$IMAGE" >> $GITHUB_ENV
32+
33+
- name: Log in to GitHub Container Registry
34+
uses: docker/login-action@v3
35+
with:
36+
registry: ghcr.io
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GITHUB_TOKEN }}
39+
40+
- name: Run Trivy scan (SARIF)
41+
# Note: severity filtering is ignored in SARIF mode — all severities are
42+
# included in the SARIF file; use the Security tab UI to filter by severity.
43+
uses: aquasecurity/trivy-action@v0.35.0
44+
with:
45+
image-ref: ${{ env.IMAGE }}
46+
format: sarif
47+
output: trivy-${{ matrix.name }}.sarif
48+
ignore-unfixed: true
49+
50+
- name: Upload SARIF to GitHub Security tab
51+
uses: github/codeql-action/upload-sarif@v4
52+
if: always()
53+
continue-on-error: true # silently skip if Advanced Security is not enabled
54+
with:
55+
sarif_file: trivy-${{ matrix.name }}.sarif
56+
category: trivy-${{ matrix.name }}
57+
58+
- name: Run Trivy scan (table summary)
59+
uses: aquasecurity/trivy-action@v0.35.0
60+
with:
61+
image-ref: ${{ env.IMAGE }}
62+
format: table
63+
output: trivy-${{ matrix.name }}-summary.txt
64+
severity: CRITICAL,HIGH,MEDIUM
65+
ignore-unfixed: true
66+
67+
- name: Write results to job summary
68+
if: always()
69+
run: |
70+
echo "## Trivy Scan — \`${{ matrix.name }}:${{ github.event.inputs.image_tag }}\`" >> $GITHUB_STEP_SUMMARY
71+
echo '```' >> $GITHUB_STEP_SUMMARY
72+
cat trivy-${{ matrix.name }}-summary.txt >> $GITHUB_STEP_SUMMARY
73+
echo '```' >> $GITHUB_STEP_SUMMARY
74+
75+
- name: Log out of GitHub Container Registry
76+
if: always()
77+
run: docker logout ghcr.io

0 commit comments

Comments
 (0)