From 87d845132a3158851a051516d61a59026cc201ee Mon Sep 17 00:00:00 2001 From: gorasatryanGH Date: Thu, 30 Jul 2026 14:34:06 +0300 Subject: [PATCH] Fix: return 404 instead of 500 for invalid advisory IDs latest_for_avid() raised DoesNotExist instead of returning None, so the Http404 fallback in AdvisoryDetails, AdvisoryPackagesDetails and AdvisoryPackageCommitPatchDetails was never reached. Fixes #2396 Signed-off-by: gorasatryanGH --- vulnerabilities/models.py | 5 ++- .../tests/test_advisory_details_view.py | 44 +++++++++++++++++++ .../test_same_avid_different_content_id.py | 14 ++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 vulnerabilities/tests/test_advisory_details_view.py diff --git a/vulnerabilities/models.py b/vulnerabilities/models.py index 826d35a54..952f3ce86 100644 --- a/vulnerabilities/models.py +++ b/vulnerabilities/models.py @@ -2926,7 +2926,10 @@ def to_dict(self): class AdvisoryV2QuerySet(BaseQuerySet): def latest_for_avid(self, avid: str): - return self.get(avid=avid, is_latest=True) + try: + return self.get(avid=avid, is_latest=True) + except self.model.DoesNotExist: + return None def latest_per_avid(self): return self.filter(is_latest=True) diff --git a/vulnerabilities/tests/test_advisory_details_view.py b/vulnerabilities/tests/test_advisory_details_view.py new file mode 100644 index 000000000..f7d060411 --- /dev/null +++ b/vulnerabilities/tests/test_advisory_details_view.py @@ -0,0 +1,44 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# + +import time + +import pytest +from django.urls import reverse + +INVALID_AVID = "pysec/PYSEC-3000-0" + + +@pytest.mark.django_db +@pytest.mark.parametrize( + "url_name", + [ + "advisory_details", + "advisory_package_details", + "advisory_package_commit_details", + ], +) +def test_advisory_views_return_404_for_invalid_avid(client, url_name): + """ + Requesting an advisory-related page for an avid that does not exist should + return a 404 Page Not Found, not a 500 Server Error. + + Regression test for: "Advisory Page Returns 500 Instead of 404 for Invalid + Advisory IDs". + """ + # Satisfy AltchaProtectionMiddleware so the request reaches the view + # instead of being redirected to the captcha page. + session = client.session + session["altcha_verified_at"] = time.time() + session.save() + + url = reverse(url_name, kwargs={"avid": INVALID_AVID}) + response = client.get(url) + + assert response.status_code == 404 diff --git a/vulnerabilities/tests/test_same_avid_different_content_id.py b/vulnerabilities/tests/test_same_avid_different_content_id.py index 6e60ab4c3..750450fbd 100644 --- a/vulnerabilities/tests/test_same_avid_different_content_id.py +++ b/vulnerabilities/tests/test_same_avid_different_content_id.py @@ -68,6 +68,20 @@ def test_latest_for_avid_tie_breaks_by_id(advisory_factory, django_assert_num_qu assert result.id == second.id +@pytest.mark.django_db +def test_latest_for_avid_returns_none_for_unknown_avid(django_assert_num_queries): + """ + ``latest_for_avid`` should return ``None`` (not raise ``DoesNotExist``) for an + avid that does not exist, since callers rely on a falsy return value to + raise an ``Http404``. See GH issue: Advisory Page Returns 500 Instead of 404 + for Invalid Advisory IDs. + """ + with django_assert_num_queries(1): + result = AdvisoryV2.objects.latest_for_avid("does-not-exist/ADV-404") + + assert result is None + + @pytest.mark.django_db def test_latest_per_avid_returns_one_row_per_avid(advisory_factory, django_assert_num_queries): advisory_factory(advisory_id="A", summary="old advisory")