Files
ServerKit/.github/workflows/security-scan.yml
T
Juan DenisandClaude Opus 5 44f5a32867 ci: stop validating the same commit twice
These five workflows triggered on both `push: [dev, main]` and
`pull_request: [dev, main]`, so one change was validated up to three times: on
the dev push, again on the dev->main PR, and a third time on the post-merge
push to main.

Narrow them to `push: [dev]` + `pull_request: [main]`:

- `pull_request: [dev]` was dead config. Every PR this repo has had targets
  main (checked back through #77, dependabot's included), so it never produced
  a run.
- `push: [main]` was redundant for release-smoke: release.yml's build-release
  job runs that same scripts/build-release.sh for real, on the same commit,
  moments later.

Also drops test-system-utils' `unit-tests` job. It ran
`pytest tests/test_utils_system.py` (44 tests) that Backend CI's bare `pytest`
already collects — there is no pytest.ini, addopts or collect_ignore narrowing
collection. The distro matrix and the raw-subprocess audit stay; those are the
parts Backend CI genuinely cannot do.

Coverage of main is unchanged: a pull_request run tests the merge result, and
release.yml still gates itself on the full backend suite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 01:17:20 -04:00

115 lines
4.7 KiB
YAML

name: Security Scan
on:
push:
branches: [dev]
paths:
- 'backend/**'
- '.github/workflows/security-scan.yml'
pull_request:
branches: [main]
paths:
- 'backend/**'
- '.github/workflows/security-scan.yml'
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
- name: Run Bandit scan
working-directory: backend
run: |
echo "## Full report (MEDIUM+ severity, MEDIUM+ confidence)"
echo ""
bandit -r app/ \
--severity-level medium \
--confidence-level medium \
-f txt \
--exit-zero
echo ""
echo "---"
echo ""
echo "## Strict gate (HIGH severity, HIGH confidence, new issues only)"
echo "Known accepts: B602 (shell=True for build/deploy scripts),"
echo " B402/B321 (FTP management feature), B202 (tarfile for backups)"
echo ""
bandit -r app/ \
--severity-level high \
--confidence-level high \
--skip B602,B402,B321,B202 \
-f txt
# ──────────────────────────────────────────────────────────────────
# 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
# ──────────────────────────────────────────────────────────────────
# 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