Skip to content

Commit 1fb28c4

Browse files
authored
wiz cli CHEF-32378 (#39)
* fix: docker image detection for compose-build strategy in grype and wiz * test Signed-off-by: Vipin Yadav <vipin.yadav@progress.com> * wiz cli CHEF-32378 Signed-off-by: Vipin Yadav <vipin.yadav@progress.com> * changes for common docker build Signed-off-by: Vipin Yadav <vipin.yadav@progress.com> --------- Signed-off-by: Vipin Yadav <vipin.yadav@progress.com>
1 parent 60aba91 commit 1fb28c4

4 files changed

Lines changed: 526 additions & 14 deletions

File tree

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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+
inputs:
16+
skip-aws:
17+
description: 'Skip AWS ECR login (for repos that do not need ECR base images)'
18+
required: false
19+
type: boolean
20+
default: false
21+
outputs:
22+
image-names:
23+
description: 'Space-separated list of built Docker image names (repository:tag)'
24+
value: ${{ jobs.build.outputs.image-names }}
25+
26+
jobs:
27+
build:
28+
name: Build and upload Docker image
29+
runs-on: ubuntu-latest
30+
permissions:
31+
id-token: write
32+
contents: read
33+
outputs:
34+
image-names: ${{ steps.build-image.outputs.IMAGES }}
35+
steps:
36+
- name: Checkout repository
37+
uses: actions/checkout@v6
38+
with:
39+
fetch-depth: 0
40+
41+
- name: Configure git for private repos
42+
run: git config --global url."https://${{ secrets.GH_TOKEN }}@github.com/".insteadOf "https://github.com/"
43+
44+
- name: Configure AWS credentials
45+
uses: aws-actions/configure-aws-credentials@v4
46+
if: ${{ !inputs.skip-aws }}
47+
with:
48+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
49+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
50+
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
51+
aws-region: us-east-2
52+
53+
- name: Login to Amazon ECR
54+
id: login-ecr
55+
if: ${{ !inputs.skip-aws }}
56+
uses: aws-actions/amazon-ecr-login@v2
57+
58+
- name: Build Docker image
59+
id: build-image
60+
env:
61+
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
62+
run: |
63+
if [ ! -f "Dockerfile" ]; then
64+
echo "❌ No Dockerfile found - cannot build"
65+
exit 1
66+
fi
67+
68+
echo "Building Docker image..."
69+
REPO_NAME=$(basename $(pwd))
70+
71+
# Strategy 1: Check for build-docker.sh script (e.g., dsm-erchef)
72+
if [ -f "build-docker.sh" ]; then
73+
echo "Found build-docker.sh script - using it to build images"
74+
chmod +x build-docker.sh
75+
GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" ./build-docker.sh
76+
77+
# Detect all images built (typically repo name or repo-name-init)
78+
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "^${REPO_NAME}" | grep -v "^<none>")
79+
80+
if [ -z "$IMAGES" ]; then
81+
echo "⚠️ No images found with prefix ${REPO_NAME} after build-docker.sh"
82+
echo "Checking for any recently built images..."
83+
IMAGES=$(docker images --format "{{.CreatedAt}}\t{{.Repository}}:{{.Tag}}" | sort -r | head -5 | cut -f2 | grep -v "^<none>")
84+
fi
85+
# Strategy 2: Check for Makefile with compose-build target (e.g., chef-platform-user-accounts-service)
86+
elif [ -f "Makefile" ] && grep -q "^compose-build:" Makefile; then
87+
echo "Using Makefile compose-build target with GITHUB_TOKEN"
88+
export GITHUB_TOKEN="${{ secrets.GH_TOKEN }}"
89+
make compose-build
90+
91+
echo "Detecting built images..."
92+
# Get all image names from compose, then keep only ones that exist locally (i.e., were actually built)
93+
IMAGES=""
94+
for img in $(docker compose config --images 2>/dev/null | sort -u); do
95+
TAG_IMG=$(echo "$img" | grep -q ':' && echo "$img" || echo "${img}:latest")
96+
if docker image inspect "$TAG_IMG" &>/dev/null; then
97+
IMAGES="${IMAGES}${TAG_IMG} "
98+
fi
99+
done
100+
IMAGES=$(echo "$IMAGES" | xargs)
101+
102+
if [ -z "$IMAGES" ]; then
103+
echo "⚠️ Could not detect built images from compose config, falling back to repo name match"
104+
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^${REPO_NAME}" | grep -v "^<none>")
105+
fi
106+
# Strategy 3: Fallback to standard docker build
107+
else
108+
echo "Using standard docker build with GITHUB_TOKEN build arg"
109+
docker build --build-arg GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" -t "${REPO_NAME}:latest" .
110+
IMAGES="${REPO_NAME}:latest"
111+
fi
112+
113+
if [ -z "$IMAGES" ]; then
114+
echo "❌ No Docker images found after build"
115+
exit 1
116+
fi
117+
118+
echo "Found images:"
119+
echo "$IMAGES"
120+
121+
# Output as space-separated list for downstream jobs
122+
echo "IMAGES=$(echo $IMAGES | tr '\n' ' ')" >> "$GITHUB_OUTPUT"
123+
124+
- name: Save Docker images to tar
125+
run: |
126+
IMAGES="${{ steps.build-image.outputs.IMAGES }}"
127+
echo "Saving images to /tmp/docker-image.tar: $IMAGES"
128+
docker save $IMAGES -o /tmp/docker-image.tar
129+
ls -lh /tmp/docker-image.tar
130+
131+
- name: Upload Docker image artifact
132+
uses: actions/upload-artifact@v4
133+
with:
134+
name: docker-image-for-scans
135+
path: /tmp/docker-image.tar
136+
retention-days: 1

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

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ on:
156156
required: false
157157
type: boolean
158158
default: false
159-
grype-image-skip-aws:
160-
description: 'Skip Grype image scan on AWS ECR images to avoid rate limits (assumes these images are scanned with Amazon ECR scan or Trivy)'
159+
image-skip-aws:
160+
description: 'Skip AWS ECR login for Docker image scans (for repos that do not need ECR base images)'
161161
required: false
162162
type: boolean
163163
default: false
@@ -541,6 +541,26 @@ on:
541541
# required: false
542542
# default: 'https://polaris.blackduck.com'
543543
# type: string
544+
perform-wiz-scan:
545+
description: 'Perform Wiz CLI security scan on Docker image'
546+
required: false
547+
type: boolean
548+
default: false
549+
wiz-fail-build:
550+
description: 'Fail the build on Wiz policy violations'
551+
required: false
552+
type: boolean
553+
default: true
554+
wiz-fail-on-critical:
555+
description: 'Fail the pipeline if Wiz finds CRITICAL vulnerabilities'
556+
required: false
557+
type: boolean
558+
default: false
559+
wiz-fail-on-high:
560+
description: 'Fail the pipeline if Wiz finds HIGH vulnerabilities'
561+
required: false
562+
type: boolean
563+
default: false
544564

545565
env:
546566
PRIMARY_APPLICATION: ${{ inputs.application }} # was 'default' # Custom repo property [primaryApplication]: chef360, automate, infra-server, habitat, supermarket, licensing, downloads, chef-client, inspec, chef-workstation (or derivatives like habitat-builder)
@@ -997,12 +1017,37 @@ jobs:
9971017
name: 'Grype Docker image scan'
9981018
if: ${{ inputs.perform-grype-image-scan }}
9991019
uses: chef/common-github-actions/.github/workflows/grype.yml@main
1000-
needs: checkout
1020+
needs: [checkout, build-docker-image]
10011021
secrets: inherit
10021022
with:
10031023
fail-grype-on-high: ${{ inputs.grype-image-fail-on-high }}
10041024
fail-grype-on-critical: ${{ inputs.grype-image-fail-on-critical }}
1005-
grype-image-skip-aws: ${{ inputs.grype-image-skip-aws }}
1025+
grype-image-skip-aws: ${{ inputs.image-skip-aws }}
1026+
prebuilt-image-artifact: docker-image-for-scans
1027+
prebuilt-image-names: ${{ needs.build-docker-image.outputs.image-names }}
1028+
1029+
build-docker-image:
1030+
name: 'Build Docker image for security scans'
1031+
if: ${{ inputs.perform-grype-image-scan == true || inputs.perform-wiz-scan == true }}
1032+
uses: chef/common-github-actions/.github/workflows/build-docker-image.yml@main
1033+
needs: checkout
1034+
secrets: inherit
1035+
with:
1036+
skip-aws: ${{ inputs.image-skip-aws }}
1037+
1038+
run-wiz-scan:
1039+
name: 'Wiz CLI security scan'
1040+
if: ${{ inputs.perform-wiz-scan == true }}
1041+
uses: chef/common-github-actions/.github/workflows/wiz.yml@main
1042+
needs: [checkout, build-docker-image]
1043+
with:
1044+
fail-build: ${{ inputs.wiz-fail-build }}
1045+
fail-on-critical: ${{ inputs.wiz-fail-on-critical }}
1046+
fail-on-high: ${{ inputs.wiz-fail-on-high }}
1047+
wiz-image-skip-aws: ${{ inputs.image-skip-aws }}
1048+
prebuilt-image-artifact: docker-image-for-scans
1049+
prebuilt-image-names: ${{ needs.build-docker-image.outputs.image-names }}
1050+
secrets: inherit
10061051

10071052
run-grype-hab-package-scan:
10081053
name: 'Grype scan Habitat packages from bldr.habitat.sh'
@@ -1145,7 +1190,7 @@ jobs:
11451190
# VER=$(cat VERSION)
11461191
# echo "VERSION=$VER" >> $GITHUB_ENV
11471192
# then ${{ env.VERSION }}
1148-
1193+
11491194
set-application-version:
11501195
runs-on: ubuntu-latest
11511196
name: 'Detect SBOM version for application'

.github/workflows/grype.yml

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ on:
2222
required: false
2323
type: boolean
2424
default: false
25+
prebuilt-image-artifact:
26+
description: 'Name of uploaded artifact containing a Docker image tar (skip Docker build if provided)'
27+
required: false
28+
type: string
29+
default: ''
30+
prebuilt-image-names:
31+
description: 'Space-separated list of Docker image:tag names inside the prebuilt artifact tar'
32+
required: false
33+
type: string
34+
default: ''
2535

2636
jobs:
2737
grype-scan:
@@ -65,13 +75,29 @@ jobs:
6575
if: ${{ !inputs.grype-image-skip-aws }}
6676
uses: aws-actions/amazon-ecr-login@v2
6777

68-
- name: Scan with Grype
69-
id: grype-scan
78+
- name: Download prebuilt Docker image
79+
if: ${{ inputs.prebuilt-image-artifact != '' }}
80+
uses: actions/download-artifact@v4
81+
with:
82+
name: ${{ inputs.prebuilt-image-artifact }}
83+
path: /tmp
84+
85+
- name: Load prebuilt Docker image
86+
id: load-image
87+
if: ${{ inputs.prebuilt-image-artifact != '' }}
88+
run: |
89+
echo "Loading prebuilt images from artifact..."
90+
docker load -i /tmp/docker-image.tar
91+
echo "IMAGES=${{ inputs.prebuilt-image-names }}" >> "$GITHUB_OUTPUT"
92+
echo "Loaded images: ${{ inputs.prebuilt-image-names }}"
93+
docker images
94+
95+
- name: Build Docker image
96+
id: build-image
97+
if: ${{ inputs.prebuilt-image-artifact == '' }}
7098
env:
7199
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
72100
run: |
73-
SCAN_NAME="${{ github.repository }}"
74-
75101
if [ ! -f "Dockerfile" ]; then
76102
echo "❌ No Dockerfile found - this workflow requires a Dockerfile to scan Docker image"
77103
exit 1
@@ -101,13 +127,19 @@ jobs:
101127
make compose-build
102128
103129
echo "Detecting built images..."
104-
docker compose images
105-
106-
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^${REPO_NAME}" | grep -v "^<none>")
130+
# Get all image names from compose, then keep only ones that exist locally (i.e., were actually built)
131+
IMAGES=""
132+
for img in $(docker compose config --images 2>/dev/null | sort -u); do
133+
TAG_IMG=$(echo "$img" | grep -q ':' && echo "$img" || echo "${img}:latest")
134+
if docker image inspect "$TAG_IMG" &>/dev/null; then
135+
IMAGES="${IMAGES}${TAG_IMG} "
136+
fi
137+
done
138+
IMAGES=$(echo "$IMAGES" | xargs)
107139
108140
if [ -z "$IMAGES" ]; then
109-
echo "No images found with prefix ${REPO_NAME}, scanning all recent images"
110-
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "^<none>" | head -5)
141+
echo "⚠️ Could not detect built images from compose config, falling back to repo name match"
142+
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^${REPO_NAME}" | grep -v "^<none>")
111143
fi
112144
# Strategy 3: Fallback to standard docker build
113145
else
@@ -121,6 +153,28 @@ jobs:
121153
exit 1
122154
fi
123155
156+
echo "IMAGES=$(echo $IMAGES | tr '\n' ' ')" >> "$GITHUB_OUTPUT"
157+
echo "Found images: $IMAGES"
158+
159+
- name: Determine scan targets
160+
id: scan-target
161+
run: |
162+
IMAGES="${{ steps.load-image.outputs.IMAGES || steps.build-image.outputs.IMAGES }}"
163+
if [ -z "$IMAGES" ]; then
164+
echo "❌ No images available to scan"
165+
exit 1
166+
fi
167+
echo "IMAGES=$IMAGES" >> "$GITHUB_OUTPUT"
168+
echo "Scan targets: $IMAGES"
169+
170+
- name: Scan with Grype
171+
id: grype-scan
172+
env:
173+
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
174+
run: |
175+
SCAN_NAME="${{ github.repository }}"
176+
IMAGES="${{ steps.scan-target.outputs.IMAGES }}"
177+
124178
echo "Found images to scan:"
125179
echo "$IMAGES"
126180

0 commit comments

Comments
 (0)