Files
Juan Denis 727310a703 Run CI on pull requests into dev
CONTRIBUTING asks contributors to target dev, but every workflow only
triggered on PRs into main, so contributor PRs merged with no checks
and failures surfaced only after the push to dev.
2026-10-10 13:26:07 -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, dev]
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