security: pip-audit + bandit gates that can fail; patch 29 known CVEs

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.
This commit is contained in:
grabowski committed 2026-09-11 23:44:43 +02:00
1 parent 97a6694ab2
commit b03318210c
14 files changed
+285 -1048

No files matched your search

+28 -24
View File
@@ -139,12 +139,16 @@ class InfluxDBAdapter(DatabaseAdapter):
"time": measurement["timestamp"].isoformat(),
"fields": {
"water_level": float(measurement["water_level"]),
"discharge": float(measurement["discharge"])
if measurement.get("discharge") is not None
else None,
"discharge_percent": float(measurement["discharge_percent"])
if measurement.get("discharge_percent")
else None,
"discharge": (
float(measurement["discharge"])
if measurement.get("discharge") is not None
else None
),
"discharge_percent": (
float(measurement["discharge_percent"])
if measurement.get("discharge_percent")
else None
),
},
}
points.append(point)
@@ -551,13 +555,13 @@ class SQLAdapter(DatabaseAdapter):
"station_code": row[1],
"station_name_en": row[2],
"station_name_th": row[3],
"water_level": float(row[4])
if row[4] is not None
else None,
"water_level": (
float(row[4]) if row[4] is not None else None
),
"discharge": float(row[5]) if row[5] is not None else None,
"discharge_percent": float(row[6])
if row[6] is not None
else None,
"discharge_percent": (
float(row[6]) if row[6] is not None else None
),
"status": row[7],
}
)
@@ -611,13 +615,13 @@ class SQLAdapter(DatabaseAdapter):
"station_code": row[1],
"station_name_en": row[2],
"station_name_th": row[3],
"water_level": float(row[4])
if row[4] is not None
else None,
"water_level": (
float(row[4]) if row[4] is not None else None
),
"discharge": float(row[5]) if row[5] is not None else None,
"discharge_percent": float(row[6])
if row[6] is not None
else None,
"discharge_percent": (
float(row[6]) if row[6] is not None else None
),
"status": row[7],
}
)
@@ -666,13 +670,13 @@ class SQLAdapter(DatabaseAdapter):
"station_id": row[1],
"station_code": row[2] or f"Station_{row[1]}",
"station_name_th": row[3] or f"Station {row[1]}",
"water_level": float(row[4])
if row[4] is not None
else None,
"water_level": (
float(row[4]) if row[4] is not None else None
),
"discharge": float(row[5]) if row[5] is not None else None,
"discharge_percent": float(row[6])
if row[6] is not None
else None,
"discharge_percent": (
float(row[6]) if row[6] is not None else None
),
"status": row[7],
}
)