refactor: FastAPI best practices — return types, Pydantic schemas, middleware, code dedup

- Все 18 роутов получили return type annotations
- Создан schemas.py с Pydantic-моделями (ScanOut, PackageOut, FindingOut, ...)
- API-роуты: response_model на list/detail/export/stats
- 404 через HTTPException(404) вместо {'detail':'Not found'} (200)
- RequestLoggingMiddleware: method, path, status, duration_ms
- Глобальный exception handler: ловит необработанные исключения → 500
- _parse_flagged(): вынесен дублирующийся string→bool
- parse_package_path(): общий для web.py и api_packages.py
- selectinload: вынесены в top-level imports
- harvester: makedirs/mkdtemp/rmtree обёрнуты в asyncio.to_thread()
This commit is contained in:
Marker689
2026-05-10 12:53:33 +03:00
parent 935d96b35a
commit c1258dde99
11 changed files with 188 additions and 55 deletions

View File

@@ -3,6 +3,7 @@
import asyncio
import hashlib
import os
from urllib.parse import unquote
import httpx
@@ -89,6 +90,15 @@ def extract_package_info(asset_path: str, ecosystem: str) -> tuple[str, str] | N
return None
def parse_package_path(path: str) -> tuple[str, str]:
"""Parse a URL path like 'eviltest/0.1.0' or 'github.com/attacker/evilmodule/v0.1.0'
into (package_name, package_version)."""
parts = path.rsplit("/", 1)
pkg_name = unquote(parts[0])
pkg_version = unquote(parts[1]) if len(parts) == 2 else ""
return pkg_name, pkg_version
async def download_asset(download_url: str, dest_dir: str) -> str | None:
"""Download an asset from Nexus using async httpx."""
dest_path = os.path.join(dest_dir, os.path.basename(download_url.split("?")[0]))