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