fix: upgrade fastapi to 0.135.1, fix starlette CVEs, update auth test assertions

- fastapi 0.115.0 → 0.135.1 pulls starlette 0.52.1 (fixes CVE-2024-47874, CVE-2025-54121)
- pip-audit: ignore CVE-2024-23342 (ecdsa Minerva attack, no fix exists; app uses HS256 only)
- Update auth guard tests: FastAPI 0.135 returns 401 (not 403) when Bearer token is missing
This commit is contained in:
Pouzor
2026-03-07 15:18:28 +01:00
parent e5262b4b71
commit 1811afa749
7 changed files with 10 additions and 9 deletions
+3 -1
View File
@@ -33,4 +33,6 @@ jobs:
with: with:
python-version: '3.11' python-version: '3.11'
- name: Pip audit - name: Pip audit
run: pip install pip-audit && pip-audit -r backend/requirements.txt # CVE-2024-23342 (ecdsa): timing attack on ECDSA — not exploitable (app uses HS256/HMAC only).
# python-jose forces ecdsa as a dependency with no fixed version available.
run: pip install pip-audit && pip-audit -r backend/requirements.txt --ignore-vuln CVE-2024-23342
+1 -1
View File
@@ -1,5 +1,5 @@
# Requires Python 3.13+ (3.14 not yet supported by pydantic-core) # Requires Python 3.13+ (3.14 not yet supported by pydantic-core)
fastapi==0.115.0 fastapi==0.135.1
uvicorn[standard]==0.30.6 uvicorn[standard]==0.30.6
sqlalchemy[asyncio]==2.0.35 sqlalchemy[asyncio]==2.0.35
aiosqlite==0.20.0 aiosqlite==0.20.0
+1 -1
View File
@@ -30,7 +30,7 @@ async def test_login_wrong_username(client: AsyncClient, mock_credentials):
async def test_protected_route_requires_auth(client: AsyncClient): async def test_protected_route_requires_auth(client: AsyncClient):
res = await client.get("/api/v1/nodes") res = await client.get("/api/v1/nodes")
assert res.status_code == 403 assert res.status_code == 401
async def test_health_is_public(client: AsyncClient): async def test_health_is_public(client: AsyncClient):
+2 -2
View File
@@ -35,7 +35,7 @@ async def test_load_canvas_empty(client: AsyncClient, headers: dict):
async def test_load_canvas_requires_auth(client: AsyncClient): async def test_load_canvas_requires_auth(client: AsyncClient):
res = await client.get("/api/v1/canvas") res = await client.get("/api/v1/canvas")
assert res.status_code == 403 assert res.status_code == 401
# ── save_canvas ─────────────────────────────────────────────────────────────── # ── save_canvas ───────────────────────────────────────────────────────────────
@@ -122,4 +122,4 @@ async def test_save_canvas_persists_edge_custom_color_and_path_style(client: Asy
async def test_save_canvas_requires_auth(client: AsyncClient): async def test_save_canvas_requires_auth(client: AsyncClient):
res = await client.post("/api/v1/canvas/save", json={"nodes": [], "edges": [], "viewport": {}}) res = await client.post("/api/v1/canvas/save", json={"nodes": [], "edges": [], "viewport": {}})
assert res.status_code == 403 assert res.status_code == 401
+1 -1
View File
@@ -99,4 +99,4 @@ async def test_update_edge_custom_color_and_path_style(client: AsyncClient, head
async def test_create_edge_requires_auth(client: AsyncClient, two_nodes): async def test_create_edge_requires_auth(client: AsyncClient, two_nodes):
src, tgt = two_nodes src, tgt = two_nodes
res = await client.post("/api/v1/edges", json={"source": src, "target": tgt, "type": "ethernet"}) res = await client.post("/api/v1/edges", json={"source": src, "target": tgt, "type": "ethernet"})
assert res.status_code == 403 assert res.status_code == 401
+1 -1
View File
@@ -109,4 +109,4 @@ async def test_update_node_container_mode(client: AsyncClient, headers: dict):
async def test_create_node_requires_auth(client: AsyncClient): async def test_create_node_requires_auth(client: AsyncClient):
res = await client.post("/api/v1/nodes", json={"type": "server", "label": "N", "status": "unknown"}) res = await client.post("/api/v1/nodes", json={"type": "server", "label": "N", "status": "unknown"})
assert res.status_code == 403 assert res.status_code == 401
+1 -2
View File
@@ -38,8 +38,7 @@ async def pending_device(db_session):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_trigger_scan_requires_auth(client: AsyncClient): async def test_trigger_scan_requires_auth(client: AsyncClient):
res = await client.post("/api/v1/scan/trigger") res = await client.post("/api/v1/scan/trigger")
# FastAPI's OAuth2PasswordBearer returns 403 when no token is provided assert res.status_code == 401
assert res.status_code in (401, 403)
@pytest.mark.asyncio @pytest.mark.asyncio