feat: 31 new tests, metrics LLM counters, Dockerfile caching, Makefile targets, compose limits, code fixes

This commit is contained in:
Marker689
2026-05-11 23:08:09 +03:00
parent 20bf7e6745
commit 18efcf482e
26 changed files with 840 additions and 12 deletions

View File

@@ -23,12 +23,13 @@ _REPORT_DEFAULTS = {
def _validate_report(report: dict) -> dict:
result = dict(report)
for field, default in _REPORT_DEFAULTS.items():
if not report.get(field):
report[field] = default
if report["verdict"] not in ("safe", "suspicious", "malicious", "unknown"):
report["verdict"] = "unknown"
return report
if not result.get(field):
result[field] = default
if result["verdict"] not in ("safe", "suspicious", "malicious", "unknown"):
result["verdict"] = "unknown"
return result
def _build_user_message(finding: dict) -> str:

View File

@@ -122,7 +122,8 @@ def parse_package_path(path: str) -> tuple[str, str]:
async def download_asset(download_url: str, dest_dir: str) -> str | None:
"""Download an asset from Nexus using async httpx."""
if not _validate_download_url(download_url):
log.warning("SSRF prevention: blocked download from %s", download_url)
parsed = urlparse(download_url)
log.warning("SSRF prevention: blocked download from %s", parsed.hostname or "unknown")
return None
dest_path = os.path.join(dest_dir, os.path.basename(download_url.split("?")[0]))

View File

@@ -33,6 +33,19 @@ async def metrics(session: AsyncSession = Depends(get_session)) -> Response:
# Latest scan timestamp
latest = await session.scalar(select(func.max(Scan.started_at)))
# LLM analysis
analyzed = (
await session.scalar(
select(func.count(Finding.id)).where(
func.json_extract(Finding.report, "$.verdict").isnot(None)
)
)
or 0
)
pending = (
await session.scalar(select(func.count(Finding.id)).where(Finding.report.is_(None))) or 0
)
lines = [
"# HELP guarddog_scans_total Total number of package scans.",
"# TYPE guarddog_scans_total counter",
@@ -46,6 +59,14 @@ async def metrics(session: AsyncSession = Depends(get_session)) -> Response:
"# TYPE guarddog_findings_total counter",
f"guarddog_findings_total {findings_total}",
"",
"# HELP guarddog_llm_analyzed_total Total findings analyzed by LLM.",
"# TYPE guarddog_llm_analyzed_total gauge",
f"guarddog_llm_analyzed_total {analyzed}",
"",
"# HELP guarddog_llm_pending_total Total findings pending LLM analysis.",
"# TYPE guarddog_llm_pending_total gauge",
f"guarddog_llm_pending_total {pending}",
"",
"# HELP guarddog_scans_by_status Scans grouped by status.",
"# TYPE guarddog_scans_by_status gauge",
]

View File

@@ -60,7 +60,11 @@ def _render(name: str, **context) -> HTMLResponse:
def _parse_flagged(value: str) -> bool | None:
return True if value == "1" else None
if value == "1":
return True
if value == "0":
return False
return None
@router.get("/", response_class=HTMLResponse)