Skip to content

Commit 21ce0fc

Browse files
committed
Remove from qs
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 1ad5469 commit 21ce0fc

File tree

1 file changed

+162
-3
lines changed

1 file changed

+162
-3
lines changed

vulnerabilities/api_v2.py

Lines changed: 162 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,6 @@ def get_queryset(self):
250250
fixing_vulnerabilities__vulnerability_id=fixing_vulnerability
251251
)
252252

253-
queryset = queryset.with_is_vulnerable()
254-
255-
# Prefetch related vulnerabilities and their related data
256253
queryset = queryset.prefetch_related(
257254
Prefetch(
258255
"affected_by_vulnerabilities",
@@ -358,3 +355,165 @@ def lookup(self, request):
358355

359356
qs = self.get_queryset().for_purls([purl]).with_is_vulnerable()
360357
return Response(PackageV2Serializer(qs, many=True, context={"request": request}).data)
358+
359+
@extend_schema(
360+
request=PackageurlListSerializer,
361+
responses={200: PackageV2Serializer(many=True)},
362+
)
363+
@action(
364+
detail=False,
365+
methods=["post"],
366+
serializer_class=PackageurlListSerializer,
367+
filter_backends=[],
368+
pagination_class=None,
369+
)
370+
def bulk_lookup(self, request):
371+
"""
372+
Return the response for exact PackageURLs requested for.
373+
"""
374+
serializer = self.serializer_class(data=request.data)
375+
if not serializer.is_valid():
376+
return Response(
377+
status=status.HTTP_400_BAD_REQUEST,
378+
data={
379+
"error": serializer.errors,
380+
"message": "A non-empty 'purls' list of PURLs is required.",
381+
},
382+
)
383+
validated_data = serializer.validated_data
384+
purls = validated_data.get("purls")
385+
386+
# Fetch packages matching the provided purls
387+
packages = Package.objects.for_purls(purls).with_is_vulnerable()
388+
389+
# Collect vulnerabilities associated with these packages
390+
vulnerabilities = set()
391+
for package in packages:
392+
vulnerabilities.update(package.affected_by_vulnerabilities.all())
393+
vulnerabilities.update(package.fixing_vulnerabilities.all())
394+
395+
# Serialize vulnerabilities with vulnerability_id as keys
396+
vulnerability_data = {
397+
vuln.vulnerability_id: VulnerabilityV2Serializer(vuln).data for vuln in vulnerabilities
398+
}
399+
400+
# Serialize packages
401+
package_data = PackageV2Serializer(
402+
packages,
403+
many=True,
404+
context={"request": request},
405+
).data
406+
407+
return Response(
408+
{
409+
"vulnerabilities": vulnerability_data,
410+
"packages": package_data,
411+
}
412+
)
413+
414+
@extend_schema(
415+
request=PackageBulkSearchRequestSerializer,
416+
responses={200: PackageV2Serializer(many=True)},
417+
)
418+
@action(
419+
detail=False,
420+
methods=["post"],
421+
serializer_class=PackageBulkSearchRequestSerializer,
422+
filter_backends=[],
423+
pagination_class=None,
424+
)
425+
def bulk_search(self, request):
426+
"""
427+
Lookup for vulnerable packages using many Package URLs at once.
428+
"""
429+
serializer = self.serializer_class(data=request.data)
430+
if not serializer.is_valid():
431+
return Response(
432+
status=status.HTTP_400_BAD_REQUEST,
433+
data={
434+
"error": serializer.errors,
435+
"message": "A non-empty 'purls' list of PURLs is required.",
436+
},
437+
)
438+
validated_data = serializer.validated_data
439+
purls = validated_data.get("purls")
440+
purl_only = validated_data.get("purl_only", False)
441+
plain_purl = validated_data.get("plain_purl", False)
442+
443+
if plain_purl:
444+
purl_objects = [PackageURL.from_string(purl) for purl in purls]
445+
plain_purl_objects = [
446+
PackageURL(
447+
type=purl.type,
448+
namespace=purl.namespace,
449+
name=purl.name,
450+
version=purl.version,
451+
)
452+
for purl in purl_objects
453+
]
454+
plain_purls = [str(purl) for purl in plain_purl_objects]
455+
456+
query = (
457+
Package.objects.filter(plain_package_url__in=plain_purls)
458+
.order_by("plain_package_url")
459+
.distinct("plain_package_url")
460+
.with_is_vulnerable()
461+
)
462+
463+
packages = query
464+
465+
# Collect vulnerabilities associated with these packages
466+
vulnerabilities = set()
467+
for package in packages:
468+
vulnerabilities.update(package.affected_by_vulnerabilities.all())
469+
vulnerabilities.update(package.fixing_vulnerabilities.all())
470+
471+
vulnerability_data = {
472+
vuln.vulnerability_id: VulnerabilityV2Serializer(vuln).data
473+
for vuln in vulnerabilities
474+
}
475+
476+
if not purl_only:
477+
package_data = PackageV2Serializer(
478+
packages, many=True, context={"request": request}
479+
).data
480+
return Response(
481+
{
482+
"vulnerabilities": vulnerability_data,
483+
"packages": package_data,
484+
}
485+
)
486+
487+
# Using order by and distinct because there will be
488+
# many fully qualified purl for a single plain purl
489+
vulnerable_purls = query.vulnerable().only("plain_package_url")
490+
vulnerable_purls = [str(package.plain_package_url) for package in vulnerable_purls]
491+
return Response(data=vulnerable_purls)
492+
493+
query = Package.objects.filter(package_url__in=purls).distinct().with_is_vulnerable()
494+
packages = query
495+
496+
# Collect vulnerabilities associated with these packages
497+
vulnerabilities = set()
498+
for package in packages:
499+
vulnerabilities.update(package.affected_by_vulnerabilities.all())
500+
vulnerabilities.update(package.fixing_vulnerabilities.all())
501+
502+
vulnerability_data = {
503+
vuln.vulnerability_id: VulnerabilityV2Serializer(vuln).data for vuln in vulnerabilities
504+
}
505+
506+
if not purl_only:
507+
package_data = PackageV2Serializer(
508+
packages, many=True, context={"request": request}
509+
).data
510+
return Response(
511+
{
512+
"vulnerabilities": vulnerability_data,
513+
"packages": package_data,
514+
}
515+
)
516+
517+
vulnerable_purls = query.vulnerable().only("package_url")
518+
vulnerable_purls = [str(package.package_url) for package in vulnerable_purls]
519+
return Response(data=vulnerable_purls)

0 commit comments

Comments
 (0)