Skip to content

ci-container-security-scan #44

ci-container-security-scan

ci-container-security-scan #44

# Copyright AGNTCiY Contributors (https://github.com/agntcy)
# SPDX-License-Identifier: Apache-2.0
---
name: ci-container-security-scan
on:
# Nightly scan on main branch only; manual dispatch allowed.
schedule:
- cron: '0 3 * * *' # Daily at 03:00 UTC (runs on default branch context: main)
workflow_dispatch:
permissions:
contents: read
actions: read
jobs:
trivy-scan:
name: Trivy Image Scan (Pull from GHCR)
permissions:
contents: read
security-events: write # for uploading SARIF
issues: write # create issues for critical CVEs
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- image: slim-node
repo: ghcr.io/${{ github.repository_owner }}/slim
version: latest
- image: slim-controller
repo: ghcr.io/${{ github.repository_owner }}/slim/control-plane
version: latest
- image: spire-server
repo: ghcr.io/spiffe/spire-server
version: 1.14.5
- image: spire-agent
repo: ghcr.io/spiffe/spire-agent
version: 1.14.5
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Log in to GHCR
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull image (explicit version)
env:
IMAGE_REPO: ${{ matrix.repo }}
IMAGE_VERSION: ${{ matrix.version }}
run: |
set -euo pipefail
IMAGE_REF="${IMAGE_REPO}:${IMAGE_VERSION}"
echo "Pulling $IMAGE_REF"
docker pull "$IMAGE_REF"
docker image inspect "$IMAGE_REF" >/dev/null 2>&1
- name: Run Trivy vulnerability scan (image)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
with:
image-ref: ${{ matrix.repo }}:${{ matrix.version }}
format: sarif
output: trivy-${{ matrix.image }}.sarif
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH,MEDIUM'
ignore-unfixed: true
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
sarif_file: trivy-${{ matrix.image }}.sarif
# Distinguish reports per container image in Code Scanning UI
category: trivy-${{ matrix.image }}
- name: Upload raw report artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: trivy-report-${{ matrix.image }}
path: trivy-${{ matrix.image }}.sarif
retention-days: 7
summarize:
name: Summarize Results
permissions:
contents: read
issues: write # create issues for critical CVEs
needs: [trivy-scan]
runs-on: ubuntu-latest
if: always()
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: trivy-artifacts
- name: Debug artifact contents
run: |
echo "Downloaded artifact directory tree:" >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
find trivy-artifacts -maxdepth 3 -type f -print >> "$GITHUB_STEP_SUMMARY" || true
echo '```' >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
- name: Generate summary
run: |
chmod +x .github/workflows/scripts/security/generate_trivy_summary.sh
.github/workflows/scripts/security/generate_trivy_summary.sh
- name: Fail if critical vulns found (optional gate)
if: ${{ github.event_name != 'pull_request' }}
run: |
set -e
found=$(grep -R "CRITICAL" -c trivy-artifacts || true)
if [ "${found}" != "0" ]; then
echo "Critical vulnerabilities detected. (Gate currently informational.)" >&2
fi
- name: Create GitHub issues for critical CVEs
if: ${{ github.event_name != 'pull_request' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
echo "Installing dependencies for issue creation script";
npm init -y >/dev/null 2>&1 || true
npm install @octokit/rest@21 glob >/dev/null 2>&1
node .github/workflows/scripts/security/create_critical_cve_issues.js