From fb5559b8b76d514ccaa347b49885add44a42fa18 Mon Sep 17 00:00:00 2001 From: Marker689 Date: Mon, 11 May 2026 19:59:47 +0300 Subject: [PATCH] fix: reject unknown ecosystems instead of silently defaulting to pypi --- guarddog_nexus/routes/webhooks.py | 10 +++++++--- tests/e2e/test_llm_and_edge_cases.py | 16 ++++++++++++++++ tests/test_webhooks.py | 4 ++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/guarddog_nexus/routes/webhooks.py b/guarddog_nexus/routes/webhooks.py index 27ce5e8..cec7d6a 100644 --- a/guarddog_nexus/routes/webhooks.py +++ b/guarddog_nexus/routes/webhooks.py @@ -10,7 +10,6 @@ from fastapi import APIRouter, BackgroundTasks, Header, HTTPException, Request, from ..config import config from ..constants import ( - DEFAULT_ECOSYSTEM, METADATA_PATTERNS, PACKAGE_EXTENSIONS, RELEVANT_WEBHOOK_ACTIONS, @@ -50,7 +49,7 @@ def _extract_asset_path(asset: dict) -> str | None: return None -def _detect_ecosystem(source: dict) -> str: +def _detect_ecosystem(source: dict) -> str | None: """Detect ecosystem from asset or component format field.""" fmt = source.get("format", "").lower() if fmt in ("pypi", "pip", "python"): @@ -59,7 +58,7 @@ def _detect_ecosystem(source: dict) -> str: return "go" if fmt in ("npm", "node"): return "npm" - return DEFAULT_ECOSYSTEM + return None @router.post("/nexus") @@ -121,6 +120,8 @@ async def nexus_webhook( download_url = asset.get("downloadUrl") or _build_download_url(repository, asset_path) 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) @@ -145,6 +146,9 @@ async def nexus_webhook( } 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) return { "status": WEBHOOK_STATUS_ACCEPTED, diff --git a/tests/e2e/test_llm_and_edge_cases.py b/tests/e2e/test_llm_and_edge_cases.py index 7e54b41..9b690ed 100644 --- a/tests/e2e/test_llm_and_edge_cases.py +++ b/tests/e2e/test_llm_and_edge_cases.py @@ -201,6 +201,22 @@ class TestErrorHandlingE2e: resp = await e2e_client.post("/webhooks/nexus", json=payload) 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: """E2E tests for HTMX fragment responses.""" diff --git a/tests/test_webhooks.py b/tests/test_webhooks.py index b9ca1d4..3c89302 100644 --- a/tests/test_webhooks.py +++ b/tests/test_webhooks.py @@ -112,8 +112,8 @@ def test_detect_ecosystem_npm(): def test_detect_ecosystem_unknown(): from guarddog_nexus.routes.webhooks import _detect_ecosystem - assert _detect_ecosystem({"format": "maven"}) == "pypi" # unknown → default - assert _detect_ecosystem({}) == "pypi" # default + assert _detect_ecosystem({"format": "maven"}) is None + assert _detect_ecosystem({}) is None # --- Go/npm webhook integration ---