refactor: реструктуризация — core/, db/, routes/, web/
guarddog_nexus/ ├── core/ scanner, harvester, nexus, llm ├── db/ engine, models, queries ├── routes/ webhooks, api_*, web └── web/ templates + static - 11 файлов перемещено (git mv — сохранена история) - Все импорты обновлены (~15 файлов) - main.py, tests — исправлены пути - 50/50 тестов, ruff clean
This commit is contained in:
@@ -9,17 +9,17 @@ import tempfile
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from guarddog_nexus.config import config
|
||||
from guarddog_nexus.constants import (
|
||||
from ..config import config
|
||||
from ..constants import (
|
||||
DEFAULT_ECOSYSTEM,
|
||||
ERROR_MESSAGE_MAX_LENGTH,
|
||||
PACKAGE_EXTENSIONS,
|
||||
SCAN_ERROR_DOWNLOAD_FAILED,
|
||||
)
|
||||
from guarddog_nexus.logging_setup import log
|
||||
from guarddog_nexus.models import Finding, Scan, ScanStatus
|
||||
from guarddog_nexus.nexus_client import compute_sha256, download_asset, extract_package_info
|
||||
from guarddog_nexus.scanner import scan_package
|
||||
from ..db.models import Finding, Scan, ScanStatus
|
||||
from ..logging_setup import log
|
||||
from .nexus import compute_sha256, download_asset, extract_package_info
|
||||
from .scanner import scan_package
|
||||
|
||||
# Per-URL locks to avoid parallel scans of the same asset
|
||||
_url_locks: dict[str, asyncio.Lock] = {}
|
||||
@@ -193,7 +193,7 @@ async def harvest(
|
||||
|
||||
async def _run_llm_analysis(findings: list[Finding], session: AsyncSession) -> list[dict]:
|
||||
"""Run LLM analysis on findings and persist reports to the database."""
|
||||
from guarddog_nexus.llm import analyze_finding
|
||||
from .llm import analyze_finding
|
||||
|
||||
reports = []
|
||||
for finding in findings:
|
||||
@@ -7,9 +7,9 @@ import json
|
||||
|
||||
import httpx
|
||||
|
||||
from guarddog_nexus.config import config
|
||||
from guarddog_nexus.constants import LLM_ANALYSIS_SYSTEM_PROMPT
|
||||
from guarddog_nexus.logging_setup import log
|
||||
from ..config import config
|
||||
from ..constants import LLM_ANALYSIS_SYSTEM_PROMPT
|
||||
from ..logging_setup import log
|
||||
|
||||
|
||||
def _build_user_message(finding: dict) -> str:
|
||||
@@ -5,13 +5,13 @@ import os
|
||||
|
||||
import httpx
|
||||
|
||||
from guarddog_nexus.config import config
|
||||
from guarddog_nexus.constants import (
|
||||
from ..config import config
|
||||
from ..constants import (
|
||||
NPM_PATH_PREFIX,
|
||||
PYPI_PATH_PREFIX,
|
||||
SHA256_CHUNK_SIZE,
|
||||
)
|
||||
from guarddog_nexus.logging_setup import log
|
||||
from ..logging_setup import log
|
||||
|
||||
|
||||
def extract_pypi_info(asset_path: str) -> tuple[str, str] | None:
|
||||
@@ -3,8 +3,8 @@
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
from guarddog_nexus.config import config
|
||||
from guarddog_nexus.constants import (
|
||||
from ..config import config
|
||||
from ..constants import (
|
||||
DEFAULT_ECOSYSTEM,
|
||||
DEFAULT_FINDING_SEVERITY,
|
||||
GUARDDOG_OUTPUT_FORMAT,
|
||||
@@ -14,7 +14,7 @@ from guarddog_nexus.constants import (
|
||||
SCAN_ERROR_JSON_PARSE,
|
||||
SCAN_ERROR_TIMEOUT,
|
||||
)
|
||||
from guarddog_nexus.logging_setup import log
|
||||
from ..logging_setup import log
|
||||
|
||||
|
||||
async def scan_package(filepath: str, ecosystem: str = DEFAULT_ECOSYSTEM) -> dict:
|
||||
@@ -20,7 +20,7 @@ class Base(DeclarativeBase):
|
||||
|
||||
async def _migrate():
|
||||
"""Add any missing columns from model definitions to existing SQLite tables."""
|
||||
import guarddog_nexus.models # noqa: F401
|
||||
import guarddog_nexus.db.models # noqa: F401
|
||||
|
||||
async with _engine.connect() as conn:
|
||||
for table in Base.metadata.sorted_tables:
|
||||
@@ -63,7 +63,7 @@ async def _migrate():
|
||||
|
||||
|
||||
async def init_db():
|
||||
import guarddog_nexus.models # noqa: F401
|
||||
import guarddog_nexus.db.models # noqa: F401
|
||||
|
||||
async with _engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
@@ -6,7 +6,7 @@ from enum import Enum
|
||||
from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, Integer, String, Text, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from guarddog_nexus.database import Base
|
||||
from guarddog_nexus.db.engine import Base
|
||||
|
||||
|
||||
class ScanStatus(str, Enum):
|
||||
@@ -20,7 +20,7 @@ from guarddog_nexus.constants import (
|
||||
SCAN_SORT_FIELDS,
|
||||
TOP_RULES_LIMIT,
|
||||
)
|
||||
from guarddog_nexus.models import Finding, Scan
|
||||
from guarddog_nexus.db.models import Finding, Scan
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Scan list query builder
|
||||
@@ -5,8 +5,8 @@ import logging
|
||||
import sys
|
||||
from logging.handlers import SysLogHandler
|
||||
|
||||
from guarddog_nexus.config import config
|
||||
from guarddog_nexus.constants import APP_PACKAGE
|
||||
from .config import config
|
||||
from .constants import APP_PACKAGE
|
||||
|
||||
|
||||
class JsonFormatter(logging.Formatter):
|
||||
|
||||
@@ -7,13 +7,13 @@ import uvicorn
|
||||
from fastapi import FastAPI
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from guarddog_nexus.api import findings, packages, scans
|
||||
from guarddog_nexus.config import config
|
||||
from guarddog_nexus.constants import APP_DESCRIPTION, APP_NAME, APP_PACKAGE, STATIC_MOUNT_PATH
|
||||
from guarddog_nexus.database import init_db
|
||||
from guarddog_nexus.db.engine import init_db
|
||||
from guarddog_nexus.logging_setup import log
|
||||
from guarddog_nexus.web.routes import router as web_router
|
||||
from guarddog_nexus.webhooks import router as webhook_router
|
||||
from guarddog_nexus.routes import api_findings, api_packages, api_scans
|
||||
from guarddog_nexus.routes.web import router as web_router
|
||||
from guarddog_nexus.routes.webhooks import router as webhook_router
|
||||
|
||||
STATIC_DIR = os.path.join(os.path.dirname(__file__), "web", "static")
|
||||
|
||||
@@ -34,9 +34,9 @@ app = FastAPI(
|
||||
)
|
||||
|
||||
app.include_router(webhook_router)
|
||||
app.include_router(scans.router)
|
||||
app.include_router(packages.router)
|
||||
app.include_router(findings.router)
|
||||
app.include_router(api_scans.router)
|
||||
app.include_router(api_packages.router)
|
||||
app.include_router(api_findings.router)
|
||||
app.include_router(web_router)
|
||||
|
||||
if os.path.isdir(STATIC_DIR):
|
||||
|
||||
0
guarddog_nexus/routes/__init__.py
Normal file
0
guarddog_nexus/routes/__init__.py
Normal file
@@ -4,16 +4,16 @@ from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from guarddog_nexus.config import config
|
||||
from guarddog_nexus.constants import (
|
||||
from ..config import config
|
||||
from ..constants import (
|
||||
DEFAULT_OFFSET,
|
||||
DEFAULT_PAGE_SIZE,
|
||||
JSON_PATH_RULE,
|
||||
JSON_PATH_SEVERITY,
|
||||
MAX_PAGE_SIZE,
|
||||
)
|
||||
from guarddog_nexus.database import get_session
|
||||
from guarddog_nexus.models import Finding
|
||||
from ..db.engine import get_session
|
||||
from ..db.models import Finding
|
||||
|
||||
router = APIRouter(prefix="/api/v1/findings", tags=["findings"])
|
||||
|
||||
@@ -70,7 +70,7 @@ async def analyze_finding_endpoint(
|
||||
if not finding:
|
||||
return {"detail": "Not found"}
|
||||
|
||||
from guarddog_nexus.llm import analyze_finding
|
||||
from ..core.llm import analyze_finding
|
||||
|
||||
report = await analyze_finding(finding.data)
|
||||
if report is None:
|
||||
@@ -8,7 +8,7 @@ from fastapi import APIRouter, Depends, Query, Response
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from guarddog_nexus.constants import (
|
||||
from ..constants import (
|
||||
CSV_MEDIA_TYPE,
|
||||
DEFAULT_OFFSET,
|
||||
DEFAULT_PAGE_SIZE,
|
||||
@@ -16,9 +16,9 @@ from guarddog_nexus.constants import (
|
||||
DEFAULT_SORT_DIR,
|
||||
MAX_PAGE_SIZE,
|
||||
)
|
||||
from guarddog_nexus.database import get_session
|
||||
from guarddog_nexus.models import Finding, Scan
|
||||
from guarddog_nexus.queries import build_package_list_query
|
||||
from ..db.engine import get_session
|
||||
from ..db.models import Finding, Scan
|
||||
from ..db.queries import build_package_list_query
|
||||
|
||||
router = APIRouter(prefix="/api/v1/packages", tags=["packages"])
|
||||
|
||||
@@ -8,7 +8,7 @@ from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from guarddog_nexus.constants import (
|
||||
from ..constants import (
|
||||
CSV_MEDIA_TYPE,
|
||||
DEFAULT_OFFSET,
|
||||
DEFAULT_PAGE_SIZE,
|
||||
@@ -16,9 +16,9 @@ from guarddog_nexus.constants import (
|
||||
DEFAULT_SORT_DIR,
|
||||
MAX_PAGE_SIZE,
|
||||
)
|
||||
from guarddog_nexus.database import get_session
|
||||
from guarddog_nexus.models import Scan
|
||||
from guarddog_nexus.queries import build_scan_list_query, get_dashboard_stats
|
||||
from ..db.engine import get_session
|
||||
from ..db.models import Scan
|
||||
from ..db.queries import build_scan_list_query, get_dashboard_stats
|
||||
|
||||
router = APIRouter(prefix="/api/v1/scans", tags=["scans"])
|
||||
|
||||
@@ -8,16 +8,16 @@ from jinja2 import Environment, PackageLoader, select_autoescape
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from guarddog_nexus.constants import (
|
||||
from ..constants import (
|
||||
APP_PACKAGE,
|
||||
DEFAULT_SORT_BY_PACKAGES,
|
||||
DEFAULT_SORT_BY_SCANS,
|
||||
DEFAULT_SORT_DIR,
|
||||
WEB_PER_PAGE,
|
||||
)
|
||||
from guarddog_nexus.database import get_session
|
||||
from guarddog_nexus.models import Finding, Scan
|
||||
from guarddog_nexus.queries import (
|
||||
from ..db.engine import get_session
|
||||
from ..db.models import Finding, Scan
|
||||
from ..db.queries import (
|
||||
build_package_list_query,
|
||||
build_scan_list_query,
|
||||
get_dashboard_stats,
|
||||
@@ -206,8 +206,8 @@ async def analyze_finding_htmx(
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
"""HTMX fragment: trigger LLM analysis and return styled result HTML."""
|
||||
from guarddog_nexus.config import config
|
||||
from guarddog_nexus.llm import analyze_finding
|
||||
from ..config import config
|
||||
from ..core.llm import analyze_finding
|
||||
|
||||
if not config.llm_enabled:
|
||||
return HTMLResponse(
|
||||
@@ -7,8 +7,8 @@ import re
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, Header, HTTPException, Request, status
|
||||
|
||||
from guarddog_nexus.config import config
|
||||
from guarddog_nexus.constants import (
|
||||
from ..config import config
|
||||
from ..constants import (
|
||||
DEFAULT_ECOSYSTEM,
|
||||
METADATA_PATTERNS,
|
||||
PACKAGE_EXTENSIONS,
|
||||
@@ -19,9 +19,9 @@ from guarddog_nexus.constants import (
|
||||
WEBHOOK_STATUS_ACCEPTED,
|
||||
WEBHOOK_STATUS_IGNORED,
|
||||
)
|
||||
from guarddog_nexus.database import get_session
|
||||
from guarddog_nexus.harvester import harvest
|
||||
from guarddog_nexus.logging_setup import log
|
||||
from ..core.harvester import harvest
|
||||
from ..db.engine import get_session
|
||||
from ..logging_setup import log
|
||||
|
||||
router = APIRouter(prefix="/webhooks", tags=["webhooks"])
|
||||
|
||||
@@ -141,7 +141,7 @@ async def nexus_webhook(
|
||||
|
||||
|
||||
async def _scan_component(repository: str, name: str, version: str, ecosystem: str):
|
||||
from guarddog_nexus.nexus_client import nexus_get
|
||||
from ..core.nexus import nexus_get
|
||||
|
||||
api_path = (
|
||||
f"/service/rest/v1/search"
|
||||
Reference in New Issue
Block a user