11
11
# • Scans the image for CRITICAL/HIGH CVEs with Trivy
12
12
# • Uploads Hadolint, Dockle and Trivy results as SARIF files
13
13
# • Pushes the image to GitHub Container Registry (GHCR)
14
- # • Signs + attests the image with Cosign **key-less (OIDC)**
14
+ # • Signs & attests the image with Cosign **key-less (OIDC)**
15
15
#
16
16
# Triggers:
17
17
# • Every push / PR to `main`
26
26
pull_request :
27
27
branches : [ "main" ]
28
28
schedule :
29
- - cron : ' 17 18 * * 2' # every Tuesday @ 18:17 UTC
29
+ - cron : ' 17 18 * * 2' # Tuesday @ 18:17 UTC
30
30
31
31
# -----------------------------------------------------------------
32
32
# GitHub permission scopes for this job
33
33
# -----------------------------------------------------------------
34
34
permissions :
35
35
contents : read
36
- packages : write
37
- security-events : write
38
- actions : read
36
+ packages : write # push to ghcr.io with built-in GITHUB_TOKEN
37
+ security-events : write # upload SARIF to “Code-scanning alerts”
38
+ actions : read # needed by upload-sarif in private repos
39
39
40
40
jobs :
41
41
build-scan-sign :
@@ -57,14 +57,13 @@ jobs:
57
57
# -------------------------------------------------------------
58
58
- name : 🔍 Dockerfile lint (Hadolint)
59
59
id : hadolint
60
- continue-on-error : true # capture result; fail later
60
+ continue-on-error : true # still upload SARIF on failure
61
61
run : |
62
- set -e
63
62
curl -sSL https://github.com/hadolint/hadolint/releases/latest/download/hadolint-Linux-x86_64 -o /usr/local/bin/hadolint
64
63
chmod +x /usr/local/bin/hadolint
65
- # Run lint; exit code >0 on rule violations
66
64
hadolint -f sarif Containerfile.lite > hadolint-results.sarif
67
65
echo "HADOLINT_EXIT=$?" >> "$GITHUB_ENV"
66
+ exit 0 # ensure step reports success
68
67
69
68
- name : ☁️ Upload Hadolint SARIF
70
69
if : always()
@@ -82,23 +81,24 @@ jobs:
82
81
uses : actions/cache@v4
83
82
with :
84
83
path : ${{ env.CACHE_DIR }}
85
- key : ${{ runner.os }}-buildx-${{ github.sha }}
86
- restore-keys : |
87
- ${{ runner.os }}-buildx-
84
+ key : ${{ runner.os }}-buildx-${{ github.sha }}
85
+ restore-keys : ${{ runner.os }}-buildx-
88
86
89
87
# -------------------------------------------------------------
90
88
# 3️⃣ Build & tag image (timestamp + latest)
91
89
# -------------------------------------------------------------
92
90
- name : 🏗️ Build Docker image
93
91
run : |
94
92
TAG=$(date +%s)
93
+ echo "TAG=$TAG" >> "$GITHUB_ENV" # reuse in push step
95
94
docker buildx build \
96
95
--file Containerfile.lite \
97
96
--tag $IMAGE_NAME:$TAG \
98
97
--tag $IMAGE_NAME:latest \
99
98
--cache-from type=local,src=${{ env.CACHE_DIR }} \
100
99
--cache-to type=local,dest=${{ env.CACHE_DIR }},mode=max \
101
- --load
100
+ --load \
101
+ . # build context is mandatory
102
102
103
103
# -------------------------------------------------------------
104
104
# 4️⃣ Image lint (Dockle CLI → SARIF)
@@ -109,14 +109,14 @@ jobs:
109
109
env :
110
110
DOCKLE_VERSION : 0.4.15
111
111
run : |
112
- set -e
113
112
curl -sSL "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.tar.gz" \
114
113
| tar -xz -C /usr/local/bin dockle
115
114
dockle --exit-code 1 \
116
- --format sarif \
117
- --output dockle-results.sarif \
118
- $IMAGE_NAME:latest || true
115
+ --format sarif \
116
+ --output dockle-results.sarif \
117
+ $IMAGE_NAME:latest
119
118
echo "DOCKLE_EXIT=$?" >> "$GITHUB_ENV"
119
+ exit 0
120
120
121
121
- name : ☁️ Upload Dockle SARIF
122
122
if : always()
@@ -138,23 +138,23 @@ jobs:
138
138
# -------------------------------------------------------------
139
139
- name : 🛡️ Trivy vulnerability scan
140
140
id : trivy
141
- continue-on-error : true # let the job continue even if Trivy exits 1
141
+ continue-on-error : true # allow SARIF upload
142
142
uses : aquasecurity/trivy-action@7b7aa264d83dc58691451798b4d117d53d21edfe
143
143
with :
144
144
image-ref : ${{ env.IMAGE_NAME }}:latest
145
- format : sarif # Trivy can emit SARIF directly
145
+ format : sarif
146
146
output : trivy-results.sarif
147
147
severity : CRITICAL,HIGH
148
- exit-code : 1 # non-zero when CRITICAL/HIGH vulns found
149
-
148
+ exit-code : 1 # non-zero on vulns
149
+
150
150
- name : ☁️ Upload Trivy SARIF
151
151
if : always()
152
152
uses : github/codeql-action/upload-sarif@v3
153
153
with :
154
154
sarif_file : trivy-results.sarif
155
155
156
156
# -------------------------------------------------------------
157
- # 7️⃣ Push both tags to GHCR (using built-in GITHUB_TOKEN)
157
+ # 7️⃣ Push both tags to GHCR (built-in GITHUB_TOKEN)
158
158
# -------------------------------------------------------------
159
159
- name : 🔑 Log in to GHCR
160
160
uses : docker/login-action@v3
@@ -165,8 +165,7 @@ jobs:
165
165
166
166
- name : 🚀 Push image to GHCR
167
167
run : |
168
- TIMESTAMP_TAG=$(docker images --format '{{.Tag}}' $IMAGE_NAME | grep -v latest)
169
- docker push $IMAGE_NAME:$TIMESTAMP_TAG
168
+ docker push $IMAGE_NAME:${{ env.TAG }}
170
169
docker push $IMAGE_NAME:latest
171
170
172
171
# -------------------------------------------------------------
@@ -177,17 +176,21 @@ jobs:
177
176
178
177
- name : 🔏 Sign & attest image
179
178
env :
180
- COSIGN_EXPERIMENTAL : " 1" # enable key-less OIDC flow
179
+ COSIGN_EXPERIMENTAL : " 1" # enable OIDC flow
181
180
run : |
182
181
cosign sign --yes $IMAGE_NAME:latest
183
182
cosign attest --yes --predicate sbom.spdx.json $IMAGE_NAME:latest
184
183
185
184
# -------------------------------------------------------------
186
- # 9️⃣ Fail job if any linter exit codes captured non-zero
185
+ # 9️⃣ Single gate – fail job on any scanner error
187
186
# -------------------------------------------------------------
188
- - name : ⛔ Enforce lint gates
189
- if : ${{ env.HADOLINT_EXIT != '0' || env.DOCKLE_EXIT != '0' }}
187
+ - name : ⛔ Enforce lint & vuln gates
188
+ if : |
189
+ env.HADOLINT_EXIT != '0' ||
190
+ env.DOCKLE_EXIT != '0' ||
191
+ steps.trivy.outcome == 'failure'
190
192
run : |
191
193
echo "Hadolint exit: $HADOLINT_EXIT"
192
194
echo "Dockle exit: $DOCKLE_EXIT"
195
+ echo "Trivy status: ${{ steps.trivy.outcome }}"
193
196
exit 1
0 commit comments