fix: reject unknown ecosystems instead of silently defaulting to pypi

This commit is contained in:
Marker689
2026-05-11 19:59:47 +03:00
parent a6cd20e41c
commit fb5559b8b7
3 changed files with 25 additions and 5 deletions

View File

@@ -10,7 +10,6 @@ from fastapi import APIRouter, BackgroundTasks, Header, HTTPException, Request,
from ..config import config from ..config import config
from ..constants import ( from ..constants import (
DEFAULT_ECOSYSTEM,
METADATA_PATTERNS, METADATA_PATTERNS,
PACKAGE_EXTENSIONS, PACKAGE_EXTENSIONS,
RELEVANT_WEBHOOK_ACTIONS, RELEVANT_WEBHOOK_ACTIONS,
@@ -50,7 +49,7 @@ def _extract_asset_path(asset: dict) -> str | None:
return None return None
def _detect_ecosystem(source: dict) -> str: def _detect_ecosystem(source: dict) -> str | None:
"""Detect ecosystem from asset or component format field.""" """Detect ecosystem from asset or component format field."""
fmt = source.get("format", "").lower() fmt = source.get("format", "").lower()
if fmt in ("pypi", "pip", "python"): if fmt in ("pypi", "pip", "python"):
@@ -59,7 +58,7 @@ def _detect_ecosystem(source: dict) -> str:
return "go" return "go"
if fmt in ("npm", "node"): if fmt in ("npm", "node"):
return "npm" return "npm"
return DEFAULT_ECOSYSTEM return None
@router.post("/nexus") @router.post("/nexus")
@@ -121,6 +120,8 @@ async def nexus_webhook(
download_url = asset.get("downloadUrl") or _build_download_url(repository, asset_path) download_url = asset.get("downloadUrl") or _build_download_url(repository, asset_path)
ecosystem = _detect_ecosystem(asset) ecosystem = _detect_ecosystem(asset)
if ecosystem is None:
return {"status": WEBHOOK_STATUS_IGNORED, "reason": "unknown_ecosystem"}
log.info("Webhook: %s asset %s (%s) in %s", action, asset_path, ecosystem, repository) log.info("Webhook: %s asset %s (%s) in %s", action, asset_path, ecosystem, repository)
@@ -145,6 +146,9 @@ async def nexus_webhook(
} }
ecosystem = _detect_ecosystem(component) ecosystem = _detect_ecosystem(component)
if ecosystem is None:
return {"status": WEBHOOK_STATUS_IGNORED, "reason": "unknown_ecosystem"}
background_tasks.add_task(_scan_component, repository, name, version, ecosystem) background_tasks.add_task(_scan_component, repository, name, version, ecosystem)
return { return {
"status": WEBHOOK_STATUS_ACCEPTED, "status": WEBHOOK_STATUS_ACCEPTED,

View File

@@ -201,6 +201,22 @@ class TestErrorHandlingE2e:
resp = await e2e_client.post("/webhooks/nexus", json=payload) resp = await e2e_client.post("/webhooks/nexus", json=payload)
assert resp.status_code == 400 assert resp.status_code == 400
@pytest.mark.asyncio
async def test_e2e_webhook_unknown_ecosystem(self, e2e_client):
"""Verify that webhooks with unknown ecosystem are rejected."""
payload = {
"action": "UPDATED",
"repositoryName": "test-repo",
"asset": {
"format": "maven",
"name": "/packages/test/1.0/test-1.0.tar.gz",
},
}
resp = await e2e_client.post("/webhooks/nexus", json=payload)
assert resp.status_code == 200
assert resp.json()["status"] == "ignored"
assert resp.json()["reason"] == "unknown_ecosystem"
class TestWebsocketFragmentE2e: class TestWebsocketFragmentE2e:
"""E2E tests for HTMX fragment responses.""" """E2E tests for HTMX fragment responses."""

View File

@@ -112,8 +112,8 @@ def test_detect_ecosystem_npm():
def test_detect_ecosystem_unknown(): def test_detect_ecosystem_unknown():
from guarddog_nexus.routes.webhooks import _detect_ecosystem from guarddog_nexus.routes.webhooks import _detect_ecosystem
assert _detect_ecosystem({"format": "maven"}) == "pypi" # unknown → default assert _detect_ecosystem({"format": "maven"}) is None
assert _detect_ecosystem({}) == "pypi" # default assert _detect_ecosystem({}) is None
# --- Go/npm webhook integration --- # --- Go/npm webhook integration ---