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:
@@ -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,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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user