diff --git a/component_catalog/api.py b/component_catalog/api.py index abd8705f..5c3d8764 100644 --- a/component_catalog/api.py +++ b/component_catalog/api.py @@ -630,7 +630,7 @@ class PackageSerializer( read_only=True, many=True, fields=[ - "vulnerability_id", + "advisory_uid", "api_url", "uuid", ], diff --git a/component_catalog/templates/component_catalog/tabs/tab_vulnerabilities.html b/component_catalog/templates/component_catalog/tabs/tab_vulnerabilities.html index 9fa439bd..1613caa8 100644 --- a/component_catalog/templates/component_catalog/tabs/tab_vulnerabilities.html +++ b/component_catalog/templates/component_catalog/tabs/tab_vulnerabilities.html @@ -51,11 +51,11 @@ {% if vulnerability.resource_url %} - {{ vulnerability.vulnerability_id }} + {{ vulnerability.advisory_id }} {% else %} - {{ vulnerability.vulnerability_id }} + {{ vulnerability.advisory_id }} {% endif %}
diff --git a/component_catalog/tests/test_api.py b/component_catalog/tests/test_api.py index afd60a0a..cfa8cb20 100644 --- a/component_catalog/tests/test_api.py +++ b/component_catalog/tests/test_api.py @@ -1351,7 +1351,7 @@ def test_api_package_endpoint_vulnerabilities_features(self): self.assertEqual("9.0", results[0]["risk_score"]) self.assertEqual( vulnerability1.vulnerability_id, - results[0]["affected_by_vulnerabilities"][0]["vulnerability_id"], + results[0]["affected_by_vulnerabilities"][0]["advisory_uid"], ) data = {"affected_by": vulnerability1.vulnerability_id} diff --git a/component_catalog/tests/test_views.py b/component_catalog/tests/test_views.py index 5efafcb1..9bfbdf55 100644 --- a/component_catalog/tests/test_views.py +++ b/component_catalog/tests/test_views.py @@ -1054,7 +1054,7 @@ def test_component_details_view_tab_vulnerabilities(self): ) self.assertContains(response, expected) self.assertContains(response, 'id="tab_vulnerabilities"') - self.assertContains(response, vulnerability1.vcid) + self.assertContains(response, vulnerability1.vulnerability_id) def test_component_catalog_component_create_ajax_view(self): component_create_ajax_url = reverse("component_catalog:component_add_ajax") @@ -3020,7 +3020,7 @@ def test_package_details_view_tab_vulnerabilities(self): ) self.assertContains(response, expected) self.assertContains(response, 'id="tab_vulnerabilities"') - self.assertContains(response, self.vulnerability1.vcid) + self.assertContains(response, self.vulnerability1.vulnerability_id) def test_vulnerablecode_get_plain_purls(self): purls = get_plain_purls(packages=[]) @@ -3064,37 +3064,6 @@ def test_vulnerablecode_get_vulnerable_purls(self): vulnerable_purls = vulnerablecode.get_vulnerable_purls(packages=[self.package1]) self.assertEqual(["pkg:pypi/django@2.1"], vulnerable_purls) - def test_vulnerablecode_get_vulnerable_cpes(self): - vulnerablecode = VulnerableCode(self.dataspace) - vulnerable_cpes = vulnerablecode.get_vulnerable_cpes(components=[]) - self.assertEqual([], vulnerable_cpes) - - components = [self.component1, self.component2] - vulnerable_cpes = vulnerablecode.get_vulnerable_cpes(components=components) - self.assertEqual([], vulnerable_cpes) - - self.component1.cpe = "cpe:2.3:a:djangoproject:django:0.95:*:*:*:*:*:*:*" - self.component1.save() - - with mock.patch( - "dejacode_toolkit.vulnerablecode.VulnerableCode.bulk_search_by_cpes" - ) as bulk_search: - bulk_search.return_value = [ - { - "vulnerability_id": "VCID-188m-1bke-aaae", - "summary": "The administrative interface in django.contrib.admin ", - "references": [ - {"reference_id": ""}, - ], - } - ] - vulnerable_cpes = vulnerablecode.get_vulnerable_cpes(components=components) - self.assertEqual([], vulnerable_cpes) - - bulk_search.return_value[0]["references"] = [{"reference_id": self.component1.cpe}] - vulnerable_cpes = vulnerablecode.get_vulnerable_cpes(components=components) - self.assertEqual([self.component1.cpe], vulnerable_cpes) - @mock.patch("dejacode_toolkit.vulnerablecode.VulnerableCode.request_get") def test_vulnerablecode_get_vulnerabilities_cache(self, mock_request_get): vulnerablecode = VulnerableCode(self.dataspace) diff --git a/dejacode_toolkit/__init__.py b/dejacode_toolkit/__init__.py index aa246c63..f6f43760 100644 --- a/dejacode_toolkit/__init__.py +++ b/dejacode_toolkit/__init__.py @@ -27,7 +27,7 @@ def get_settings(var_name, default=None): def is_service_available(label, session, url, raise_exceptions): """Check if a configured integration service is available.""" try: - response = session.head(url, timeout=REQUESTS_TIMEOUT) + response = session.head(url, allow_redirects=True, timeout=REQUESTS_TIMEOUT) response.raise_for_status() except requests.exceptions.RequestException as request_exception: logger.debug(f"{label} is_available() error: {request_exception}") @@ -43,6 +43,7 @@ class BaseService: settings_prefix = None url_field_name = None api_key_field_name = None + api_version = None default_timeout = REQUESTS_TIMEOUT def __init__(self, dataspace): @@ -71,6 +72,9 @@ def __init__(self, dataspace): self.api_url = f"{self.service_url.rstrip('/')}/api/" + if self.api_version: + self.api_url = f"{self.api_url}{self.api_version.rstrip('/')}/" + def get_session(self): session = requests.Session() diff --git a/dejacode_toolkit/vulnerablecode.py b/dejacode_toolkit/vulnerablecode.py index 34980dcf..82a2e581 100644 --- a/dejacode_toolkit/vulnerablecode.py +++ b/dejacode_toolkit/vulnerablecode.py @@ -19,87 +19,44 @@ class VulnerableCode(BaseService): settings_prefix = "VULNERABLECODE" url_field_name = "vulnerablecode_url" api_key_field_name = "vulnerablecode_api_key" + api_version = "v3" - def get_vulnerabilities( + def get_vulnerabilities_by_purl( self, - url, - field_name, - field_value, + purl, timeout=None, ): - """Get list of vulnerabilities.""" - cached_results = cache.get(field_value) + """Get list of vulnerabilities providing a package `purl`.""" + plain_purl = get_plain_purl(purl) + + cached_results = cache.get(plain_purl) if cached_results: return cached_results - payload = {field_name: field_value} - - response = self.request_get(url=url, params=payload, timeout=timeout) + response = self.bulk_search_by_purl(purls=[plain_purl], timeout=timeout) if response and response.get("count"): results = response["results"] - cache.set(field_value, results) + cache.set(plain_purl, results) return results - def get_vulnerabilities_by_purl( - self, - purl, - timeout=None, - ): - """Get list of vulnerabilities providing a package `purl`.""" - return self.get_vulnerabilities( - url=f"{self.api_url}packages/", - field_name="purl", - field_value=get_plain_purl(purl), - timeout=timeout, - ) - - def get_vulnerabilities_by_cpe( - self, - cpe, - timeout=None, - ): - """Get list of vulnerabilities providing a package or component `cpe`.""" - return self.get_vulnerabilities( - url=f"{self.api_url}cpes/", - field_name="cpe", - field_value=cpe, - timeout=timeout, - ) - def bulk_search_by_purl( self, purls, - purl_only, + details=True, timeout=None, ): """Bulk search of vulnerabilities using the provided list of `purls`.""" - url = f"{self.api_url}packages/bulk_search" + url = f"{self.api_url}packages" data = { "purls": purls, - "purl_only": purl_only, - "plain_purl": True, + "details": details, } logger.debug(f"VulnerableCode: url={url} purls_count={len(purls)}") return self.request_post(url=url, json=data, timeout=timeout) - def bulk_search_by_cpes( - self, - cpes, - timeout=None, - ): - """Bulk search of vulnerabilities using the provided list of `cpes`.""" - url = f"{self.api_url}cpes/bulk_search" - - data = { - "cpes": cpes, - } - - logger.debug(f"VulnerableCode: url={url} cpes_count={len(cpes)}") - return self.request_post(url, json=data, timeout=timeout) - - def get_vulnerable_purls(self, packages, purl_only=True, timeout=10): + def get_vulnerable_purls(self, packages, details=False, timeout=10): """ Return a list of PURLs for which at least one `affected_by_vulnerabilities` was found in the VulnerableCodeDB for the given list of `packages`. @@ -110,34 +67,11 @@ def get_vulnerable_purls(self, packages, purl_only=True, timeout=10): return [] vulnerable_purls = self.bulk_search_by_purl( - plain_purls, - purl_only=purl_only, + purls=plain_purls, + details=details, timeout=timeout, ) - return vulnerable_purls or [] - - def get_vulnerable_cpes(self, components): - """ - Return a list of vulnerable CPEs found in the VulnerableCodeDB for the given - list of `components`. - """ - cpes = [component.cpe for component in components if component.cpe] - - if not cpes: - return [] - - search_results = self.bulk_search_by_cpes(cpes) - if not search_results: - return [] - - vulnerable_cpes = [ - reference.get("reference_id") - for entry in search_results - for reference in entry.get("references") - if reference.get("reference_id").startswith("cpe") - ] - - return list(set(vulnerable_cpes)) + return vulnerable_purls.get("results") or [] def get_package_url_available_types(self): # Replace by fetching the endpoint once available. diff --git a/product_portfolio/templates/product_portfolio/compliance/compliance_watchlist_card.html b/product_portfolio/templates/product_portfolio/compliance/compliance_watchlist_card.html index 2e1bdb4d..73ad45c3 100644 --- a/product_portfolio/templates/product_portfolio/compliance/compliance_watchlist_card.html +++ b/product_portfolio/templates/product_portfolio/compliance/compliance_watchlist_card.html @@ -44,7 +44,7 @@

{{ product.low_count }} low {% endif %} {% if not product.critical_count and not product.high_count and not product.medium_count and not product.low_count %} - None + None {% endif %}

diff --git a/product_portfolio/tests/test_api.py b/product_portfolio/tests/test_api.py index 88b50bcd..c60a0356 100644 --- a/product_portfolio/tests/test_api.py +++ b/product_portfolio/tests/test_api.py @@ -1157,7 +1157,7 @@ def test_api_productpackage_endpoint_vulnerabilities_features(self): response = self.client.get(self.pp1_detail_url) response_analysis = response.data["vulnerability_analyses"][0] - self.assertEqual(vulnerability1.vulnerability_id, response_analysis["vulnerability_id"]) + self.assertEqual(vulnerability1.advisory_uid, response_analysis["advisory_uid"]) self.assertEqual(analysis1.state, response_analysis["state"]) self.assertEqual(analysis1.justification, response_analysis["justification"]) @@ -1189,7 +1189,7 @@ def test_api_product_endpoint_vulnerabilities_features(self): response = self.client.get(self.product1_detail_url) response_analysis = response.data["vulnerability_analyses"][0] - self.assertEqual(vulnerability1.vulnerability_id, response_analysis["vulnerability_id"]) + self.assertEqual(vulnerability1.advisory_uid, response_analysis["advisory_uid"]) self.assertEqual(analysis1.state, response_analysis["state"]) self.assertEqual(analysis1.justification, response_analysis["justification"]) diff --git a/product_portfolio/tests/test_views.py b/product_portfolio/tests/test_views.py index c4eb4ba2..8fc46d0e 100644 --- a/product_portfolio/tests/test_views.py +++ b/product_portfolio/tests/test_views.py @@ -328,9 +328,9 @@ def test_product_portfolio_tab_vulnerability_view_packages_row_rendering(self): expected = f"""