Skip to content

Commit

Permalink
Run CVE analysis when DB cache or upstream cdn is live (#141)
Browse files Browse the repository at this point in the history
Include graceful error / skip cve analysis for grype based on enforcement and db availability

Signed-off-by: saisatishkarra <saisatish.karra@konghq.com>
Co-authored-by: saisiatishkarra <saisatishkarra@konghq.com>
  • Loading branch information
saisatishkarra and saisiatishkarra authored Aug 16, 2024
1 parent 7a3a7bd commit a213265
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/dir-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ jobs:
asset_prefix: test.insomnia
dir: ${{env.TEST_REPOSITORY}}
upload-sbom-release-assets: true
force_grype_db_update: true ## Explicitly skip cache
fail_build: false
1 change: 1 addition & 0 deletions .github/workflows/docker-image-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
asset_prefix: test.kong-gateway-dev-linux-arm64
image: ${{env.IMAGE}}@${{ steps.image_manifest_metadata.outputs.arm64_sha }}
upload-sbom-release-assets: true
force_grype_db_update: true ## Explicitly skip db cache when available

test-download-sbom:
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
Expand Down
89 changes: 86 additions & 3 deletions security-actions/sca/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ inputs:
options:
- 'true'
- 'false'
force_grype_db_update:
required: false
default: false
description: 'Force to download DB when cache is available and up-to-date'
type: choice
options:
- 'true'
- 'false'

# Outputs to be consumed by others using this SCA action
outputs:
Expand Down Expand Up @@ -110,11 +118,82 @@ runs:
files: "${{ steps.meta.outputs.sbom_spdx_file }}, ${{ steps.meta.outputs.sbom_cyclonedx_file }}"
fail: true

- name: Download Grype
uses: anchore/scan-action/download-grype@v4.1.1

# Check for any existing cache to reuse / update
- name: Cache Grype DB
id: cache_grype_db
if: ${{ inputs.force_grype_db_update != 'true' }}
uses: actions/cache@v4
env:
cache-name: cache_grype_db
with:
# Grype cache files are stored in `~/.cache/grype/db` on Linux/macOS
path: ~/.cache/grype/db
key: ${{ env.cache-name }}

# Make a network call to anchore grype CDN.
# This could fail when CDN is flaky for long periods of time.
# Setting timeout for available avoids long stuck grype processes on workflow jobs

## Edgecase: Grype DB will never update if stale cache is found
- name: Grype DB Check Updates
#if: ${{ steps.cache_grype_db.outputs.cache-hit != 'true' }}
id: grype_db_check_updates
shell: bash
run: |
db_check_status=0
db_update_status=0
echo "::group::Grype DB Status Check"
grype db check -vv || db_check_status=$?
if [[ "${db_check_status}" -eq 0 ]]; then
echo "::notice :: Grype DB is already up-to-date"
fi
echo "::endgroup::"
echo "::group:: Update Grype DB"
if [[ "${db_check_status}" -ne 0 ]] || [[ ${FORCE_GRYPE_DB_UPDATE} == "true" ]]; then
grype db update -vv || db_update_status=$?
fi
if [[ "${db_update_status}" -ne 0 ]]; then
GRYPE_DB_UPDATE_MSG="Grype DB updates was not successful. SCA / CVE Grype results might be skipped / unavailable due to DB issues"
if [[ ${FAIL_BUILD} -eq 1 ]]; then
echo "::error ::${GRYPE_DB_UPDATE_MSG}"
exit ${FAIL_BUILD}
elif [[ $FAIL_BUILD -eq 0 ]]; then
echo "::warning ::${GRYPE_DB_UPDATE_MSG}"
echo "GRYPE_DB_UPDATE_STATUS=${db_update_status}" >> $GITHUB_OUTPUT
fi
else
echo "::notice :: Grype DB is updated succesfully"
fi
echo "::endgroup::"
echo "GRYPE_DB_UPDATE_STATUS=${db_update_status}" >> $GITHUB_OUTPUT
env:
FAIL_BUILD: ${{ (steps.meta.outputs.global_enforce_build_failure == 'true' || inputs.fail_build == 'true') && '1' || '0' }}
GRYPE_DB_UPDATE_AVAILABLE_TIMEOUT: 30s # timeout to fetch listing.json to check if db download is needed
GRYPE_DB_UPDATE_DOWNLOAD_TIMEOUT: 600s # timeout for actual db download if needed
FORCE_GRYPE_DB_UPDATE: ${{ inputs.force_grype_db_update }}

- name: Cache Grype DB updates
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }}
id: cache_grype_db_updates
uses: actions/cache@v4
env:
cache-name: cache_grype_db # Use generic cache key instead of unique keys for different refs since CVE DB doesn't change frequently
with:
# Grype cache files are stored in `~/.cache/grype/db` on Linux/macOS
path: ~/.cache/grype/db
key: ${{ env.cache-name }}

# Don't fail during report generation
- name: Vulnerability analysis of SBOM
uses: anchore/scan-action@v4.1.1
id: grype_analysis_sarif
if: ${{ steps.sbom_report.outputs.files_exists == 'true' }}
if: ${{ steps.sbom_report.outputs.files_exists == 'true' && steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }} # Run only if DB is available on the runner }}
with:
sbom: ${{ steps.meta.outputs.sbom_spdx_file }}
output-format: sarif
Expand All @@ -127,7 +206,7 @@ runs:
- name: Vulnerability analysis of SBOM
uses: anchore/scan-action@v4.1.1
id: grype_analysis_json
if: ${{ steps.sbom_report.outputs.files_exists == 'true' }}
if: ${{ steps.sbom_report.outputs.files_exists == 'true' && steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }} # Run only if DB is available on the runner}}
with:
sbom: ${{ steps.meta.outputs.sbom_spdx_file }}
output-format: json
Expand All @@ -138,6 +217,7 @@ runs:
GRYPE_DB_AUTO_UPDATE: false # Use grype db cache from grype step above

- name: Check vulnerability analysis report existence
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }}
uses: andstor/file-existence-action@v3
id: grype_report
with:
Expand All @@ -148,11 +228,13 @@ runs:
# Hack to increase readability of grype artifacts attached to workflows and releases
- name: Rename grype analysis report
shell: bash
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }} # Run only if DB is available on the runner
run: |
mv ${{ steps.grype_analysis_sarif.outputs.sarif }} ${{ steps.meta.outputs.grype_sarif_file }}
mv ${{ steps.grype_analysis_json.outputs.json }} ${{ steps.meta.outputs.grype_json_file }}
- name: Upload grype analysis report
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }} # Run only if DB is available on the runner
uses: actions/upload-artifact@v4
with:
name: ${{ steps.meta.outputs.grype_sarif_file }}
Expand All @@ -162,6 +244,7 @@ runs:

# Upload grype cve reports
- name: Upload grype analysis report
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }} # Run only if DB is available on the runner
uses: actions/upload-artifact@v4
with:
name: ${{ steps.meta.outputs.grype_json_file }}
Expand All @@ -174,7 +257,7 @@ runs:
# Table format will supress any specified ignore rules
- name: Inspect Vulnerability analysis of SBOM
uses: anchore/scan-action@v4.1.1
if: ${{ steps.sbom_report.outputs.files_exists == 'true' }}
if: ${{ steps.sbom_report.outputs.files_exists == 'true' && steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }}
with:
sbom: ${{ steps.meta.outputs.sbom_spdx_file }}
output-format: table
Expand Down
92 changes: 89 additions & 3 deletions security-actions/scan-docker-image/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ inputs:
options:
- 'true'
- 'false'
force_grype_db_update:
required: false
default: false
description: 'Force to download DB when cache is available and up-to-date'
type: choice
options:
- 'true'
- 'false'

outputs:
cis-json-report:
Expand Down Expand Up @@ -113,25 +121,99 @@ runs:
with:
files: "${{ steps.meta.outputs.sbom_spdx_file }}, ${{ steps.meta.outputs.sbom_cyclonedx_file }}"
fail: true

- name: Download Grype
uses: anchore/scan-action/download-grype@v4.1.1

# Check for any existing cache to reuse / update
- name: Cache Grype DB
if: ${{ inputs.force_grype_db_update != 'true' }}
id: cache_grype_db
uses: actions/cache@v4
env:
cache-name: cache_grype_db
with:
# Grype cache files are stored in `~/.cache/grype/db` on Linux/macOS
path: ~/.cache/grype/db
key: ${{ env.cache-name }}

# Make a network call to anchore grype CDN.
# This could fail when CDN is flaky for long periods of time.
# Setting timeout for available avoids long stuck grype processes on workflow jobs

## Edgecase: Grype DB will never update if stale cache is found
- name: Grype DB Check Updates
#if: ${{ steps.cache_grype_db.outputs.cache-hit != 'true' }}
id: grype_db_check_updates
shell: bash
run: |
db_check_status=0
db_update_status=0
echo "::group::Grype DB Status Check"
grype db check -vv || db_check_status=$?
if [[ "${db_check_status}" -eq 0 ]]; then
echo "::notice :: Grype DB is already up-to-date"
fi
echo "::endgroup::"
echo "::group:: Update Grype DB"
if [[ "${db_check_status}" -ne 0 ]] || [[ ${FORCE_GRYPE_DB_UPDATE} == "true" ]]; then
grype db update -vv || db_update_status=$?
fi
if [[ "${db_update_status}" -ne 0 ]]; then
GRYPE_DB_UPDATE_MSG="Grype DB updates was not successful. SCA / CVE Grype results might be skipped / unavailable due to DB issues"
if [[ ${FAIL_BUILD} -eq 1 ]]; then
echo "::error ::${GRYPE_DB_UPDATE_MSG}"
exit ${FAIL_BUILD}
elif [[ $FAIL_BUILD -eq 0 ]]; then
echo "::warning ::${GRYPE_DB_UPDATE_MSG}"
echo "GRYPE_DB_UPDATE_STATUS=${db_update_status}" >> $GITHUB_OUTPUT
fi
else
echo "::notice :: Grype DB is updated succesfully"
fi
echo "::endgroup::"
echo "GRYPE_DB_UPDATE_STATUS=${db_update_status}" >> $GITHUB_OUTPUT
env:
FAIL_BUILD: ${{ (steps.meta.outputs.global_enforce_build_failure == 'true' || inputs.fail_build == 'true') && '1' || '0' }}
GRYPE_DB_UPDATE_AVAILABLE_TIMEOUT: 30s # timeout to fetch listing.json to check if db download is needed
GRYPE_DB_UPDATE_DOWNLOAD_TIMEOUT: 600s # timeout for actual db download if needed
FORCE_GRYPE_DB_UPDATE: ${{ inputs.force_grype_db_update }}

- name: Cache Grype DB updates
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }}
id: cache_grype_db_updates
uses: actions/cache@v4
env:
cache-name: cache_grype_db # Use generic cache key instead of unique keys for different refs since CVE DB doesn't change frequently
with:
# Grype cache files are stored in `~/.cache/grype/db` on Linux/macOS
path: ~/.cache/grype/db
key: ${{ env.cache-name }}

# Grype is invoked first time ever
# Don't fail during report generation
- name: Vulnerability analysis of SBOM
uses: anchore/scan-action@v4.1.1
id: grype_analysis_sarif
if: ${{ steps.sbom_report.outputs.files_exists == 'true' }}
if: ${{ steps.sbom_report.outputs.files_exists == 'true' && steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }}
with:
sbom: ${{ steps.meta.outputs.sbom_spdx_file }}
output-format: sarif
fail-build: 'false'
add-cpes-if-none: true
severity-cutoff: ${{ steps.meta.outputs.global_severity_cutoff }}
env:
GRYPE_DB_AUTO_UPDATE: false

# Don't fail during report generation
# JSON format will report any ignored rules
- name: Vulnerability analysis of SBOM
uses: anchore/scan-action@v4.1.1
id: grype_analysis_json
if: ${{ steps.sbom_report.outputs.files_exists == 'true' }}
if: ${{ steps.sbom_report.outputs.files_exists == 'true' && steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }}
with:
sbom: ${{ steps.meta.outputs.sbom_spdx_file }}
output-format: json
Expand All @@ -142,6 +224,7 @@ runs:
GRYPE_DB_AUTO_UPDATE: false # Use grype db cache from grype step above

- name: Check vulnerability analysis report existence
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }} # Run only if DB is available on the runner
uses: andstor/file-existence-action@v3
id: grype_report
with:
Expand All @@ -151,12 +234,14 @@ runs:
# Grype CVE Action generates an ./results.sarif or ./results.report and no way to customize output file name
# Hack to increase readability of grype artifacts attached to workflows and releases
- name: Rename grype analysis report
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }} # Run only if DB is available on the runner
shell: bash
run: |
mv ${{ steps.grype_analysis_sarif.outputs.sarif }} ${{ steps.meta.outputs.grype_sarif_file }}
mv ${{ steps.grype_analysis_json.outputs.json }} ${{ steps.meta.outputs.grype_json_file }}
- name: Upload grype analysis report
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }} # Run only if DB is available on the runner
uses: actions/upload-artifact@v4
with:
name: ${{ steps.meta.outputs.grype_sarif_file }}
Expand All @@ -166,6 +251,7 @@ runs:

# Upload grype cve reports
- name: Upload grype analysis report
if: ${{ steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }} # Run only if DB is available on the runner
uses: actions/upload-artifact@v4
with:
name: ${{ steps.meta.outputs.grype_json_file }}
Expand All @@ -178,7 +264,7 @@ runs:
# Table format will supress any specified ignore rules
- name: Inspect Vulnerability analysis of SBOM
uses: anchore/scan-action@v4.1.1
if: ${{ steps.sbom_report.outputs.files_exists == 'true' }}
if: ${{ steps.sbom_report.outputs.files_exists == 'true' && steps.grype_db_check_updates.outputs.GRYPE_DB_UPDATE_STATUS == 0 }}
with:
sbom: ${{ steps.meta.outputs.sbom_spdx_file }}
output-format: table
Expand Down

0 comments on commit a213265

Please sign in to comment.