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")