security.yml previously ran safety/bandit/semgrep with `|| true` and could not go red. Now: pip-audit on requirements.txt is a hard gate (dev deps reported only), bandit HIGH fails (B104 bind-all skipped: intended behind Cloudflare/Caddy), pip-licenses uploaded as a report. Weekly + on dependency/source changes. Running it locally found 29 advisories, all in pinned-and-forgotten runtime deps: starlette 0.27 (7, incl. Host-header path confusion and form DoS), fastapi 0.104, requests 2.31 (3), pymysql 1.1. Bumped to current: fastapi 0.141.1 / starlette 1.6.0, pydantic 2.13.5, uvicorn 0.52.4, requests 2.34.2, pymysql 1.2.0; dev: pytest 9.1.1, black 26.5.1. pip-audit is now clean. requires-python narrowed to 3.11 (the truth: psycopg2-binary 2.9.9 fails on 3.13; pandas 2.0.3 has no 3.12 wheels). Full suite passes; API smoke-tested (health, stations, forecast, history, stats, docs, openapi) on the new stack. black 26 reformatted 8 files.
76 lines
2.3 KiB
YAML
76 lines
2.3 KiB
YAML
name: CI
|
|
|
|
# What this checks, on every push and PR to master:
|
|
# 1. formatting contract (black + isort, config in pyproject.toml)
|
|
# 2. flake8 hard-error gate (syntax, undefined names)
|
|
# 3. the pytest suite (synthetic data, no DB/network; ~1 min)
|
|
# Docker build / staging / production / perf jobs from the original template
|
|
# were removed: there is no registry, no staging host, and production is a
|
|
# systemd unit deployed by `git pull` on the server (docs/FLOOD_FORECASTING.md
|
|
# section 6, scripts/install.sh). Re-add a job when the thing it deploys exists.
|
|
|
|
on:
|
|
push:
|
|
branches: [master, develop]
|
|
pull_request:
|
|
branches: [master]
|
|
schedule:
|
|
# daily, catches dependency drift / upstream API changes in the tests
|
|
- cron: "0 2 * * *"
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
PYTHON_VERSION: "3.11" # pandas 2.0.3 ships no 3.12 wheels; psycopg2-binary 2.9.9 breaks on 3.13
|
|
|
|
jobs:
|
|
lint:
|
|
name: Format & lint
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
cache: pip
|
|
cache-dependency-path: requirements-dev.txt
|
|
|
|
- name: Install tools
|
|
run: |
|
|
python -m pip install --upgrade pip --root-user-action=ignore
|
|
pip install --root-user-action=ignore black==26.5.1 isort==5.12.0 flake8==6.1.0
|
|
|
|
- name: black
|
|
run: black --check --diff src/ *.py
|
|
|
|
- name: isort
|
|
run: isort --check-only --diff src/ *.py
|
|
|
|
- name: flake8 (errors only)
|
|
run: flake8 src/ --count --select=E9,F63,F7,F82 --show-source --statistics
|
|
|
|
test:
|
|
name: Test suite
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
cache: pip
|
|
cache-dependency-path: |
|
|
requirements.txt
|
|
requirements-dev.txt
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
python -m pip install --upgrade pip --root-user-action=ignore
|
|
pip install --root-user-action=ignore -r requirements.txt
|
|
pip install --root-user-action=ignore pytest==9.1.1 pytest-asyncio==0.21.1
|
|
|
|
- name: pytest
|
|
env:
|
|
DB_TYPE: sqlite
|
|
run: pytest -q -p no:cacheprovider
|