Skip to content

Commit 5d2332a

Browse files
esolitosCopilot
andcommitted
feat: add reusable Mend code scan workflow
refactor(workflows): replace code scan with unified mend scan workflow Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent ece1505 commit 5d2332a

1 file changed

Lines changed: 316 additions & 0 deletions

File tree

.github/workflows/mend.yml

Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
---
2+
name: Code Scan (reusable)
3+
4+
on:
5+
workflow_call:
6+
inputs:
7+
scan-type:
8+
description: |
9+
Type of scan to perform.
10+
Options:
11+
- 'sast' (or 'code') for Static Application Security Testing (scanning source code)
12+
- 'sca' (or 'dependencies') for Software Composition Analysis (scanning dependencies)
13+
- 'image' for Container Image Scanning. Note: This REQUIRES the 'image-list' input to be set.
14+
required: true
15+
type: string
16+
17+
mend-app-name:
18+
description: "Mend Application Name"
19+
required: true
20+
type: string
21+
22+
mend-project-name:
23+
description: "Mend Project Name"
24+
required: false
25+
type: string
26+
27+
tags:
28+
description: "Assign tags to scan and project (comma-separated key:value pairs)"
29+
required: false
30+
type: string
31+
32+
sast-source-path:
33+
description: "Path to the source code to be scanned"
34+
required: false
35+
type: string
36+
default: "."
37+
38+
sast-engines:
39+
description: |
40+
**Recommended:** Comma-separated list of SAST engine IDs (e.g., '101,108' for Java and JavaScript). Omit for auto-recognition.
41+
Useful ones: Ruby(5), C/C++(12), Go(18), Java(101), Python(104), JavaScript(108)
42+
[See documentation for complete list](https://docs.mend.io/platform/latest/configure-the-mend-cli-for-sast#ConfiguretheMendCLIforSAST-Mend-CLI-SAST-supported-languages-and-engine-IDsMendCLISAST-supportedlanguagesandengineIDs)
43+
required: false
44+
type: string
45+
46+
image-list:
47+
description: |
48+
List of container images to scan (one per line).
49+
Required when scan-type is 'image'.
50+
Example:
51+
myregistry.io/app:latest
52+
myregistry.io/api:v1.0
53+
required: false
54+
type: string
55+
56+
secrets:
57+
MEND_EMAIL:
58+
description: "Mend user email for authentication"
59+
required: true
60+
MEND_USER_KEY:
61+
description: "Mend user API key for authentication"
62+
required: true
63+
64+
defaults:
65+
run:
66+
# Specify to ensure "pipefail and errexit" are set.
67+
# Ref: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#defaultsrunshell
68+
shell: bash
69+
70+
env:
71+
MEND_ORG: ${{ vars.MEND_ORGANIZATION }}
72+
MEND_APP: ${{ inputs.mend-app-name }}
73+
MEND_PROJ: ${{ inputs.mend-project-name }} # optional
74+
MEND_EMAIL: ${{ secrets.MEND_EMAIL }}
75+
MEND_USER_KEY: ${{ secrets.MEND_USER_KEY }}
76+
MEND_URL: https://saas-eu.mend.io
77+
78+
jobs:
79+
prepare-image-matrix:
80+
if: ${{ inputs.scan-type == 'image' }}
81+
82+
runs-on: ubuntu-latest
83+
outputs:
84+
images: ${{ steps.parse.outputs.images }}
85+
86+
steps:
87+
- name: Parse Image List
88+
id: parse
89+
run: |
90+
images='${{ inputs.image-list }}'
91+
92+
if [ -z "$images" ]; then
93+
echo "❌ Error: image-list input is required for image scanning"
94+
exit 1
95+
fi
96+
97+
# Convert newline-separated list to JSON array
98+
# Remove comments (lines starting with #), empty lines, and whitespace
99+
json_array=$(echo "$images" | sed '/^[[:space:]]*#/d; /^[[:space:]]*$/d' | jq -R -s -c 'split("\n") | map(select(length > 0))')
100+
101+
echo "images=$json_array" >> $GITHUB_OUTPUT
102+
echo "📋 Images to scan: $json_array"
103+
104+
scan-sast:
105+
if: ${{ contains(fromJSON('["sast", "code"]'), inputs.scan-type) }}
106+
107+
runs-on: ubuntu-latest
108+
109+
env:
110+
# The following are used by the Mend CLI during SAST scans
111+
MEND_SAST_TIMEOUT_TOTAL: "3600"
112+
MEND_SAST_SCAN_RETRIES: "3"
113+
MEND_SAST_TARGET_DIRECTORY: ${{ inputs.sast-source-path }}
114+
MEND_SAST_ENGINES: ${{ inputs.sast-engines }}
115+
116+
steps:
117+
- name: Install Mend CLI
118+
run: |
119+
if command -v mend &> /dev/null; then
120+
echo "✅ Mend CLI already installed"
121+
mend --version
122+
exit 0
123+
fi
124+
125+
ARCH=$(uname -m)
126+
case $ARCH in
127+
x86_64) ARCH="amd64" ;;
128+
aarch64) ARCH="arm64" ;;
129+
esac
130+
CLI_URL="https://downloads.mend.io/cli/linux_${ARCH}/mend"
131+
curl -fsSL "${CLI_URL}" -o /tmp/mend
132+
sudo mv /tmp/mend /usr/local/bin/mend
133+
sudo chmod +x /usr/local/bin/mend
134+
echo "✅ Mend CLI installed"
135+
mend --version
136+
137+
- name: Run Mend Code Scan
138+
id: scan
139+
run: |
140+
mend_args=(
141+
"--non-interactive"
142+
"--num-cpu" "$(nproc)"
143+
"--scope" "${MEND_ORG}//${MEND_APP}//${MEND_PROJ}"
144+
)
145+
146+
if [ -n "${{ inputs.tags }}" ]; then
147+
mend_args+=("--tags" "${{ inputs.tags }}")
148+
fi
149+
150+
set +e
151+
mend sast "${mend_args[@]}"
152+
exit_code=$?
153+
echo "mend-exit=$exit_code" >> $GITHUB_OUTPUT
154+
155+
- name: Process Scan Results
156+
env:
157+
SCAN_EXIT_CODE: ${{ steps.scan.outputs.mend-exit }}
158+
run: |
159+
# Generate GitHub Actions Job Summary
160+
echo "## 🔍 Mend Code Scan Results" >> $GITHUB_STEP_SUMMARY
161+
echo "" >> $GITHUB_STEP_SUMMARY
162+
echo "**Organization:** ${MEND_ORG}" >> $GITHUB_STEP_SUMMARY
163+
echo "**Application:** ${MEND_APP}" >> $GITHUB_STEP_SUMMARY
164+
echo "**Project:** ${MEND_PROJ}" >> $GITHUB_STEP_SUMMARY
165+
echo "**Source Path:** ${MEND_SAST_TARGET_DIRECTORY}" >> $GITHUB_STEP_SUMMARY
166+
echo "" >> $GITHUB_STEP_SUMMARY
167+
168+
case $SCAN_EXIT_CODE in
169+
0)
170+
echo "### ✅ Success" >> $GITHUB_STEP_SUMMARY
171+
echo "Scan completed successfully with no policy violations." >> $GITHUB_STEP_SUMMARY
172+
;;
173+
1)
174+
echo "### ❌ Invalid Configuration" >> $GITHUB_STEP_SUMMARY
175+
echo "An invalid configuration parameter was passed. Check for typos in the parameters." >> $GITHUB_STEP_SUMMARY
176+
;;
177+
2)
178+
echo "### ❌ Connection Error" >> $GITHUB_STEP_SUMMARY
179+
echo "Unable to access the update or license details from the Mend server URL. Check internet connection." >> $GITHUB_STEP_SUMMARY
180+
;;
181+
4)
182+
echo "### ❌ Unsupported Language" >> $GITHUB_STEP_SUMMARY
183+
echo "Unable to detect a supported language within the project based on the file extensions provided." >> $GITHUB_STEP_SUMMARY
184+
;;
185+
7)
186+
echo "### ❌ Permission Error" >> $GITHUB_STEP_SUMMARY
187+
echo "Could not create a cache subdirectory. Check that the Mend CLI permissions include 'create'." >> $GITHUB_STEP_SUMMARY
188+
;;
189+
9)
190+
echo "### ⚠️ Policy Violation" >> $GITHUB_STEP_SUMMARY
191+
echo "Results contain too many vulnerabilities, which contravenes the defined policy." >> $GITHUB_STEP_SUMMARY
192+
echo "" >> $GITHUB_STEP_SUMMARY
193+
echo "Please review the findings in the Mend platform." >> $GITHUB_STEP_SUMMARY
194+
;;
195+
10)
196+
echo "### ❌ Scanning Engine Failure" >> $GITHUB_STEP_SUMMARY
197+
echo "A scanning engine stalled or failed." >> $GITHUB_STEP_SUMMARY
198+
;;
199+
*)
200+
echo "### ❌ Unknown Error" >> $GITHUB_STEP_SUMMARY
201+
echo "Scan failed with exit code: ${SCAN_EXIT_CODE}" >> $GITHUB_STEP_SUMMARY
202+
;;
203+
esac
204+
205+
exit $SCAN_EXIT_CODE
206+
207+
208+
scan-image:
209+
if: ${{ inputs.scan-type == 'image' }}
210+
211+
runs-on: ubuntu-latest
212+
213+
env:
214+
MEND_IMAGE_SCAN_TIMEOUT_TOTAL: "3600"
215+
MEND_IMAGE_SCAN_RETRIES: "3"
216+
217+
needs: [prepare-image-matrix]
218+
219+
strategy:
220+
fail-fast: false
221+
matrix:
222+
image: ${{ fromJson(needs.prepare-image-matrix.outputs.images) }}
223+
224+
steps:
225+
- name: Install Mend CLI
226+
run: |
227+
if command -v mend &> /dev/null; then
228+
echo "✅ Mend CLI already installed"
229+
mend --version
230+
exit 0
231+
fi
232+
233+
ARCH=$(uname -m)
234+
case $ARCH in
235+
x86_64) ARCH="amd64" ;;
236+
aarch64) ARCH="arm64" ;;
237+
esac
238+
239+
CLI_URL="https://downloads.mend.io/cli/linux_${ARCH}/mend"
240+
curl -fsSL "${CLI_URL}" -o /tmp/mend
241+
sudo mv /tmp/mend /usr/local/bin/mend
242+
sudo chmod +x /usr/local/bin/mend
243+
echo "✅ Mend CLI installed"
244+
mend --version
245+
246+
- name: Define Mend Project Name
247+
if: ${{ env.MEND_PROJ == '' }}
248+
run: |
249+
# Replace any forward slashes and colons in the image name with double underscores
250+
MEND_PROJ=$(echo "${{ matrix.image }}" | sed 's/[\/:]/__/g')
251+
echo "Normalized Mend Project Name: ${MEND_PROJ}"
252+
echo "MEND_PROJ=${MEND_PROJ}" >> $GITHUB_ENV
253+
254+
- name: Run Mend Image Scan
255+
id: scan
256+
run: |
257+
echo "🔍 Scanning image: ${{ matrix.image }}"
258+
259+
mend_args=(
260+
"--non-interactive"
261+
"--scope" "${MEND_ORG}//${MEND_APP}//${MEND_PROJ}"
262+
)
263+
264+
if [ -n "${{ inputs.tags }}" ]; then
265+
mend_args+=("--tags" "${{ inputs.tags }}")
266+
fi
267+
268+
echo "Using Mend arguments:"
269+
for arg in "${mend_args[@]}"; do
270+
echo " - $arg"
271+
done
272+
273+
set +e
274+
mend image "${mend_args[@]}" "${{ matrix.image }}"
275+
exit_code=$?
276+
echo "mend-exit=$exit_code" >> $GITHUB_OUTPUT
277+
278+
- name: Process Scan Results
279+
env:
280+
SCAN_EXIT_CODE: ${{ steps.scan.outputs.mend-exit }}
281+
run: |
282+
# Generate GitHub Actions Job Summary
283+
echo "## 🔍 Mend Image Scan Results" >> $GITHUB_STEP_SUMMARY
284+
echo "" >> $GITHUB_STEP_SUMMARY
285+
echo "**Image:** ${{ matrix.image }}" >> $GITHUB_STEP_SUMMARY
286+
echo "**Organization:** ${MEND_ORG}" >> $GITHUB_STEP_SUMMARY
287+
echo "**Application:** ${MEND_APP}" >> $GITHUB_STEP_SUMMARY
288+
echo "**Project:** ${MEND_PROJ}" >> $GITHUB_STEP_SUMMARY
289+
echo "" >> $GITHUB_STEP_SUMMARY
290+
291+
case $SCAN_EXIT_CODE in
292+
0)
293+
echo "### ✅ Success" >> $GITHUB_STEP_SUMMARY
294+
echo "Image scan completed successfully with no policy violations." >> $GITHUB_STEP_SUMMARY
295+
;;
296+
1)
297+
echo "### ❌ Invalid Configuration" >> $GITHUB_STEP_SUMMARY
298+
echo "An invalid configuration parameter was passed. Check for typos in the parameters." >> $GITHUB_STEP_SUMMARY
299+
;;
300+
2)
301+
echo "### ❌ Connection Error" >> $GITHUB_STEP_SUMMARY
302+
echo "Unable to access the update or license details from the Mend server URL. Check internet connection." >> $GITHUB_STEP_SUMMARY
303+
;;
304+
9)
305+
echo "### ⚠️ Policy Violation" >> $GITHUB_STEP_SUMMARY
306+
echo "Image scan results contain vulnerabilities that contravene the defined policy." >> $GITHUB_STEP_SUMMARY
307+
echo "" >> $GITHUB_STEP_SUMMARY
308+
echo "Please review the findings in the Mend platform." >> $GITHUB_STEP_SUMMARY
309+
;;
310+
*)
311+
echo "### ❌ Error" >> $GITHUB_STEP_SUMMARY
312+
echo "Image scan failed with exit code: ${SCAN_EXIT_CODE}" >> $GITHUB_STEP_SUMMARY
313+
;;
314+
esac
315+
316+
exit $SCAN_EXIT_CODE

0 commit comments

Comments
 (0)