Skip to content

Commit 6670f15

Browse files
committed
cve
Signed-off-by: Smyslov Maxim <maksim.smyslov@flant.com>
1 parent 44a5d6d commit 6670f15

1 file changed

Lines changed: 374 additions & 0 deletions

File tree

.github/workflows/cve_scan.yml

Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
name: CVE Scan
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened, labeled, synchronize]
6+
push:
7+
branches:
8+
- main
9+
# workflow_dispatch:
10+
# inputs:
11+
# tag_type:
12+
# type: choice
13+
# description: Tag type
14+
# required: false
15+
# options:
16+
# - release
17+
# - dev
18+
# tag_name:
19+
# description: "release version in semver minor format (example: 1.68) or specified tag from dev registry"
20+
# required: false
21+
# scan_several_lastest_releases:
22+
# description: 'Optional. Whether to scan last several releases or not. true/false. For scheduled pipelines it is always true. Default is: false.'
23+
# required: false
24+
# latest_releases_amount:
25+
# description: 'Optional. Number of latest releases to scan. Default is: 3'
26+
# required: false
27+
# severity:
28+
# description: 'Optional. Vulnerabilities severity to scan. Default is: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL'
29+
# required: false
30+
31+
# jobs:
32+
# cve_scan_on_pr:
33+
# if: github.event_name == 'pull_request'
34+
# name: CVE scan for PR
35+
# runs-on: ubuntu-latest
36+
# steps:
37+
# - uses: actions/checkout@v4
38+
# - uses: deckhouse/modules-actions/cve_scan@v5
39+
# with:
40+
# tag: pr${{ github.event.number }}
41+
# module_name: ${{ vars.MODULE_NAME }}
42+
# dd_url: ${{ secrets.DEFECTDOJO_HOST }}
43+
# dd_token: ${{ secrets.DEFECTDOJO_API_TOKEN }}
44+
# prod_registry: ${{ secrets.PROD_READ_REGISTRY }}
45+
# prod_registry_user: ${{ secrets.PROD_READ_REGISTRY_LOGIN }}
46+
# prod_registry_password: ${{ secrets.PROD_READ_REGISTRY_PASSWORD }}
47+
# dev_registry: ${{ secrets.DEV_REGISTRY }}
48+
# dev_registry_user: ${{ secrets.DEV_REGISTRY_LOGIN }}
49+
# dev_registry_password: ${{ secrets.DEV_REGISTRY_PASSWORD }}
50+
# deckhouse_private_repo: ${{ secrets.DECKHOUSE_PRIVATE_REPO }}
51+
# severity: "HIGH,CRITICAL"
52+
# cve_scan:
53+
# if: github.event_name != 'pull_request'
54+
# name: Regular CVE scan
55+
# runs-on: ubuntu-latest
56+
# steps:
57+
# - uses: actions/checkout@v4
58+
# - uses: deckhouse/modules-actions/cve_scan@v5
59+
# with:
60+
# tag: ${{ github.event.inputs.tag_name || github.event.repository.default_branch }}
61+
# tag_type: ${{ github.event.inputs.tag_type }}
62+
# module_name: ${{ vars.MODULE_NAME }}
63+
# dd_url: ${{ secrets.DEFECTDOJO_HOST }}
64+
# dd_token: ${{ secrets.DEFECTDOJO_API_TOKEN }}
65+
# prod_registry: ${{ secrets.PROD_READ_REGISTRY }}
66+
# prod_registry_user: ${{ secrets.PROD_READ_REGISTRY_LOGIN }}
67+
# prod_registry_password: ${{ secrets.PROD_READ_REGISTRY_PASSWORD }}
68+
# dev_registry: ${{ secrets.DEV_REGISTRY }}
69+
# dev_registry_user: ${{ secrets.DEV_REGISTRY_LOGIN }}
70+
# dev_registry_password: ${{ secrets.DEV_REGISTRY_PASSWORD }}
71+
# deckhouse_private_repo: ${{ secrets.DECKHOUSE_PRIVATE_REPO }}
72+
# scan_several_lastest_releases: ${{ github.event.inputs.scan_several_lastest_releases }}
73+
# latest_releases_amount: ${{ github.event.inputs.latest_releases_amount || '3' }}
74+
# severity: ${{ github.event.inputs.severity }}
75+
76+
jobs:
77+
cve_scan_on_pr:
78+
if: github.event_name == 'pull_request'
79+
name: CVE scan for PR
80+
runs-on: ubuntu-latest
81+
env:
82+
TRIVY_BIN_VERSION: "v0.67.2"
83+
TRIVY_REGISTRY: $TRIVY_REGISTRY
84+
PROD_READ_REGISTRY_USER: $PROD_READ_REGISTRY_USER
85+
PROD_READ_REGISTRY_PASSWORD: $PROD_READ_REGISTRY_PASSWORD
86+
TRIVY_DB_URL: $TRIVY_DB_URL
87+
TRIVY_JAVA_DB_URL: $TRIVY_JAVA_DB_URL
88+
TRIVY_POLICY_URL: TRIVY_POLICY_URL
89+
SEVERITY: SEVERITY
90+
91+
steps:
92+
- name: scan
93+
run: |
94+
echo "Creating workdir"
95+
workdir="trivy_scan"
96+
# remove workdir in case it was not removed on previous run
97+
rm -rf "${workdir}"
98+
mkdir "${workdir}"
99+
100+
echo
101+
echo "======================================================="
102+
echo
103+
104+
echo "Get Trivy"
105+
echo "Trivy version: ${TRIVY_BIN_VERSION}"
106+
mkdir -p "${workdir}/bin/trivy-${TRIVY_BIN_VERSION}"
107+
curl -L -s --fail-with-body https://${DECKHOUSE_PRIVATE_REPO}/api/v4/projects/${TRIVY_REPO_ID}/packages/generic/trivy-${TRIVY_BIN_VERSION}/${TRIVY_BIN_VERSION}/trivy -o ${workdir}/bin/trivy-${TRIVY_BIN_VERSION}/trivy
108+
chmod u+x ${workdir}/bin/trivy-${TRIVY_BIN_VERSION}/trivy
109+
ln -s ${PWD}/${workdir}/bin/trivy-${TRIVY_BIN_VERSION}/trivy ${workdir}/bin/trivy
110+
111+
echo
112+
echo "======================================================="
113+
echo
114+
115+
echo "Updating Trivy Data Bases"
116+
mkdir -p "${workdir}/bin/trivy_cache"
117+
${workdir}/bin/trivy image --timeout 15m --username "${PROD_READ_REGISTRY_USER}" --password "${PROD_READ_REGISTRY_PASSWORD}" --download-db-only --db-repository "${TRIVY_DB_URL}" --cache-dir "${workdir}/bin/trivy_cache"
118+
${workdir}/bin/trivy image --timeout 15m --username "${PROD_READ_REGISTRY_USER}" --password "${PROD_READ_REGISTRY_PASSWORD}" --download-java-db-only --java-db-repository "${TRIVY_JAVA_DB_URL}" --cache-dir "${workdir}/bin/trivy_cache"
119+
120+
echo
121+
echo "======================================================="
122+
echo
123+
124+
${workdir}/bin/trivy fs --scanners vuln,license ./ --output report.json --format table --ignorefile "${module_workdir}/.trivyignore"
125+
126+
rm -r ${workdir}
127+
128+
129+
130+
131+
132+
133+
134+
135+
# echo "Preparing DOCKER_CONFIG and log in to registries"
136+
# mkdir -p "${workdir}/docker"
137+
# export DOCKER_CONFIG="${workdir}/docker"
138+
# echo "${{inputs.prod_registry_password}}" | docker login --username="${{inputs.prod_registry_user}}" --password-stdin ${{inputs.prod_registry}}
139+
# echo "${{inputs.dev_registry_password}}" | docker login --username="${{inputs.dev_registry_user}}" --password-stdin ${{inputs.dev_registry}}
140+
# echo
141+
# echo "======================================================="
142+
# echo
143+
# echo "Get Trivy"
144+
# echo "Trivy version: ${TRIVY_BIN_VERSION}"
145+
# mkdir -p "${workdir}/bin/trivy-${TRIVY_BIN_VERSION}"
146+
# curl -L -s --fail-with-body https://${DECKHOUSE_PRIVATE_REPO}/api/v4/projects/${TRIVY_REPO_ID}/packages/generic/trivy-${TRIVY_BIN_VERSION}/${TRIVY_BIN_VERSION}/trivy -o ${workdir}/bin/trivy-${TRIVY_BIN_VERSION}/trivy
147+
# chmod u+x ${workdir}/bin/trivy-${TRIVY_BIN_VERSION}/trivy
148+
# ln -s ${PWD}/${workdir}/bin/trivy-${TRIVY_BIN_VERSION}/trivy ${workdir}/bin/trivy
149+
150+
# echo "Updating Trivy Data Bases"
151+
# mkdir -p "${workdir}/bin/trivy_cache"
152+
# ${workdir}/bin/trivy image --timeout 15m --username "${{inputs.prod_registry_user}}" --password "${{inputs.prod_registry_password}}" --download-db-only --db-repository "${TRIVY_DB_URL}" --cache-dir "${workdir}/bin/trivy_cache"
153+
# ${workdir}/bin/trivy image --timeout 15m --username "${{inputs.prod_registry_user}}" --password "${{inputs.prod_registry_password}}" --download-java-db-only --java-db-repository "${TRIVY_JAVA_DB_URL}" --cache-dir "${workdir}/bin/trivy_cache"
154+
# echo
155+
# echo "======================================================="
156+
# echo
157+
# # Defining functions
158+
159+
# trivy_scan() {
160+
# ${workdir}/bin/trivy i --timeout 15m --vex oci --show-suppressed --config-check "${TRIVY_POLICY_URL}" --cache-dir "${workdir}/bin/trivy_cache" --skip-db-update --skip-java-db-update --exit-code 0 --severity "${SEVERITY}" --ignorefile "${module_workdir}/.trivyignore" --format ${1} ${2} ${3} --quiet ${4} --username "${trivy_registry_user}" --password "${trivy_registry_pass}" --image-src remote
161+
# }
162+
163+
# send_report() {
164+
# dd_scan_type="${1}"
165+
# dd_report_file_path="${2}"
166+
# dd_module_name="${3}"
167+
# dd_image_name="${4}"
168+
# dd_engagement_name="[$(echo "${dd_scan_type}" | tr '[:lower:]' '[:upper:]')] [IMAGES] [${dd_branch}]"
169+
# tags_string="\"external_modules\",\"images\",\"${dd_scan_type}\",\"${dd_release_or_dev_tag}\",\"${dd_image_version}\""
170+
# if [[ -n "${dd_short_release_tag}" && -n "${dd_full_release_tag}" ]]; then
171+
# tags_string+=",\"${dd_short_release_tag}\",\"${dd_full_release_tag}\""
172+
# fi
173+
# echo ""
174+
# echo "Uploading trivy ${dd_branch} report for image \"${dd_image_name}\" of \"${dd_module_name}\" module"
175+
# echo ""
176+
# dd_upload_response=$(curl -sw "%{http_code}" -X POST \
177+
# --retry 10 \
178+
# --retry-delay 20 \
179+
# --retry-all-errors \
180+
# ${DD_URL}/api/v2/reimport-scan/ \
181+
# -H "accept: application/json" \
182+
# -H "Authorization: Token ${DD_TOKEN}" \
183+
# -F "auto_create_context=True" \
184+
# -F "minimum_severity=Info" \
185+
# -F "active=true" \
186+
# -F "verified=true" \
187+
# -F "scan_type=Trivy Scan" \
188+
# -F "close_old_findings=true" \
189+
# -F "do_not_reactivate=false" \
190+
# -F "push_to_jira=false" \
191+
# -F "file=@${dd_report_file_path}" \
192+
# -F "product_type_name=External Modules" \
193+
# -F "product_name=${dd_module_name}" \
194+
# -F "scan_date=${date_iso}" \
195+
# -F "engagement_name=${dd_engagement_name}" \
196+
# -F "service=${dd_module_name} / ${dd_image_name}" \
197+
# -F "group_by=component_name+component_version" \
198+
# -F "deduplication_on_engagement=false" \
199+
# -F "tags=external_module,${dd_scan_type},module:${dd_module_name},image:${dd_image_name},branch:${dd_branch},${dd_short_release_tag},${dd_full_release_tag},${dd_default_branch_tag},${dd_release_or_dev_tag}" \
200+
# -F "test_title=[${dd_module_name}]: ${dd_image_name}:${dd_image_version}" \
201+
# -F "version=${dd_image_version}" \
202+
# -F "build_id=${IMAGE_HASH}" \
203+
# -F "commit_hash=${CI_COMMIT_SHA}" \
204+
# -F "branch_tag=${module_tag}" \
205+
# -F "apply_tags_to_findings=true")
206+
207+
# dd_return_code="${dd_upload_response: -3}"
208+
# dd_return_body="${dd_upload_response:0: -3}"
209+
# if [ ${dd_return_code} -eq 201 ]; then
210+
# dd_engagement_id=$(echo ${dd_return_body} | jq ".engagement_id" )
211+
# echo "dd_engagement_id: ${dd_engagement_id}"
212+
# echo "Update with tags: ${tags_string}"
213+
# # Updating engagement
214+
# dd_eng_patch_response=$(curl -sw "%{http_code}" -X "PATCH" \
215+
# --retry 10 \
216+
# --retry-delay 20 \
217+
# --retry-all-errors \
218+
# "${DD_URL}/api/v2/engagements/${dd_engagement_id}/" \
219+
# -H "accept: application/json" \
220+
# -H "Authorization: Token ${DD_TOKEN}" \
221+
# -H "Content-Type: application/json" \
222+
# -d "{
223+
# \"tags\": ["${tags_string}"],
224+
# \"version\": \"${dd_image_version}\",
225+
# \"branch_tag\": \"${dd_branch}\"
226+
# }")
227+
# if [ ${dd_eng_patch_response: -3} -eq 200 ]; then
228+
# echo "Engagemet \"${dd_engagement_name}\" updated successfully"
229+
# else
230+
# echo "!!!WARNING!!!"
231+
# echo "Engagemet \"${dd_engagement_name}\" WAS NOT UPDATED"
232+
# echo "HTTP_CODE: ${dd_eng_patch_response: -3}"
233+
# echo "DD_RESPONSE: ${dd_eng_patch_response:0: -3}"
234+
# fi
235+
# else
236+
# echo "!!!WARNING!!!"
237+
# echo "Report for image \"${dd_image_name}\" of \"${dd_module_name}\" module WAS NOT UPLOADED"
238+
# echo "HTTP_CODE: ${dd_return_code}"
239+
# echo "DD_RESPONSE: ${dd_return_body}"
240+
# fi
241+
# }
242+
# if [ "${{ github.event_name }}" == "schedule" ]; then
243+
# SCAN_SEVERAL_LASTEST_RELEASES="true"
244+
# fi
245+
246+
# echo "Setting up registry path for module"
247+
# PROD_REGISTRY_MODULE_BASEDIR="${{inputs.prod_registry}}/${MODULE_PROD_REGISTRY_PATH}"
248+
# DEV_REGISTRY_MODULE_BASEDIR="${{inputs.dev_registry}}/${MODULE_DEV_REGISTRY_PATH}"
249+
250+
# echo "Getting tags to scan"
251+
# module_tags=("${TAG}")
252+
# # Check if provided tag for manual run is for release
253+
# if [ "${{ github.event_name }}" != "pull_request" ]; then
254+
# if [ "${TAG}" != "${{ github.event.repository.default_branch }}" ]; then
255+
# if [ "${TAG_TYPE}" == "release" ]; then
256+
# # if some specific release is defined - scan only it
257+
# if echo "${TAG}"|grep -qE "^[0-9]+\.[0-9]+$"; then
258+
# module_tags=($(crane ls "${PROD_REGISTRY_MODULE_BASEDIR}/${MODULE_NAME}" | grep "^v${TAG}\.[0-9]*$" | sort -V -r | head -n 1))
259+
# else
260+
# echo "ERROR: Please specify required release in the following format: [0-9]+\.[0-9]+"
261+
# exit 1
262+
# fi
263+
# elif [ "${TAG_TYPE}" == "dev" ]; then
264+
# if [ $(crane ls "${DEV_REGISTRY_MODULE_BASEDIR}/${MODULE_NAME}" | grep "^${TAG}$" | wc -l) -eq 1 ]; then
265+
# module_tags=("${TAG}")
266+
# else
267+
# echo "ERROR: Provided tag \"${TAG}\" is not found in dev registry"
268+
# exit 1
269+
# fi
270+
# else
271+
# echo "ERROR: TAG TYPE is not defined!"
272+
# exit 1
273+
# fi
274+
# fi
275+
# fi
276+
# if [ "${SCAN_SEVERAL_LASTEST_RELEASES}" == "true" ]; then
277+
# # Get release tags by regexp, sort by sevmer desc, cut to get minor version, uniq and get 3 latest
278+
# releases=($(crane ls "${PROD_REGISTRY_MODULE_BASEDIR}/${MODULE_NAME}" | grep "^v[0-9]*\.[0-9]*\.[0-9]*" | sort -V -r))
279+
# latest_minor_releases=($(printf '%s\n' "${releases[@]}"| cut -d "." -f -2 | uniq | head -n ${LATEST_RELEASES_AMOUNT}))
280+
# for r in "${latest_minor_releases[@]}"; do
281+
# module_tags+=($(printf '%s\n' "${releases[@]}" | grep "${r}" | sort -V -r|head -n 1))
282+
# done
283+
# fi
284+
285+
# echo "CVE Scan will be applied to the following tags of ${MODULE_NAME}"
286+
# echo "${module_tags[*]}"
287+
# # Scan in loop for provided list of tags
288+
# for module_tag in ${module_tags[*]}; do
289+
# dd_default_branch_tag=""
290+
# dd_short_release_tag=""
291+
# dd_full_release_tag=""
292+
# dd_release_or_dev_tag="dev"
293+
# dd_image_version="${module_tag}"
294+
# dd_branch="${module_tag}"
295+
# date_iso=$(date -I)
296+
# module_image="${DEV_REGISTRY_MODULE_BASEDIR}/${MODULE_NAME}"
297+
# trivy_registry_user="${{inputs.dev_registry_user}}"
298+
# trivy_registry_pass="${{inputs.dev_registry_password}}"
299+
# if [ "${module_tag}" == "${{ github.event.repository.default_branch }}" ]; then
300+
# dd_default_branch_tag="default_branch"
301+
# fi
302+
# # If we are scanning release images - we need to redefine image path to prod registry
303+
# if echo "${module_tag}" | grep -q "^v[0-9]*\.[0-9]*\.[0-9]*" && [[ "${{ github.event_name }}" != "pull_request" ]]; then
304+
# module_image="${PROD_REGISTRY_MODULE_BASEDIR}/${MODULE_NAME}"
305+
# trivy_registry_user="${{inputs.prod_registry_user}}"
306+
# trivy_registry_pass="${{inputs.prod_registry_password}}"
307+
# dd_short_release_tag="release:$(echo ${module_tag} | cut -d '.' -f -2 | sed 's/^v//')"
308+
# dd_full_release_tag="image_release_tag:${module_tag}"
309+
# dd_release_or_dev_tag="release"
310+
# dd_image_version="$(echo ${dd_short_release_tag} | sed 's/^release\://')"
311+
# fi
312+
# module_workdir="${workdir}/${MODULE_NAME}_${module_tag}"
313+
# module_reports="${module_workdir}/reports"
314+
# mkdir -p "${module_reports}"
315+
# touch ${module_workdir}/.trivyignore
316+
# echo "Run Trivy scan"
317+
# echo "Image to check: ${module_image}:${module_tag}"
318+
# echo "Severity: ${SEVERITY}"
319+
# echo "----------------------------------------------"
320+
# echo ""
321+
# echo "Getting module image"
322+
# crane export "${module_image}:${module_tag}" "${MODULE_NAME}.tar"
323+
# tar xf "${MODULE_NAME}.tar" -C "${module_workdir}/"
324+
# echo "Preparing images list to scan"
325+
# digests=$(cat "${module_workdir}${IMAGES_DIGESTS_PATH}")
326+
# # Main module images to scan
327+
# digests=$(echo "${digests}"|jq --arg i "${MODULE_NAME}" --arg s "${module_tag}" '. += { ($i): ($s) }')
328+
# echo "Images to scan:"
329+
# echo "${digests}"
330+
# while read -r line; do
331+
# IMAGE_NAME=$(jq -rc '.key' <<< "${line}")
332+
# if [[ "${IMAGE_NAME}" == "trivy" ]]; then
333+
# continue
334+
# fi
335+
# # Set flag if additional image to use tag instead of hash
336+
# additional_image_detected=false
337+
# if [ "${IMAGE_NAME}" == "${MODULE_NAME}" ]; then
338+
# additional_image_detected=true
339+
# fi
340+
# echo "----------------------------------------------"
341+
# echo "👾 Scaning image \"${IMAGE_NAME}\" of module \"${MODULE_NAME}\" for tag \"${module_tag}\""
342+
# echo ""
343+
# IMAGE_HASH="$(jq -rc '.value' <<< "$line")"
344+
345+
# if [ "$additional_image_detected" == true ]; then
346+
# if [ "${TRIVY_REPORTS_LOG_OUTPUT}" != "false" ]; then
347+
# # CVE Scan
348+
# trivy_scan "table" "--scanners vuln" "" "${module_image}:${module_tag}"
349+
# # License scan
350+
# trivy_scan "table" "--scanners license --license-full" "" "${module_image}:${module_tag}"
351+
# fi
352+
# # CVE Scan
353+
# trivy_scan "json" "--scanners vuln" "--output ${module_reports}/ext_${MODULE_NAME}_${IMAGE_NAME}_report.json" "${module_image}:${module_tag}"
354+
# # License scan
355+
# trivy_scan "json" "--scanners license --license-full" "--output ${module_reports}/ext_${MODULE_NAME}_${IMAGE_NAME}_report_license.json" "${module_image}:${module_tag}"
356+
# else
357+
# if [ "${TRIVY_REPORTS_LOG_OUTPUT}" != "false" ]; then
358+
# # CVE Scan
359+
# trivy_scan "table" "--scanners vuln" "" "${module_image}@${IMAGE_HASH}"
360+
# # License scan
361+
# trivy_scan "table" "--scanners license --license-full" "" "${module_image}@${IMAGE_HASH}"
362+
# fi
363+
# # CVE Scan
364+
# trivy_scan "json" "--scanners vuln" "--output ${module_reports}/ext_${MODULE_NAME}_${IMAGE_NAME}_report.json" "${module_image}@${IMAGE_HASH}"
365+
# # License scan
366+
# trivy_scan "json" "--scanners license --license-full" "--output ${module_reports}/ext_${MODULE_NAME}_${IMAGE_NAME}_report_license.json" "${module_image}@${IMAGE_HASH}"
367+
# fi
368+
# echo " Done"
369+
370+
# send_report "CVE" "${module_reports}/ext_${MODULE_NAME}_${IMAGE_NAME}_report.json" "${MODULE_NAME}" "${IMAGE_NAME}"
371+
# send_report "License" "${module_reports}/ext_${MODULE_NAME}_${IMAGE_NAME}_report_license.json" "${MODULE_NAME}" "${IMAGE_NAME}"
372+
# done < <(jq -rc 'to_entries[]' <<< "${digests}")
373+
# done
374+
# rm -r ${workdir}

0 commit comments

Comments
 (0)