|
17 | 17 | from rest_framework.test import APIClient |
18 | 18 | from rest_framework.test import APITestCase |
19 | 19 |
|
| 20 | +from vulnerabilities.api_v2 import AdvisoryV2Serializer |
20 | 21 | from vulnerabilities.api_v2 import PackageV2Serializer |
21 | 22 | from vulnerabilities.api_v2 import VulnerabilityListSerializer |
| 23 | +from vulnerabilities.models import AdvisoryAlias |
22 | 24 | from vulnerabilities.models import AdvisoryV2 |
23 | 25 | from vulnerabilities.models import Alias |
24 | 26 | from vulnerabilities.models import ApiUser |
@@ -905,3 +907,130 @@ def test_get_all_vulnerable_purls(self): |
905 | 907 | response = self.client.get(url) |
906 | 908 | assert response.status_code == 200 |
907 | 909 | assert "pkg:pypi/sample@1.0.0" in response.data |
| 910 | + |
| 911 | + |
| 912 | +class AdvisoryV2ViewSetTest(APITestCase): |
| 913 | + def setUp(self): |
| 914 | + self.advisory1 = AdvisoryV2.objects.create( |
| 915 | + datasource_id="nginx_importer_v2", |
| 916 | + advisory_id="CVE-2021-1234", |
| 917 | + avid="nginx_importer_v2/CVE-2021-1234", |
| 918 | + unique_content_id="a" * 64, |
| 919 | + url="https://example.com/advisory1", |
| 920 | + date_collected="2024-01-01T00:00:00Z", |
| 921 | + summary="Test advisory 1", |
| 922 | + ) |
| 923 | + self.advisory2 = AdvisoryV2.objects.create( |
| 924 | + datasource_id="pypa_importer_v2", |
| 925 | + advisory_id="PYSEC-2022-5678", |
| 926 | + avid="pypa_importer_v2/PYSEC-2022-5678", |
| 927 | + unique_content_id="b" * 64, |
| 928 | + url="https://example.com/advisory2", |
| 929 | + date_collected="2024-01-01T00:00:00Z", |
| 930 | + summary="Test advisory 2", |
| 931 | + ) |
| 932 | + |
| 933 | + self.alias1 = AdvisoryAlias.objects.create(alias="CVE-2021-1234") |
| 934 | + self.advisory1.aliases.add(self.alias1) |
| 935 | + |
| 936 | + self.alias2 = AdvisoryAlias.objects.create(alias="GHSA-xxxx-yyyy-zzzz") |
| 937 | + self.advisory2.aliases.add(self.alias2) |
| 938 | + |
| 939 | + cache.clear() |
| 940 | + self.client = APIClient(enforce_csrf_checks=True) |
| 941 | + |
| 942 | + def test_list_advisories(self): |
| 943 | + """ |
| 944 | + Test listing all advisories without filters. |
| 945 | + """ |
| 946 | + url = reverse("advisory-v2-list") |
| 947 | + response = self.client.get(url, format="json") |
| 948 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 949 | + self.assertIn("results", response.data) |
| 950 | + self.assertEqual(response.data["count"], 2) |
| 951 | + |
| 952 | + def test_retrieve_advisory_by_avid(self): |
| 953 | + """ |
| 954 | + Test retrieving a specific advisory by its avid. |
| 955 | + The avid contains a slash, handled by lookup_value_regex. |
| 956 | + """ |
| 957 | + url = reverse("advisory-v2-detail", kwargs={"avid": self.advisory1.avid}) |
| 958 | + response = self.client.get(url, format="json") |
| 959 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 960 | + self.assertEqual(response.data["advisory_id"], self.advisory1.avid) |
| 961 | + self.assertEqual(response.data["url"], self.advisory1.url) |
| 962 | + self.assertIn("CVE-2021-1234", response.data["aliases"]) |
| 963 | + |
| 964 | + def test_retrieve_nonexistent_advisory_returns_404(self): |
| 965 | + """ |
| 966 | + Test that a non-existent advisory returns 404. |
| 967 | + """ |
| 968 | + url = reverse("advisory-v2-detail", kwargs={"avid": "fake_source/FAKE-0000"}) |
| 969 | + response = self.client.get(url, format="json") |
| 970 | + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) |
| 971 | + |
| 972 | + def test_filter_by_alias(self): |
| 973 | + """ |
| 974 | + Test filtering advisories by alias returns only matching advisory. |
| 975 | + """ |
| 976 | + url = reverse("advisory-v2-list") |
| 977 | + response = self.client.get(url, {"alias": "CVE-2021-1234"}, format="json") |
| 978 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 979 | + self.assertEqual(response.data["count"], 1) |
| 980 | + result = response.data["results"][0] |
| 981 | + self.assertIn("CVE-2021-1234", result["aliases"]) |
| 982 | + |
| 983 | + def test_filter_by_advisory_id(self): |
| 984 | + """ |
| 985 | + Test filtering advisories by advisory_id (avid). |
| 986 | + """ |
| 987 | + url = reverse("advisory-v2-list") |
| 988 | + response = self.client.get( |
| 989 | + url, {"advisory_id": "nginx_importer_v2/CVE-2021-1234"}, format="json" |
| 990 | + ) |
| 991 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 992 | + self.assertEqual(response.data["count"], 1) |
| 993 | + self.assertEqual(response.data["results"][0]["advisory_id"], self.advisory1.avid) |
| 994 | + |
| 995 | + def test_filter_by_datasource_id(self): |
| 996 | + """ |
| 997 | + Test filtering advisories by datasource_id returns only that source's advisories. |
| 998 | + """ |
| 999 | + url = reverse("advisory-v2-list") |
| 1000 | + response = self.client.get(url, {"datasource_id": "nginx_importer_v2"}, format="json") |
| 1001 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 1002 | + self.assertEqual(response.data["count"], 1) |
| 1003 | + self.assertEqual(response.data["results"][0]["advisory_id"], self.advisory1.avid) |
| 1004 | + |
| 1005 | + def test_filter_by_nonexistent_alias_returns_empty(self): |
| 1006 | + """ |
| 1007 | + Test that filtering by a non-existent alias returns an empty list. |
| 1008 | + """ |
| 1009 | + url = reverse("advisory-v2-list") |
| 1010 | + response = self.client.get(url, {"alias": "CVE-9999-9999"}, format="json") |
| 1011 | + self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 1012 | + self.assertEqual(response.data["count"], 0) |
| 1013 | + |
| 1014 | + def test_advisory_serializer_fields(self): |
| 1015 | + """ |
| 1016 | + Test that AdvisoryV2Serializer returns all required fields. |
| 1017 | + """ |
| 1018 | + serializer = AdvisoryV2Serializer(self.advisory1) |
| 1019 | + data = serializer.data |
| 1020 | + expected_fields = [ |
| 1021 | + "advisory_id", |
| 1022 | + "url", |
| 1023 | + "aliases", |
| 1024 | + "summary", |
| 1025 | + "severities", |
| 1026 | + "weaknesses", |
| 1027 | + "references", |
| 1028 | + "exploitability", |
| 1029 | + "weighted_severity", |
| 1030 | + "risk_score", |
| 1031 | + "related_ssvc_trees", |
| 1032 | + ] |
| 1033 | + for field in expected_fields: |
| 1034 | + self.assertIn(field, data) |
| 1035 | + self.assertEqual(data["advisory_id"], self.advisory1.avid) |
| 1036 | + self.assertIn("CVE-2021-1234", data["aliases"]) |
0 commit comments