Skip to content

Commit 92b3325

Browse files
committed
refactor: [#251] apply security-first workflow philosophy with exit-code 0
1 parent 7ff69be commit 92b3325

File tree

2 files changed

+123
-102
lines changed

2 files changed

+123
-102
lines changed

.github/workflows/docker-security-scan.yml

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,24 @@ name: Docker Security Scan
22

33
on:
44
push:
5-
branches:
6-
- main
7-
- develop
5+
branches: [main, develop]
86
paths:
97
- "docker/**"
108
- "templates/docker-compose/**"
119
- ".github/workflows/docker-security-scan.yml"
10+
1211
pull_request:
1312
paths:
1413
- "docker/**"
1514
- "templates/docker-compose/**"
1615
- ".github/workflows/docker-security-scan.yml"
16+
17+
# Scheduled scans are important because new CVEs appear
18+
# even if the code or images didn’t change
1719
schedule:
1820
- cron: "0 6 * * *" # Daily at 6 AM UTC
19-
workflow_dispatch: # Allow manual triggering
21+
22+
workflow_dispatch:
2023

2124
jobs:
2225
scan-project-images:
@@ -25,6 +28,7 @@ jobs:
2528
timeout-minutes: 15
2629
permissions:
2730
contents: read
31+
2832
strategy:
2933
fail-fast: false
3034
matrix:
@@ -35,42 +39,52 @@ jobs:
3539
- dockerfile: docker/ssh-server/Dockerfile
3640
context: docker/ssh-server
3741
name: ssh-server
42+
3843
steps:
3944
- name: Checkout code
4045
uses: actions/checkout@v4
4146

47+
# Build images locally so Trivy scans exactly
48+
# what this repository produces
4249
- name: Build Docker image
4350
run: |
44-
docker build -t torrust-tracker-deployer/${{ matrix.image.name }}:latest \
51+
docker build \
52+
-t torrust-tracker-deployer/${{ matrix.image.name }}:latest \
4553
-f ${{ matrix.image.dockerfile }} \
4654
.
4755
56+
# Human-readable output in logs
57+
# This NEVER fails the job; it’s only for visibility
4858
- name: Display vulnerabilities (table format)
4959
uses: aquasecurity/[email protected]
5060
with:
5161
image-ref: torrust-tracker-deployer/${{ matrix.image.name }}:latest
5262
format: "table"
5363
severity: "HIGH,CRITICAL"
54-
exit-code: "0" # Don't fail here, just display
64+
exit-code: "0"
5565

56-
- name: Run Trivy vulnerability scanner
66+
# SARIF generation for GitHub Code Scanning
67+
#
68+
# IMPORTANT:
69+
# - exit-code MUST be 0
70+
# - Trivy sometimes exits with 1 even when no vulns exist
71+
# - GitHub Security UI is responsible for enforcement
72+
- name: Generate SARIF (Code Scanning)
5773
uses: aquasecurity/[email protected]
58-
continue-on-error: true
59-
id: trivy-scan
6074
with:
6175
image-ref: torrust-tracker-deployer/${{ matrix.image.name }}:latest
6276
format: "sarif"
63-
output: "trivy-results-${{ matrix.image.name }}.sarif"
77+
output: "trivy-${{ matrix.image.name }}.sarif"
6478
severity: "HIGH,CRITICAL"
65-
exit-code: "1"
66-
scanners: "vuln" # Only vulnerabilities, skip secrets (test containers have legitimate SSH keys)
79+
exit-code: "0"
80+
scanners: "vuln"
6781

6882
- name: Upload SARIF artifact
6983
uses: actions/upload-artifact@v4
7084
if: always()
7185
with:
7286
name: sarif-project-${{ matrix.image.name }}-${{ github.run_id }}
73-
path: "trivy-results-${{ matrix.image.name }}.sarif"
87+
path: trivy-${{ matrix.image.name }}.sarif
7488
retention-days: 30
7589

7690
scan-third-party-images:
@@ -79,82 +93,88 @@ jobs:
7993
timeout-minutes: 15
8094
permissions:
8195
contents: read
96+
8297
strategy:
8398
fail-fast: false
8499
matrix:
85-
# NOTE: These images must match the ones used in templates/docker-compose/docker-compose.yml.tera
86-
# TODO: Automate image detection from docker-compose templates - see https://github.com/torrust/torrust-tracker-deployer/issues/252
100+
# These must match docker-compose templates
101+
# in templates/docker-compose/docker-compose.yml.tera
87102
image:
88103
- torrust/tracker:develop
89104
- mysql:8.0
90105
- grafana/grafana:11.4.0
91106
- prom/prometheus:v3.0.1
107+
92108
steps:
93109
- name: Display vulnerabilities (table format)
94110
uses: aquasecurity/[email protected]
95111
with:
96112
image-ref: ${{ matrix.image }}
97113
format: "table"
98114
severity: "HIGH,CRITICAL"
99-
exit-code: "0" # Don't fail here, just display
115+
exit-code: "0"
100116

101-
- name: Run Trivy vulnerability scanner
117+
# Third-party images should NEVER block CI.
118+
# We only report findings to GitHub Security.
119+
- name: Generate SARIF (Code Scanning)
102120
uses: aquasecurity/[email protected]
103-
continue-on-error: true
104-
id: trivy-scan
105121
with:
106122
image-ref: ${{ matrix.image }}
107123
format: "sarif"
108-
output: "trivy-results.sarif"
124+
output: "trivy.sarif"
109125
severity: "HIGH,CRITICAL"
110-
exit-code: "1"
111-
scanners: "vuln" # Focus on CVEs, not secrets
126+
exit-code: "0"
127+
scanners: "vuln"
112128

113-
- name: Sanitize image name for artifact
129+
# Needed to produce stable artifact names
130+
- name: Sanitize image name
114131
id: sanitize
115-
run: echo "name=$(echo '${{ matrix.image }}' | tr '/:' '-')" >> $GITHUB_OUTPUT
132+
run: |
133+
echo "name=$(echo '${{ matrix.image }}' | tr '/:' '-')" >> "$GITHUB_OUTPUT"
116134
117135
- name: Upload SARIF artifact
118136
uses: actions/upload-artifact@v4
119137
if: always()
120138
with:
121139
name: sarif-third-party-${{ steps.sanitize.outputs.name }}-${{ github.run_id }}
122-
path: "trivy-results.sarif"
140+
path: trivy.sarif
123141
retention-days: 30
124142

125143
upload-sarif-results:
126144
name: Upload SARIF Results to GitHub Security
127145
runs-on: ubuntu-latest
128-
needs: [scan-project-images, scan-third-party-images]
146+
needs:
147+
- scan-project-images
148+
- scan-third-party-images
149+
150+
# Always run so we don’t lose security visibility
129151
if: always()
152+
130153
permissions:
131154
security-events: write
155+
132156
steps:
133157
- name: Download all SARIF artifacts
134158
uses: actions/download-artifact@v4
135159
with:
136160
pattern: sarif-*-${{ github.run_id }}
137-
merge-multiple: false
138161

139-
- name: Upload SARIF files to GitHub Security
162+
# We use gh CLI because it’s easier to loop
163+
# and assign stable categories per image
164+
- name: Upload SARIF files
165+
env:
166+
GH_TOKEN: ${{ github.token }}
140167
run: |
141-
# Upload each SARIF file with a unique category
142-
find . -name "*.sarif" -type f | while read -r sarif_file; do
143-
# Extract image name from directory path for category
144-
category=$(basename $(dirname "$sarif_file") | sed 's/^sarif-//' | sed 's/-[0-9]*$//')
145-
echo "Uploading $sarif_file with category: docker-$category"
146-
147-
# Use gh CLI to upload SARIF (simpler than action in loop)
148-
cat "$sarif_file" | gh api \
168+
find . -name "*.sarif" -type f | while read -r sarif; do
169+
category=$(basename "$(dirname "$sarif")" | sed 's/^sarif-//' | sed 's/-[0-9]*$//')
170+
echo "Uploading $sarif as docker-$category"
171+
172+
gh api \
149173
--method POST \
150174
-H "Accept: application/vnd.github+json" \
151-
-H "X-GitHub-Api-Version: 2022-11-28" \
152175
/repos/${{ github.repository }}/code-scanning/sarifs \
153-
-f sarif=@- \
176+
-f sarif=@-"$sarif" \
154177
-f ref="${{ github.ref }}" \
155178
-f commit_sha="${{ github.sha }}" \
156-
-f checkout_uri="${{ github.server_url }}/${{ github.repository }}" \
157-
-f category="docker-$category" || echo "Failed to upload $sarif_file"
179+
-f category="docker-$category" || echo "Upload failed for $sarif"
158180
done
159-
env:
160-
GH_TOKEN: ${{ github.token }}

0 commit comments

Comments
 (0)