feat: 31 new tests, metrics LLM counters, Dockerfile caching, Makefile targets, compose limits, code fixes
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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]))
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user