1414 required : false
1515 type : boolean
1616 default : true
17- wiz-image-skip-aws :
18- description : ' Skip AWS ECR login (assumes images are scanned elsewhere)'
17+ fail-on-critical :
18+ description : ' Fail the build if Wiz finds CRITICAL vulnerabilities'
19+ required : false
20+ type : boolean
21+ default : false
22+ fail-on-high :
23+ description : ' Fail the build if Wiz finds HIGH vulnerabilities'
1924 required : false
2025 type : boolean
2126 default : false
@@ -55,14 +60,13 @@ jobs:
5560 env :
5661 GITHUB_TOKEN : ${{ secrets.GH_TOKEN }}
5762 run : |
58- REPO_NAME=$(basename $(pwd))
59-
6063 if [ ! -f "Dockerfile" ]; then
61- echo "❌ No Dockerfile found - this workflow requires a Dockerfile to scan Docker image "
64+ echo "❌ No Dockerfile found - cannot scan"
6265 exit 1
6366 fi
6467
6568 echo "Building Docker image..."
69+ REPO_NAME=$(basename $(pwd))
6670
6771 # Strategy 1: Check for build-docker.sh script (e.g., dsm-erchef)
6872 if [ -f "build-docker.sh" ]; then
@@ -94,14 +98,21 @@ jobs:
9498
9599 if [ -n "$NEW_IDS" ]; then
96100 for id in $NEW_IDS; do
97- IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" --filter "id=${id}" | grep -v "<none>" | head -1)
98- [ -n "$IMAGE" ] && break
101+ # Use docker inspect instead of --filter (compatible with all Docker versions)
102+ IMAGE=$(docker inspect --format '{{index .RepoTags 0}}' "$id" 2>/dev/null || true)
103+ [ -n "$IMAGE" ] && [ "$IMAGE" != "<none>:<none>" ] && break
104+ IMAGE=""
99105 done
100106 fi
101107
102108 if [ -z "$IMAGE" ]; then
103- echo "No new image detected, using most recent image"
104- IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "^<none>" | head -1)
109+ echo "No new image detected by ID comparison, falling back to repo name match"
110+ IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "^${REPO_NAME}" | grep -v "<none>" | head -1)
111+ fi
112+
113+ if [ -z "$IMAGE" ]; then
114+ echo "⚠️ No image found matching ${REPO_NAME}, using most recent non-runner image"
115+ IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "^<none>" | grep -v "^ghcr.io/github/" | grep -v "^ghcr.io/dependabot/" | head -1)
105116 fi
106117 # Strategy 3: Fallback to standard docker build
107118 else
@@ -118,10 +129,143 @@ jobs:
118129 echo "Image to scan: $IMAGE"
119130 echo "IMAGE=$IMAGE" >> "$GITHUB_OUTPUT"
120131
132+ - name : Fetch Wiz credentials from AKeyless
133+ id : fetch-secrets
134+ uses : LanceMcCarthy/akeyless-action@ca2424bb132118c0b907f38e6dae0475acc0fac4 # v5.2.1
135+ with :
136+ access-id : " p-5g555fgryzj2om"
137+ static-secrets : ' {"/ProductSecurity/Tools/WIZ_CLIENT_ID":"WIZ_CLIENT_ID","/ProductSecurity/Tools/WIZ_CLIENT_SECRET":"WIZ_CLIENT_SECRET"}'
138+
139+ - name : Download Wiz CLI
140+ run : |
141+ curl -fsSL -o wizcli https://downloads.wiz.io/v1/wizcli/latest/wizcli-linux-amd64
142+ chmod +x wizcli
143+
121144 - name : Wiz CLI container image scan
122145 id : wiz-scan
123- uses : prgs-community/githubactions-reusableworkflows/actions/wizcli@latest
146+ continue-on-error : true
147+ env :
148+ WIZ_CLIENT_ID : ${{ steps.fetch-secrets.outputs.WIZ_CLIENT_ID }}
149+ WIZ_CLIENT_SECRET : ${{ steps.fetch-secrets.outputs.WIZ_CLIENT_SECRET }}
150+ run : |
151+ set -o pipefail
152+
153+ SCAN_TYPE='container-image'
154+ SCAN_TARGET='${{ steps.build-image.outputs.IMAGE }}'
155+
156+ args=("$SCAN_TYPE")
157+ if [ -n "$SCAN_TARGET" ]; then
158+ args+=("$SCAN_TARGET")
159+ fi
160+
161+ # Always output JSON for severity analysis
162+ args+=("--json-output-file" "/tmp/wiz-scan.json")
163+
164+ ./wizcli scan "${args[@]}" 2>&1 | tee /tmp/wiz-scan-results.txt
165+ EXIT_CODE=${PIPESTATUS[0]}
166+
167+ echo ""
168+ echo "============================================"
169+ echo "Wiz CLI Scan Output"
170+ echo "============================================"
171+ cat /tmp/wiz-scan-results.txt
172+ echo "============================================"
173+ echo ""
174+
175+ if [ $EXIT_CODE -eq 0 ]; then
176+ echo "scan-result=passed" >> $GITHUB_OUTPUT
177+ else
178+ echo "scan-result=failed" >> $GITHUB_OUTPUT
179+ fi
180+ exit $EXIT_CODE
181+
182+ - name : Check Wiz results for severity violations
183+ id : severity-check
184+ if : always()
185+ run : |
186+ JSON_FILE="/tmp/wiz-scan.json"
187+
188+ if [ ! -f "$JSON_FILE" ]; then
189+ echo "⚠️ Wiz JSON output not found, skipping severity check"
190+ echo "severity-result=skipped" >> $GITHUB_OUTPUT
191+ exit 0
192+ fi
193+
194+ # Count vulnerabilities by severity from Wiz JSON analytics summary
195+ CRITICAL_COUNT=$(jq '.result.analytics.vulnerabilities.criticalCount // 0' "$JSON_FILE" 2>/dev/null || echo "0")
196+ HIGH_COUNT=$(jq '.result.analytics.vulnerabilities.highCount // 0' "$JSON_FILE" 2>/dev/null || echo "0")
197+
198+ echo ""
199+ echo "============================================"
200+ echo "Wiz Security Scan - Vulnerability Summary"
201+ echo "============================================"
202+ echo "CRITICAL vulnerabilities: $CRITICAL_COUNT"
203+ echo "HIGH vulnerabilities: $HIGH_COUNT"
204+ echo "============================================"
205+
206+ # Save counts for job summary
207+ echo "critical-count=$CRITICAL_COUNT" >> $GITHUB_OUTPUT
208+ echo "high-count=$HIGH_COUNT" >> $GITHUB_OUTPUT
209+
210+ VIOLATIONS=""
211+ [ "${{ inputs.fail-on-critical }}" == "true" ] && [ "$CRITICAL_COUNT" -gt 0 ] && VIOLATIONS="${VIOLATIONS}${CRITICAL_COUNT} CRITICAL, "
212+ [ "${{ inputs.fail-on-high }}" == "true" ] && [ "$HIGH_COUNT" -gt 0 ] && VIOLATIONS="${VIOLATIONS}${HIGH_COUNT} HIGH, "
213+
214+ if [ -n "$VIOLATIONS" ]; then
215+ echo ""
216+ echo "❌ BUILD FAILED: Found ${VIOLATIONS%, } vulnerabilities"
217+ echo "severity-result=failed" >> $GITHUB_OUTPUT
218+ exit 1
219+ else
220+ echo ""
221+ echo "✅ No severity-violating vulnerabilities found"
222+ echo "severity-result=passed" >> $GITHUB_OUTPUT
223+ fi
224+
225+ - name : Write Job Summary
226+ if : always()
227+ run : |
228+ SCAN_RESULT="${{ steps.wiz-scan.outputs.scan-result }}"
229+ SEVERITY_RESULT="${{ steps.severity-check.outputs.severity-result }}"
230+
231+ # Overall result: fail if either policy or severity check failed
232+ if [ "$SCAN_RESULT" = "passed" ] && [ "$SEVERITY_RESULT" != "failed" ]; then
233+ ICON="✅"
234+ OVERALL="passed"
235+ else
236+ ICON="❌"
237+ OVERALL="failed"
238+ fi
239+
240+ {
241+ echo "## ${ICON} Wiz CLI Scan Results"
242+ echo ""
243+ echo "| Field | Value |"
244+ echo "|-------|-------|"
245+ echo "| **Scan type** | \`container-image\` |"
246+ echo "| **Target** | \`${{ steps.build-image.outputs.IMAGE }}\` |"
247+ echo "| **Policy result** | **${SCAN_RESULT}** |"
248+ echo "| **Severity result** | **${SEVERITY_RESULT}** |"
249+ echo "| **Overall** | **${OVERALL}** |"
250+ echo ""
251+ echo "### Vulnerability Counts"
252+ echo ""
253+ echo "| Severity | Count | Fail on? |"
254+ echo "|----------|-------|----------|"
255+ echo "| CRITICAL | ${{ steps.severity-check.outputs.critical-count || '0' }} | ${{ inputs.fail-on-critical }} |"
256+ echo "| HIGH | ${{ steps.severity-check.outputs.high-count || '0' }} | ${{ inputs.fail-on-high }} |"
257+ echo ""
258+ echo "### Scan Output"
259+ echo '```'
260+ cat /tmp/wiz-scan-results.txt 2>/dev/null || echo "(no output captured)"
261+ echo '```'
262+ } >> "$GITHUB_STEP_SUMMARY"
263+
264+ - name : Upload Wiz scan results
265+ if : always()
266+ uses : actions/upload-artifact@v4
124267 with :
125- scan-type : ' container-image'
126- scan-target : ${{ steps.build-image.outputs.IMAGE }}
127- fail-build : ${{ inputs.fail-build }}
268+ name : wiz-scan-${{ github.event.repository.name }}
269+ path : |
270+ /tmp/wiz-scan.json
271+ /tmp/wiz-scan-results.txt
0 commit comments