Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 15 additions & 65 deletions gcp/api/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import threading
import time
import concurrent.futures
from typing import Callable

from collections import defaultdict

Expand Down Expand Up @@ -100,11 +99,6 @@

_TEST_INSTANCE = 'oss-vdb-test'

# ----
# Type Aliases:

ToResponseCallable = Callable[[osv.Bug], ndb.Future]

# ----

_ndb_client = ndb.Client()
Expand Down Expand Up @@ -392,9 +386,9 @@ def Check(self, request, context: grpc.ServicerContext):
del request # Unused.
del context # Unused.

# Read up to a single Bug entity from the DB. This should not cause an
# exception or time out.
osv.Bug.query().fetch(1)
# Read up to a single Vulnerability entity from the DB.
# This should not cause an exception or time out.
osv.Vulnerability.query().fetch(1)
return health_pb2.HealthCheckResponse(
status=health_pb2.HealthCheckResponse.ServingStatus.SERVING)

Expand Down Expand Up @@ -965,12 +959,6 @@ def query_package(context: QueryContext,
if not package_name:
return []

if (package_name.startswith('linux') and ecosystem.startswith('Ubuntu') and
version):
result = yield query_ubuntu_linux(context, package_name, ecosystem, version,
include_details)
return result

# Ideally, we'd check both unnormalized and normalized named at once, if there
# is no provided ecosystem (even though that is not explicitly supported), but
# Datastore cannot give cursors for 'OR' queries, so just only normalize if
Expand All @@ -981,6 +969,18 @@ def query_package(context: QueryContext,
query = osv.AffectedVersions.query(osv.AffectedVersions.name == package_name)
if ecosystem:
query = query.filter(osv.AffectedVersions.ecosystem == ecosystem)
if version:
helper = ecosystems.get(ecosystem)
if helper is not None:
try:
coarse = helper.coarse_version(version)
query = query.filter(osv.AffectedVersions.coarse_min <= coarse)
query = query.filter(osv.AffectedVersions.coarse_max >= coarse)
except (ValueError, NotImplementedError):
# We want to avoid logging user requests.
pass
# TODO(michaelkedar): I think a ValueError would mean the version
# would not match any affected versions, so we may be able to return.
query = query.order(osv.AffectedVersions.vuln_id)

bugs = []
Expand Down Expand Up @@ -1147,56 +1147,6 @@ def cleanup(_: ndb.Future):
return future


@ndb.tasklet
def query_ubuntu_linux(context: QueryContext,
package_name: str,
ecosystem: str,
version: str,
include_details: bool = True) -> list[ndb.Future]:
"""Workaround query for linux kernel vulns in Ubuntu, because there's heaps of
them and it takes a while to check all the version ranges.

The logic here is copied from the original implementation of server.py,
using the Bug entity to perform matching on only the version strings, and not
doing range-based matching.
"""

query = osv.Bug.query(
osv.Bug.status == osv.BugStatus.PROCESSED,
osv.Bug.project == package_name,
# pylint: disable=singleton-comparison
osv.Bug.public == True,
osv.Bug.ecosystem == ecosystem,
osv.Bug.affected_fuzzy == version)

bugs = []
it: ndb.QueryIterator = query.iter(start_cursor=context.cursor_at_current())
while (yield it.has_next_async()):
if context.should_break_page(len(bugs)):
context.save_cursor_at_page_break(it)
break

bug: osv.Bug = it.next()
for affected in bug.affected_packages:
eco = affected.package.ecosystem
if ecosystem not in (eco, ecosystems.normalize(eco),
ecosystems.remove_variants(eco)):
continue
if package_name != affected.package.name:
continue
if version not in affected.versions:
continue
# Found a match: retrieve the proto from the bucket / Vulnerability entity
if include_details:
bugs.append(get_vuln_async(bug.db_id))
else:
bugs.append(get_minimal_async(bug.db_id))
context.total_responses.add(1)
break

return bugs


def serve(port: int, local: bool):
"""Configures and runs the OSV API server."""
server = grpc.server(concurrent.futures.ThreadPoolExecutor(max_workers=5))
Expand Down
8 changes: 8 additions & 0 deletions gcp/datastore/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ indexes:
properties:
- name: name
- name: vuln_id

- kind: AffectedVersions
properties:
- name: ecosystem
- name: name
- name: vuln_id
- name: coarse_min
- name: coarse_max

# Indexes for website /list search
- kind: ListedVulnerability
Expand Down
Loading