Files
ServerKit/.github/workflows/security-scan.yml
Juan Denis da0f18146b ci(security): expand scans and narrow Bandit exceptions
Schedule dependency and extension scans, audit production frontend dependencies, and replace category suppressions with reviewed function-specific exceptions. Preserve full reports and test the exception gate.
2026-09-05 04:30:11 -04:00

144 lines
5.7 KiB
YAML

name: Security Scan
on:
push:
branches: [dev]
paths:
- 'backend/**'
- 'builtin-extensions/**'
- '**/requirements*.txt'
- 'frontend/package*.json'
- 'scripts/check-bandit-report.py'
- 'scripts/security/**'
- '.github/workflows/security-scan.yml'
pull_request:
branches: [main]
paths:
- 'backend/**'
- 'builtin-extensions/**'
- '**/requirements*.txt'
- 'frontend/package*.json'
- 'scripts/check-bandit-report.py'
- 'scripts/security/**'
- '.github/workflows/security-scan.yml'
schedule:
- cron: '17 9 * * 1' # Weekly; advisories change even without repository changes.
workflow_dispatch:
permissions:
contents: read
jobs:
# ──────────────────────────────────────────────────────────────────
# Job 1: Bandit — static analysis for Python security issues
# ──────────────────────────────────────────────────────────────────
bandit:
name: Bandit SAST
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Bandit
run: pip install bandit==1.9.3
- name: Run Bandit scan
run: |
python -m unittest discover -s scripts/security -p 'test_*.py'
bandit -r backend/app builtin-extensions -f json -o bandit-report.json --exit-zero
python scripts/check-bandit-report.py bandit-report.json
- name: Upload full Bandit report
if: always()
uses: actions/upload-artifact@v4
with:
name: bandit-report
path: bandit-report.json
if-no-files-found: warn
# ──────────────────────────────────────────────────────────────────
# Job 2: pip-audit — dependency vulnerability scanning (the gate)
#
# This is the blocking check. Unlike the Safety job below it needs no
# account, no API key and no network-fetched policy: it resolves the pinned
# requirements against the PyPI Advisory Database and fails on anything it
# finds. Every suppression therefore has to live in THIS file, in a diff a
# reviewer can see — which is the whole point. Safety was reporting
# "No issues found" while its Platform-side policy silently ignored four
# advisories, one of them a real, fixable CVE in a directly pinned package.
# ──────────────────────────────────────────────────────────────────
pip-audit:
name: pip-audit Dependency Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install pip-audit
run: pip install pip-audit
# No --ignore-vuln entries today. If one is ever needed, add it here with
# a comment saying which advisory, why it does not apply, and when to
# revisit — never by silencing the scanner globally.
- name: Audit backend requirements
run: pip-audit -r backend/requirements.txt --progress-spinner off
- name: Audit test-harness requirements
run: pip-audit -r scripts/test/harness/requirements.txt --progress-spinner off
- name: Audit extension requirements
shell: bash
run: |
while IFS= read -r -d '' requirements; do
pip-audit -r "$requirements" --progress-spinner off
done < <(find builtin-extensions -type f -name 'requirements*.txt' -print0)
npm-audit:
name: Frontend Production Dependency Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Audit production dependency lockfile
working-directory: frontend
# No installation or package scripts are needed to audit the lockfile.
run: npm audit --package-lock-only --omit=dev --audit-level=high
# ──────────────────────────────────────────────────────────────────
# Job 3: Safety — advisory only
#
# Kept for the Safety Platform dashboard, but deliberately NOT a gate.
# The action shells out to a hosted service, and a service-side failure
# there (results upload erroring with "Sorry, something went wrong" while
# the scan itself reported clean) took CI red on 2026-07-20 with no repo
# change behind it — requirements had not moved since 2026-07-04. An
# outage at a third party should not block merges; pip-audit above is the
# check that actually has to pass.
# ──────────────────────────────────────────────────────────────────
safety:
name: Safety Dependency Scan (advisory)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Run Safety CLI to check for vulnerabilities
continue-on-error: true
uses: pyupio/safety-action@v1
with:
api-key: ${{ secrets.SAFETY_API_KEY }}
args: --full-report