Skip to content

Commit 6849aee

Browse files
committed
docker-image-job
Signed-off-by: Vipin Yadav <vipin.yadav@progress.com>
1 parent 83ce367 commit 6849aee

File tree

3 files changed

+211
-67
lines changed

3 files changed

+211
-67
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# build-docker-image.yml
2+
# Reusable workflow to build a Docker image and upload it as an artifact.
3+
# Supports three build strategies:
4+
# 1. build-docker.sh script (e.g., dsm-erchef)
5+
# 2. Makefile with compose-build target
6+
# 3. Standard docker build (fallback)
7+
#
8+
# The built image is saved as a tar and uploaded as a GitHub Actions artifact
9+
# for downstream jobs (e.g., Wiz CLI scan, Grype scan) to consume.
10+
11+
name: Build Docker image
12+
13+
on:
14+
workflow_call:
15+
outputs:
16+
image-names:
17+
description: 'Space-separated list of built Docker image names (repository:tag)'
18+
value: ${{ jobs.build.outputs.image-names }}
19+
20+
jobs:
21+
build:
22+
name: Build and upload Docker image
23+
runs-on: ubuntu-latest
24+
outputs:
25+
image-names: ${{ steps.build-image.outputs.IMAGES }}
26+
steps:
27+
- name: Checkout repository
28+
uses: actions/checkout@v6
29+
with:
30+
fetch-depth: 0
31+
32+
- name: Configure git for private repos
33+
run: git config --global url."https://${{ secrets.GH_TOKEN }}@github.com/".insteadOf "https://github.com/"
34+
35+
- name: Build Docker image
36+
id: build-image
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
39+
run: |
40+
if [ ! -f "Dockerfile" ]; then
41+
echo "❌ No Dockerfile found - cannot build"
42+
exit 1
43+
fi
44+
45+
echo "Building Docker image..."
46+
REPO_NAME=$(basename $(pwd))
47+
48+
# Strategy 1: Check for build-docker.sh script (e.g., dsm-erchef)
49+
if [ -f "build-docker.sh" ]; then
50+
echo "Found build-docker.sh script - using it to build images"
51+
chmod +x build-docker.sh
52+
GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" ./build-docker.sh
53+
54+
# Detect all images built (typically repo name or repo-name-init)
55+
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "^${REPO_NAME}" | grep -v "^<none>")
56+
57+
if [ -z "$IMAGES" ]; then
58+
echo "⚠️ No images found with prefix ${REPO_NAME} after build-docker.sh"
59+
echo "Checking for any recently built images..."
60+
IMAGES=$(docker images --format "{{.CreatedAt}}\t{{.Repository}}:{{.Tag}}" | sort -r | head -5 | cut -f2 | grep -v "^<none>")
61+
fi
62+
# Strategy 2: Check for Makefile with compose-build target (e.g., chef-platform-user-accounts-service)
63+
elif [ -f "Makefile" ] && grep -q "^compose-build:" Makefile; then
64+
echo "Using Makefile compose-build target with GITHUB_TOKEN"
65+
export GITHUB_TOKEN="${{ secrets.GH_TOKEN }}"
66+
make compose-build
67+
68+
echo "Detecting built images..."
69+
docker compose images
70+
71+
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^${REPO_NAME}" | grep -v "^<none>")
72+
73+
if [ -z "$IMAGES" ]; then
74+
echo "No images found with prefix ${REPO_NAME}, scanning all recent images"
75+
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "^<none>" | head -5)
76+
fi
77+
# Strategy 3: Fallback to standard docker build
78+
else
79+
echo "Using standard docker build with GITHUB_TOKEN build arg"
80+
docker build --build-arg GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" -t "${REPO_NAME}:latest" .
81+
IMAGES="${REPO_NAME}:latest"
82+
fi
83+
84+
if [ -z "$IMAGES" ]; then
85+
echo "❌ No Docker images found after build"
86+
exit 1
87+
fi
88+
89+
echo "Found images:"
90+
echo "$IMAGES"
91+
92+
# Output as space-separated list for downstream jobs
93+
echo "IMAGES=$(echo $IMAGES | tr '\n' ' ')" >> "$GITHUB_OUTPUT"
94+
95+
- name: Save Docker images to tar
96+
run: |
97+
IMAGES="${{ steps.build-image.outputs.IMAGES }}"
98+
echo "Saving images to /tmp/docker-image.tar: $IMAGES"
99+
docker save $IMAGES -o /tmp/docker-image.tar
100+
ls -lh /tmp/docker-image.tar
101+
102+
- name: Upload Docker image artifact
103+
uses: actions/upload-artifact@v4
104+
with:
105+
name: docker-image-for-scans
106+
path: /tmp/docker-image.tar
107+
retention-days: 1

.github/workflows/ci-main-pull-request.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1007,15 +1007,24 @@ jobs:
10071007
fail-grype-on-critical: ${{ inputs.grype-image-fail-on-critical }}
10081008
grype-image-skip-aws: ${{ inputs.grype-image-skip-aws }}
10091009

1010+
build-docker-image:
1011+
name: 'Build Docker image for security scans'
1012+
if: ${{ inputs.perform-wiz-scan == true }}
1013+
uses: chef/common-github-actions/.github/workflows/build-docker-image.yml@grype-wiz
1014+
needs: checkout
1015+
secrets: inherit
1016+
10101017
run-wiz-scan:
10111018
name: 'Wiz CLI security scan'
10121019
if: ${{ inputs.perform-wiz-scan == true }}
10131020
uses: chef/common-github-actions/.github/workflows/wiz.yml@grype-wiz
1014-
needs: checkout
1021+
needs: [checkout, build-docker-image]
10151022
with:
10161023
fail-build: ${{ inputs.wiz-fail-build }}
10171024
fail-on-critical: ${{ inputs.wiz-fail-on-critical }}
10181025
fail-on-high: ${{ inputs.wiz-fail-on-high }}
1026+
prebuilt-image-artifact: docker-image-for-scans
1027+
prebuilt-image-names: ${{ needs.build-docker-image.outputs.image-names }}
10191028
secrets: inherit
10201029

10211030
run-grype-hab-package-scan:

.github/workflows/wiz.yml

Lines changed: 94 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ on:
2424
required: false
2525
type: boolean
2626
default: false
27+
prebuilt-image-artifact:
28+
description: 'Name of uploaded artifact containing a Docker image tar (skip Docker build if provided)'
29+
required: false
30+
type: string
31+
default: ''
32+
prebuilt-image-names:
33+
description: 'Space-separated list of Docker image:tag names inside the prebuilt artifact tar'
34+
required: false
35+
type: string
36+
default: ''
2737

2838
jobs:
2939
wiz-scan:
@@ -55,8 +65,26 @@ jobs:
5565
# if: ${{ !inputs.wiz-image-skip-aws }}
5666
# uses: aws-actions/amazon-ecr-login@v2
5767

68+
- name: Download prebuilt Docker image
69+
if: ${{ inputs.prebuilt-image-artifact != '' }}
70+
uses: actions/download-artifact@v4
71+
with:
72+
name: ${{ inputs.prebuilt-image-artifact }}
73+
path: /tmp
74+
75+
- name: Load prebuilt Docker image
76+
id: load-image
77+
if: ${{ inputs.prebuilt-image-artifact != '' }}
78+
run: |
79+
echo "Loading prebuilt images from artifact..."
80+
docker load -i /tmp/docker-image.tar
81+
echo "IMAGES=${{ inputs.prebuilt-image-names }}" >> "$GITHUB_OUTPUT"
82+
echo "Loaded images: ${{ inputs.prebuilt-image-names }}"
83+
docker images
84+
5885
- name: Build Docker image
5986
id: build-image
87+
if: ${{ inputs.prebuilt-image-artifact == '' }}
6088
env:
6189
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
6290
run: |
@@ -74,60 +102,55 @@ jobs:
74102
chmod +x build-docker.sh
75103
GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" ./build-docker.sh
76104
77-
IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "^${REPO_NAME}" | grep -v "^<none>" | head -1)
105+
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "^${REPO_NAME}" | grep -v "^<none>")
78106
79-
if [ -z "$IMAGE" ]; then
80-
echo "⚠️ No image found with prefix ${REPO_NAME} after build-docker.sh"
107+
if [ -z "$IMAGES" ]; then
108+
echo "⚠️ No images found with prefix ${REPO_NAME} after build-docker.sh"
81109
echo "Checking for any recently built images..."
82-
IMAGE=$(docker images --format "{{.CreatedAt}}\t{{.Repository}}:{{.Tag}}" | sort -r | head -1 | cut -f2)
110+
IMAGES=$(docker images --format "{{.CreatedAt}}\t{{.Repository}}:{{.Tag}}" | sort -r | head -5 | cut -f2 | grep -v "^<none>")
83111
fi
84112
# Strategy 2: Check for Makefile with compose-build target
85113
elif [ -f "Makefile" ] && grep -q "^compose-build:" Makefile; then
86114
echo "Using Makefile compose-build target with GITHUB_TOKEN"
87115
export GITHUB_TOKEN="${{ secrets.GH_TOKEN }}"
88-
89-
# Record image IDs before build to detect newly built images
90-
BEFORE_IDS=$(docker images -q --no-trunc | sort)
91-
92116
make compose-build
93117
94-
echo "Detecting built image..."
95-
# Find newly created images by comparing before/after image IDs
96-
AFTER_IDS=$(docker images -q --no-trunc | sort)
97-
NEW_IDS=$(comm -13 <(echo "$BEFORE_IDS") <(echo "$AFTER_IDS"))
98-
99-
if [ -n "$NEW_IDS" ]; then
100-
for id in $NEW_IDS; do
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=""
105-
done
106-
fi
118+
echo "Detecting built images..."
119+
docker compose images
107120
108-
if [ -z "$IMAGE" ]; then
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
121+
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^${REPO_NAME}" | grep -v "^<none>")
112122
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)
123+
if [ -z "$IMAGES" ]; then
124+
echo "No images found with prefix ${REPO_NAME}, scanning all recent images"
125+
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "^<none>" | head -5)
116126
fi
117127
# Strategy 3: Fallback to standard docker build
118128
else
119129
echo "Using standard docker build with GITHUB_TOKEN build arg"
120130
docker build --build-arg GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" -t "${REPO_NAME}:latest" .
121-
IMAGE="${REPO_NAME}:latest"
131+
IMAGES="${REPO_NAME}:latest"
122132
fi
123133
124-
if [ -z "$IMAGE" ]; then
125-
echo "❌ No Docker image found after build"
134+
if [ -z "$IMAGES" ]; then
135+
echo "❌ No Docker images found after build"
126136
exit 1
127137
fi
128138
129-
echo "Image to scan: $IMAGE"
130-
echo "IMAGE=$IMAGE" >> "$GITHUB_OUTPUT"
139+
echo "Found images to scan:"
140+
echo "$IMAGES"
141+
echo "IMAGES=$(echo $IMAGES | tr '\n' ' ')" >> "$GITHUB_OUTPUT"
142+
143+
- name: Set scan target images
144+
id: scan-target
145+
run: |
146+
# Use prebuilt images if available, otherwise use freshly built images
147+
IMAGES="${{ steps.load-image.outputs.IMAGES || steps.build-image.outputs.IMAGES }}"
148+
if [ -z "$IMAGES" ]; then
149+
echo "❌ No Docker images available for scanning"
150+
exit 1
151+
fi
152+
echo "Scan targets: $IMAGES"
153+
echo "IMAGES=$IMAGES" >> "$GITHUB_OUTPUT"
131154
132155
- name: Fetch Wiz credentials from AKeyless
133156
id: fetch-secrets
@@ -150,50 +173,55 @@ jobs:
150173
run: |
151174
set -o pipefail
152175
153-
SCAN_TYPE='container-image'
154-
SCAN_TARGET='${{ steps.build-image.outputs.IMAGE }}'
176+
IMAGES='${{ steps.scan-target.outputs.IMAGES }}'
177+
SCAN_RESULT="passed"
155178
156-
args=("$SCAN_TYPE")
157-
if [ -n "$SCAN_TARGET" ]; then
158-
args+=("$SCAN_TARGET")
159-
fi
179+
# Initialize combined output files
180+
> /tmp/wiz-scan.json
181+
> /tmp/wiz-scan-results.txt
160182
161-
# Always output JSON for severity analysis
162-
args+=("--json-output-file" "/tmp/wiz-scan.json")
183+
for IMAGE_NAME in $IMAGES; do
184+
echo ""
185+
echo "============================================"
186+
echo "Scanning Docker image: $IMAGE_NAME"
187+
echo "============================================"
188+
189+
JSON_FILE="/tmp/wiz-scan-$(echo $IMAGE_NAME | tr '/:' '__').json"
190+
191+
./wizcli scan container-image "$IMAGE_NAME" --json-output-file "$JSON_FILE" 2>&1 | tee -a /tmp/wiz-scan-results.txt
192+
EXIT_CODE=${PIPESTATUS[0]}
163193
164-
./wizcli scan "${args[@]}" 2>&1 | tee /tmp/wiz-scan-results.txt
165-
EXIT_CODE=${PIPESTATUS[0]}
194+
# Append JSON result to combined file
195+
cat "$JSON_FILE" >> /tmp/wiz-scan.json 2>/dev/null || true
196+
197+
if [ $EXIT_CODE -ne 0 ]; then
198+
SCAN_RESULT="failed"
199+
fi
200+
done
166201
167202
echo ""
168203
echo "============================================"
169-
echo "Wiz CLI Scan Output"
170-
echo "============================================"
171-
cat /tmp/wiz-scan-results.txt
204+
echo "Wiz CLI Scan Complete - Result: $SCAN_RESULT"
172205
echo "============================================"
173-
echo ""
174206
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
207+
echo "scan-result=$SCAN_RESULT" >> $GITHUB_OUTPUT
208+
[ "$SCAN_RESULT" = "failed" ] && exit 1 || exit 0
181209
182210
- name: Check Wiz results for severity violations
183211
id: severity-check
184212
if: always()
185213
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")
214+
# Aggregate vulnerability counts across all per-image JSON files
215+
CRITICAL_COUNT=0
216+
HIGH_COUNT=0
217+
218+
for JSON_FILE in /tmp/wiz-scan-*.json; do
219+
[ -f "$JSON_FILE" ] || continue
220+
C=$(jq '.result.analytics.vulnerabilities.criticalCount // 0' "$JSON_FILE" 2>/dev/null || echo "0")
221+
H=$(jq '.result.analytics.vulnerabilities.highCount // 0' "$JSON_FILE" 2>/dev/null || echo "0")
222+
CRITICAL_COUNT=$((CRITICAL_COUNT + C))
223+
HIGH_COUNT=$((HIGH_COUNT + H))
224+
done
197225
198226
echo ""
199227
echo "============================================"
@@ -243,7 +271,7 @@ jobs:
243271
echo "| Field | Value |"
244272
echo "|-------|-------|"
245273
echo "| **Scan type** | \`container-image\` |"
246-
echo "| **Target** | \`${{ steps.build-image.outputs.IMAGE }}\` |"
274+
echo "| **Target(s)** | \`${{ steps.scan-target.outputs.IMAGES }}\` |"
247275
echo "| **Policy result** | **${SCAN_RESULT}** |"
248276
echo "| **Severity result** | **${SEVERITY_RESULT}** |"
249277
echo "| **Overall** | **${OVERALL}** |"
@@ -267,5 +295,5 @@ jobs:
267295
with:
268296
name: wiz-scan-${{ github.event.repository.name }}
269297
path: |
270-
/tmp/wiz-scan.json
298+
/tmp/wiz-scan*.json
271299
/tmp/wiz-scan-results.txt

0 commit comments

Comments
 (0)