diff --git a/docs/faq.md b/docs/faq.md index 3de099cdab4..dac8b0dff2b 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -91,6 +91,16 @@ If you have any questions, please feel free to create an issue! ## Data +### Why isn't a record available? + +If you are unable to retrieve a record you are expecting to be able to find, it +may be because it has not imported successfully, due to there being a quality issue with it. + +If a record has not met [OSV.dev's quality bar](data_quality.md), the 404 page +for the vulnerability will state this. + +You should raise this with the home database responsible for the record. + ### I've found something wrong with the data Data quality is very important to us. Please remember that OSV.dev is an diff --git a/gcp/appengine/frontend3/src/templates/404.html b/gcp/appengine/frontend3/src/templates/404.html index 76186370223..b1ab3107a5f 100644 --- a/gcp/appengine/frontend3/src/templates/404.html +++ b/gcp/appengine/frontend3/src/templates/404.html @@ -12,6 +12,27 @@ {% block top_bar %} {% endblock %} {% block content %} +{% if vuln_id %} +
+
+
+

{{ vuln_id }} Not Found!

+

+ {% if has_importfindings %} + The record has not imported successfully from its source
+ {% endif %} + Please see our + FAQ for more information. +

+ +
+
+ +
+{% else %}
@@ -29,4 +50,5 @@

Oops! Page Not Found!

+{% endif %} {% endblock %} diff --git a/gcp/appengine/frontend3/src/templates/list.html b/gcp/appengine/frontend3/src/templates/list.html index 6f9dedf324f..d1ead29022a 100644 --- a/gcp/appengine/frontend3/src/templates/list.html +++ b/gcp/appengine/frontend3/src/templates/list.html @@ -128,7 +128,7 @@

Vulnerabilities

{%- endfor -%} {%- if vulnerabilities | length == 0 -%} - No results + No results (check our FAQ if this is unexpected) {%- endif -%} {%- if page < total_pages -%} diff --git a/gcp/appengine/frontend_handlers.py b/gcp/appengine/frontend_handlers.py index a0b0dc2a9cb..753cad7fed3 100644 --- a/gcp/appengine/frontend_handlers.py +++ b/gcp/appengine/frontend_handlers.py @@ -55,6 +55,19 @@ _DEPS_BASE_URL = 'https://deps.dev' _FIRST_CVSS_CALCULATOR_BASE_URL = 'https://www.first.org/cvss/calculator' + +class VulnerabilityNotFound(exceptions.NotFound): + """Plumb the vulnerability ID not found to the error handler.""" + + def __init__(self, vuln_id: str) -> None: + super().__init__() + self.vuln_id = vuln_id + + +class VulnerabilityNotImported(VulnerabilityNotFound): + """Plumb the vulnerability ID with import findings to the error handler.""" + + if utils.is_prod(): redis_host = os.environ.get('REDISHOST', 'localhost') redis_port = int(os.environ.get('REDISPORT', 6379)) @@ -126,6 +139,11 @@ def robots(): return response +@blueprint.route('/favicon.ico') +def favicon(): + return current_app.send_static_file('img/favicon-32x32.png') + + @blueprint.route('/blog/', strict_slashes=False) def blog(): return render_template('blog.html', index=_load_blog_content('index.html')) @@ -251,15 +269,13 @@ def vulnerability_redirector(potential_vuln_id): # AlmaLinux have colons in their identifiers, which gets URL encoded. potential_vuln_id = parse.unquote(potential_vuln_id) if not _VALID_VULN_ID.match(potential_vuln_id): - abort(404) + abort(400) return None - vuln = osv_get_by_id(potential_vuln_id) - if vuln: - return redirect(f'/vulnerability/{potential_vuln_id}') + # This may raise an exception directly or via abort() for failed retrievals. + _ = osv_get_by_id(potential_vuln_id) - abort(404) - return None + return redirect(f'/vulnerability/{potential_vuln_id}') @blueprint.route('/.json') @@ -269,13 +285,11 @@ def vulnerability_json_redirector(potential_vuln_id): https://api.osv.dev/v1/vulns/VULN-ID. """ if not _VALID_VULN_ID.match(potential_vuln_id): - abort(404) + abort(400) return None - vuln = osv_get_by_id(potential_vuln_id) - if not vuln: - abort(404) - return None + # This calls abort() on failed retrievals. + _ = osv_get_by_id(potential_vuln_id) if utils.is_prod(): api_url = 'api.osv.dev' @@ -524,12 +538,15 @@ def osv_get_by_id(vuln_id): bug = osv.Bug.get_by_id(vuln_id) if not bug: - abort(404) - return None + if osv.ImportFinding.get_by_id(vuln_id): + # abort(404) is too simplistic for this. + raise VulnerabilityNotImported(vuln_id) + # abort(404) is too simplistic for this. + raise VulnerabilityNotFound(vuln_id) if bug.status == osv.BugStatus.UNPROCESSED: - abort(404) - return None + # abort(404) is too simplistic for this. + raise VulnerabilityNotFound(vuln_id) if not bug.public: abort(403) @@ -705,6 +722,11 @@ def list_packages(vuln_affected: list[dict]): @blueprint.app_errorhandler(404) def not_found_error(error: exceptions.HTTPException): logging.info('Handled %s - Path attempted: %s', error, request.path) + if isinstance(error, VulnerabilityNotFound): + return render_template( + '404.html', + vuln_id=error.vuln_id, + has_importfindings=isinstance(error, VulnerabilityNotImported)), 404 return render_template('404.html'), 404