Skip to content

CVE Scan - Container Images #19

CVE Scan - Container Images

CVE Scan - Container Images #19

Workflow file for this run

# SPDX-FileCopyrightText: SUSE LLC
# SPDX-License-Identifier: Apache-2.0
name: CVE Scan - Container Images
on:
push:
branches:
- "main"
workflow_dispatch:
schedule:
- cron: '47 2 * * *' # every day at 2:47 AM
timezone: "Europe/Madrid"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
HELM_VERSION: v4.2.0 # https://github.com/helm/helm/releases
SEMVER_VERSION: 1a547a75f946717223fb7ca821ba6f3f337e9aca # https://api.github.com/repos/fsaintjacques/semver-tool/commits?per_page=1
CYCLONEDX_VERSION: sha256:dc5a886c592c49076ce09079433e961be94f1bb8521f837c1467b585b33f67e1 # v0.32.0 - https://hub.docker.com/r/cyclonedx/cyclonedx-cli/tags
TRIVY_VERSION: v0.71.2 # https://github.com/aquasecurity/trivy/releases
jobs:
extract-images:
name: Extract Container Images
runs-on: ubuntu-24.04
outputs:
images: ${{ steps.extract.outputs.images }}
chart-name: ${{ steps.metadata.outputs.name }}
chart-version: ${{ steps.metadata.outputs.version }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install Helm
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5
with:
version: ${{ env.HELM_VERSION }}
- name: Extract chart metadata
id: metadata
shell: bash
run: |
source "${{ github.workspace }}/.github/scripts/helpers.sh"
extract_chart_metadata "$DEFAULT_CHART_PATH"
- name: Extract images from Helm chart
id: extract
shell: bash
run: |
source "${{ github.workspace }}/.github/scripts/helpers.sh"
IMAGES=$(extract_all_images "$DEFAULT_CHART_PATH")
echo "images=${IMAGES}" >> $GITHUB_OUTPUT
log_info "Extracted images:"
echo "$IMAGES" | jq '.[]'
setup-trivy-db:
name: Setup Trivy Database
needs: extract-images
runs-on: ubuntu-24.04
steps:
- name: Download Trivy DBs
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: image
image-ref: registry.suse.com/bci/bci-micro # dummy image to trigger DB download
version: ${{ env.TRIVY_VERSION }}
cache: true
scan-images:
name: Scan Image for CVEs
needs: [extract-images, setup-trivy-db]
runs-on: ubuntu-24.04
strategy:
matrix:
image: ${{ fromJson(needs.extract-images.outputs.images) }}
permissions:
contents: read
security-events: write
env:
TRIVY_SKIP_DB_UPDATE: "true"
TRIVY_SKIP_JAVA_DB_UPDATE: "true"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
sparse-checkout: .github
sparse-checkout-cone-mode: false
- name: Sanitize image name for filename
id: sanitize
shell: bash
run: |
source "${{ github.workspace }}/.github/scripts/helpers.sh"
generate_image_info "${{ matrix.image }}"
- name: Run Trivy vulnerability scanner
id: trivy-scan
continue-on-error: true
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
image-ref: ${{ matrix.image }}
format: "sarif"
output: "${{ steps.sanitize.outputs.safe_name }}-trivy-results.sarif"
severity: "CRITICAL,HIGH"
version: ${{ env.TRIVY_VERSION }}
cache: true
- name: Alert on scan failure
if: steps.trivy-scan.outcome == 'failure'
run: |
echo "⚠️ WARNING: Failed to scan image: ${{ matrix.image }}"
echo "This may indicate the image is unavailable or has been removed from the registry."
echo "Please verify the image source and availability."
- name: Scan for SBOM
id: sbom-scan
continue-on-error: true
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
image-ref: ${{ matrix.image }}
format: "cyclonedx"
output: "${{ steps.sanitize.outputs.safe_name }}-sbom.json"
version: ${{ env.TRIVY_VERSION }}
cache: true
- name: Alert on SBOM scan failure
if: steps.sbom-scan.outcome == 'failure'
run: |
echo "⚠️ WARNING: Failed to generate SBOM for image: ${{ matrix.image }}"
echo "This may indicate the image is unavailable or has been removed from the registry."
echo "Please verify the image source and availability."
- name: Upload SBOM artifact
if: steps.sbom-scan.outcome == 'success'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: sbom-${{ steps.sanitize.outputs.safe_name }}
path: ${{ steps.sanitize.outputs.safe_name }}-sbom.json
- name: Upload temporary SARIF artifact
if: steps.trivy-scan.outcome == 'success'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: sarif-${{ steps.sanitize.outputs.safe_name }}
path: |
${{ steps.sanitize.outputs.safe_name }}-trivy-results.sarif
${{ steps.sanitize.outputs.safe_name }}-image-info.json
- name: Upload SARIF to GitHub Security
if: steps.trivy-scan.outcome == 'success'
uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4
with:
sarif_file: ${{ steps.sanitize.outputs.safe_name }}-trivy-results.sarif
category: container/${{ steps.sanitize.outputs.base_name }}
generate-reports:
name: Generate Reports
needs: [scan-images, extract-images]
runs-on: ubuntu-24.04
strategy:
matrix:
report: [sbom, imageslock]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: sbom-*
path: reports
merge-multiple: true
- name: Generate ${{ matrix.report }}
env:
CYCLONEDX_VERSION: ${{ env.CYCLONEDX_VERSION }}
run: ${{ github.workspace }}/.github/scripts/cve-scan-helper.sh ${{ matrix.report }} "reports" "${{ needs.extract-images.outputs.chart-name }}" "${{ needs.extract-images.outputs.chart-version }}"
- name: Upload ${{ matrix.report }} report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ${{ matrix.report == 'sbom' && 'sbom.cyclonedx' || 'images.lock' }}
path: reports/${{ matrix.report == 'sbom' && 'sbom.cyclonedx.json' || 'images-lock.yaml' }}
if-no-files-found: warn
check-vulnerabilities:
name: Check for Vulnerabilities
needs: [generate-reports, extract-images]
runs-on: ubuntu-24.04
outputs:
vulnerable_images: ${{ steps.check-vulns.outputs.vulnerable_images }}
permissions:
actions: read
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: sarif-*
path: sarif-results
- name: Check for vulnerabilities
id: check-vulns
run: |
source "${{ github.workspace }}/.github/scripts/helpers.sh"
check_vulnerabilities sarif-results
create-remediation-prs:
name: Create/Update Fix PRs
needs: check-vulnerabilities
if: fromJson(needs.check-vulnerabilities.outputs.vulnerable_images)[0] != null
runs-on: ubuntu-24.04
strategy:
matrix:
image: ${{ fromJson(needs.check-vulnerabilities.outputs.vulnerable_images) }}
fail-fast: false
permissions:
contents: write
pull-requests: write
security-events: read
env:
GITHUB_TOKEN: ${{ secrets.TRENTOBOT_GH_PAT }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
- name: Import GPG key
id: import-gpg
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
with:
gpg_private_key: ${{ secrets.TRENTOBOT_GPG_KEY }}
git_user_signingkey: true
git_commit_gpgsign: true
git_tag_gpgsign: true
git_committer_name: trentobot
git_committer_email: trentobot@suse.com
- name: Install semver-tool
run: |
sudo wget -O /usr/local/bin/semver https://raw.githubusercontent.com/fsaintjacques/semver-tool/${{ env.SEMVER_VERSION }}/src/semver
sudo chmod +x /usr/local/bin/semver
- name: Sanitize image name for filename
id: sanitize
shell: bash
run: |
source "${{ github.workspace }}/.github/scripts/helpers.sh"
generate_image_info "${{ matrix.image }}"
- name: Download SARIF for this image
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: sarif-${{ steps.sanitize.outputs.safe_name }}
path: sarif-results
- name: Analyze SARIF & Extract CVE Info
id: analyze
run: |
${{ github.workspace }}/.github/scripts/cve-scan-helper-remediation.sh analyze-sarif \
sarif-results \
image-analysis.json
- name: Find Upgrade Version
if: steps.analyze.outputs.skip != 'true'
id: upgrade
run: |
${{ github.workspace }}/.github/scripts/cve-scan-helper-remediation.sh find-upgrade \
image-analysis.json \
upgrade-plan.json
- name: Verify Target Image
if: steps.upgrade.conclusion == 'success' && steps.upgrade.outputs.skip != 'true'
run: |
${{ github.workspace }}/.github/scripts/cve-scan-helper-remediation.sh verify-image \
image-analysis.json \
upgrade-plan.json \
verification.json
- name: Update Values Files
if: steps.upgrade.conclusion == 'success' && steps.upgrade.outputs.skip != 'true'
id: update
run: |
${{ github.workspace }}/.github/scripts/cve-scan-helper-remediation.sh update-values \
image-analysis.json \
upgrade-plan.json \
charts \
values-updates.json
- name: Create Pull Request
if: steps.upgrade.conclusion == 'success' && steps.upgrade.outputs.skip != 'true'
id: pr
env:
GH_TOKEN: ${{ github.token }}
run: |
${{ github.workspace }}/.github/scripts/cve-scan-helper-remediation.sh manage-pr \
image-analysis.json \
upgrade-plan.json \
values-updates.json \
pr-result.json
if [ -f pr-result.json ]; then
ACTION=$(jq -r '.action_taken' pr-result.json)
if [ "$ACTION" != "no_changes" ]; then
echo "has_updates=true" >> $GITHUB_OUTPUT
fi
fi
cleanup-scan-artifacts:
name: Cleanup Scan Artifacts
needs: [check-vulnerabilities, create-remediation-prs]
if: always()
runs-on: ubuntu-24.04
permissions:
actions: write
steps:
- uses: geekyeggo/delete-artifact@176a747ab7e287e3ff4787bf8a148716375ca118 # v6
with:
name: |
sbom-*
sarif-*