name: Vulnerability Scan on: pull_request: push: branches: [main] schedule: # Run weekly on Monday at 9:00 UTC - cron: '0 9 * * 1' permissions: contents: read jobs: pip-audit: name: pip-audit runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Restore global uv cache id: cache-restore uses: actions/cache/restore@v4 with: path: | ~/.cache/uv ~/.local/share/uv .venv key: uv-main-py3.11-${{ hashFiles('uv.lock') }} restore-keys: | uv-main-py3.11- - name: Install uv uses: astral-sh/setup-uv@v6 with: version: "0.11.3" python-version: "3.11" enable-cache: false - name: Install dependencies run: uv sync --all-groups --all-extras --no-install-project - name: Install pip-audit run: uv pip install pip-audit - name: Run pip-audit run: | uv run pip-audit --desc --aliases --skip-editable --format json --output pip-audit-report.json \ --ignore-vuln CVE-2025-69872 \ --ignore-vuln CVE-2026-25645 \ --ignore-vuln CVE-2026-27448 \ --ignore-vuln CVE-2026-27459 \ --ignore-vuln PYSEC-2023-235 # Ignored CVEs: # CVE-2025-69872 - diskcache 5.6.3: no fix available (latest version) # CVE-2026-25645 - requests 2.32.5: fix requires 2.33.0, blocked by crewai-tools ~=2.32.5 pin # CVE-2026-27448 - pyopenssl 25.3.0: fix requires 26.0.0, blocked by snowflake-connector-python <26.0.0 pin # CVE-2026-27459 - pyopenssl 25.3.0: same as above # PYSEC-2023-235 - couchbase: fixed in 4.6.0 (already upgraded), advisory not yet updated continue-on-error: true - name: Display results if: always() run: | if [ -f pip-audit-report.json ]; then echo "## pip-audit Results" >> $GITHUB_STEP_SUMMARY echo '```json' >> $GITHUB_STEP_SUMMARY cat pip-audit-report.json | python3 -m json.tool >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY # Fail if vulnerabilities found python3 -c " import json, sys with open('pip-audit-report.json') as f: data = json.load(f) vulns = [d for d in data.get('dependencies', []) if d.get('vulns')] if vulns: print(f'::error::Found vulnerabilities in {len(vulns)} package(s)') for v in vulns: for vuln in v['vulns']: print(f' - {v[\"name\"]}=={v[\"version\"]}: {vuln[\"id\"]}') sys.exit(1) print('No known vulnerabilities found') " else echo "::error::pip-audit failed to produce a report. Check the pip-audit step logs." exit 1 fi - name: Upload pip-audit report if: always() uses: actions/upload-artifact@v4 with: name: pip-audit-report path: pip-audit-report.json - name: Save uv caches if: steps.cache-restore.outputs.cache-hit != 'true' uses: actions/cache/save@v4 with: path: | ~/.cache/uv ~/.local/share/uv .venv key: uv-main-py3.11-${{ hashFiles('uv.lock') }}