Skip to content

CVE Security Scan

CVE Security Scan #287

Workflow file for this run

name: CVE Security Scan
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
# Run security scan daily at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
permissions:
contents: read
security-events: write
# Configurable severity threshold for CI blocking.
# Set SECURITY_SEVERITY_CUTOFF in repository variables to override.
# Valid values: CRITICAL, HIGH, MEDIUM, LOW
env:
SEVERITY_CUTOFF: ${{ vars.SECURITY_SEVERITY_CUTOFF || 'CRITICAL,HIGH' }}
jobs:
security-scan:
if: github.ref != 'refs/heads/gh-pages'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: true
# Trivy filesystem scan — detects vulnerabilities in source code,
# configuration files, and any lock files present.
- name: Trivy filesystem scan
uses: aquasecurity/trivy-action@0.35.0
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: ${{ env.SEVERITY_CUTOFF }}
exit-code: '1'
- name: Upload Trivy SARIF to GitHub Security
uses: github/codeql-action/upload-sarif@v4
if: always() && hashFiles('trivy-results.sarif') != ''
continue-on-error: true
with:
sarif_file: 'trivy-results.sarif'
- name: License compatibility check
if: always()
run: |
python3 << 'EOF'
import json
import sys
# Compatible licenses with BSD-3-Clause
COMPATIBLE_LICENSES = {
'MIT', 'BSD-2-Clause', 'BSD-3-Clause', 'Apache-2.0',
'ISC', 'Unlicense', 'BSL-1.0', 'Zlib', 'PostgreSQL',
'Public Domain',
}
# LGPL is compatible only with dynamic linking
CONDITIONAL_LICENSES = {
'LGPL-2.1': 'dynamic linking required',
'LGPL-2.1-or-later': 'dynamic linking required',
'LGPL-3.0': 'dynamic linking required',
}
INCOMPATIBLE_LICENSES = {
'GPL-2.0', 'GPL-2.0-only', 'GPL-2.0-or-later',
'GPL-3.0', 'GPL-3.0-only', 'GPL-3.0-or-later',
'AGPL-3.0',
}
with open('vcpkg.json', 'r') as f:
manifest = json.load(f)
project = manifest.get('name', 'unknown')
project_license = manifest.get('license', 'unknown')
print(f"License Compatibility Check: {project} ({project_license})")
print("=" * 60)
# Known licenses for ecosystem SOUP components
known_licenses = {
'asio': 'BSL-1.0',
'fmt': 'MIT',
'zlib': 'Zlib',
'openssl': 'Apache-2.0',
'spdlog': 'MIT',
'gtest': 'BSD-3-Clause',
'benchmark': 'Apache-2.0',
'libiconv': 'LGPL-2.1',
'libmariadb': 'LGPL-2.1',
'libpq': 'PostgreSQL',
'libpqxx': 'BSD-3-Clause',
'sqlite3': 'Public Domain',
'hiredis': 'BSD-3-Clause',
'grpc': 'Apache-2.0',
'protobuf': 'BSD-3-Clause',
'opentelemetry-cpp': 'Apache-2.0',
'mongo-cxx-driver': 'Apache-2.0',
}
all_ok = True
def collect_deps(deps_list):
names = []
for dep in deps_list:
if isinstance(dep, str):
names.append(dep)
elif isinstance(dep, dict):
names.append(dep.get('name', 'unknown'))
return names
# Core dependencies
dep_names = collect_deps(manifest.get('dependencies', []))
# Feature dependencies
for feat_data in manifest.get('features', {}).values():
dep_names.extend(collect_deps(feat_data.get('dependencies', [])))
# Deduplicate
dep_names = sorted(set(dep_names))
for dep_name in dep_names:
# Skip ecosystem packages
if dep_name.startswith('kcenon-'):
print(f" {dep_name:25} {'BSD-3-Clause':15} ECOSYSTEM")
continue
license_id = known_licenses.get(dep_name)
if license_id is None:
print(f" {dep_name:25} {'UNKNOWN':15} REVIEW NEEDED")
continue
if license_id in COMPATIBLE_LICENSES:
print(f" {dep_name:25} {license_id:15} COMPATIBLE")
elif license_id in CONDITIONAL_LICENSES:
note = CONDITIONAL_LICENSES[license_id]
print(f" {dep_name:25} {license_id:15} CONDITIONAL ({note})")
elif license_id in INCOMPATIBLE_LICENSES:
print(f" {dep_name:25} {license_id:15} INCOMPATIBLE")
all_ok = False
else:
print(f" {dep_name:25} {license_id:15} REVIEW NEEDED")
print("=" * 60)
if all_ok:
print("All dependencies are license compatible")
else:
print("License compatibility issues found!")
sys.exit(1)
EOF
- name: Generate security report
if: always()
run: |
echo "# Security Scan Report" > security-report.md
echo "" >> security-report.md
echo "**Scan Date**: $(date -u)" >> security-report.md
echo "**Repository**: ${{ github.repository }}" >> security-report.md
echo "**Branch**: ${{ github.ref_name }}" >> security-report.md
echo "**Commit**: ${{ github.sha }}" >> security-report.md
echo "**Severity Threshold**: ${{ env.SEVERITY_CUTOFF }}" >> security-report.md
echo "" >> security-report.md
if [ -f "trivy-results.sarif" ]; then
echo "## Vulnerability Scan" >> security-report.md
echo "" >> security-report.md
echo "Trivy filesystem scan completed. Check the GitHub Security tab" >> security-report.md
echo "for detailed results." >> security-report.md
else
echo "## Vulnerability Scan" >> security-report.md
echo "" >> security-report.md
echo "Scan failed or no results generated." >> security-report.md
fi
- name: Upload security report
uses: actions/upload-artifact@v7
if: always()
continue-on-error: true
with:
name: security-report-${{ github.sha }}
path: security-report.md
retention-days: 30