|
21 | 21 | from rest_framework.response import Response
|
22 | 22 | from rest_framework.reverse import reverse
|
23 | 23 |
|
| 24 | +from vulnerabilities.models import CodeFix |
24 | 25 | from vulnerabilities.models import Package
|
25 | 26 | from vulnerabilities.models import Vulnerability
|
26 | 27 | from vulnerabilities.models import VulnerabilityReference
|
@@ -198,14 +199,25 @@ def get_affected_by_vulnerabilities(self, obj):
|
198 | 199 | Return a dictionary with vulnerabilities as keys and their details, including fixed_by_packages.
|
199 | 200 | """
|
200 | 201 | result = {}
|
| 202 | + request = self.context.get("request") |
201 | 203 | for vuln in getattr(obj, "prefetched_affected_vulnerabilities", []):
|
202 | 204 | fixed_by_package = vuln.fixed_by_packages.first()
|
203 | 205 | purl = None
|
204 | 206 | if fixed_by_package:
|
205 | 207 | purl = fixed_by_package.package_url
|
| 208 | + # Get code fixed for a vulnerability |
| 209 | + code_fixes = CodeFix.objects.filter( |
| 210 | + affected_package_vulnerability__vulnerability=vuln |
| 211 | + ).distinct() |
| 212 | + code_fix_urls = [ |
| 213 | + reverse("codefix-detail", args=[code_fix.id], request=request) |
| 214 | + for code_fix in code_fixes |
| 215 | + ] |
| 216 | + |
206 | 217 | result[vuln.vulnerability_id] = {
|
207 | 218 | "vulnerability_id": vuln.vulnerability_id,
|
208 | 219 | "fixed_by_packages": purl,
|
| 220 | + "code_fixes": code_fix_urls, |
209 | 221 | }
|
210 | 222 | return result
|
211 | 223 |
|
@@ -521,3 +533,76 @@ def lookup(self, request):
|
521 | 533 |
|
522 | 534 | qs = self.get_queryset().for_purls([purl]).with_is_vulnerable()
|
523 | 535 | return Response(PackageV2Serializer(qs, many=True, context={"request": request}).data)
|
| 536 | + |
| 537 | + |
| 538 | +class CodeFixSerializer(serializers.ModelSerializer): |
| 539 | + """ |
| 540 | + Serializer for the CodeFix model. |
| 541 | + Provides detailed information about a code fix. |
| 542 | + """ |
| 543 | + |
| 544 | + affected_vulnerability_id = serializers.CharField( |
| 545 | + source="affected_package_vulnerability.vulnerability.vulnerability_id", |
| 546 | + read_only=True, |
| 547 | + help_text="ID of the affected vulnerability.", |
| 548 | + ) |
| 549 | + affected_package_purl = serializers.CharField( |
| 550 | + source="affected_package_vulnerability.package.package_url", |
| 551 | + read_only=True, |
| 552 | + help_text="PURL of the affected package.", |
| 553 | + ) |
| 554 | + fixed_package_purl = serializers.CharField( |
| 555 | + source="fixed_package_vulnerability.package.package_url", |
| 556 | + read_only=True, |
| 557 | + help_text="PURL of the fixing package (if available).", |
| 558 | + ) |
| 559 | + created_at = serializers.DateTimeField( |
| 560 | + format="%Y-%m-%dT%H:%M:%SZ", |
| 561 | + read_only=True, |
| 562 | + help_text="Timestamp when the code fix was created.", |
| 563 | + ) |
| 564 | + updated_at = serializers.DateTimeField( |
| 565 | + format="%Y-%m-%dT%H:%M:%SZ", |
| 566 | + read_only=True, |
| 567 | + help_text="Timestamp when the code fix was last updated.", |
| 568 | + ) |
| 569 | + |
| 570 | + class Meta: |
| 571 | + model = CodeFix |
| 572 | + fields = [ |
| 573 | + "id", |
| 574 | + "commits", |
| 575 | + "pulls", |
| 576 | + "downloads", |
| 577 | + "patch", |
| 578 | + "affected_vulnerability_id", |
| 579 | + "affected_package_purl", |
| 580 | + "fixed_package_purl", |
| 581 | + "notes", |
| 582 | + "references", |
| 583 | + "is_reviewed", |
| 584 | + "created_at", |
| 585 | + "updated_at", |
| 586 | + ] |
| 587 | + read_only_fields = ["created_at", "updated_at"] |
| 588 | + |
| 589 | + |
| 590 | +class CodeFixViewSet(viewsets.ReadOnlyModelViewSet): |
| 591 | + """ |
| 592 | + API endpoint that allows viewing CodeFix entries. |
| 593 | + """ |
| 594 | + |
| 595 | + queryset = CodeFix.objects.all() |
| 596 | + serializer_class = CodeFixSerializer |
| 597 | + |
| 598 | + def get_queryset(self): |
| 599 | + """ |
| 600 | + Optionally filter by vulnerability ID. |
| 601 | + """ |
| 602 | + queryset = super().get_queryset() |
| 603 | + vulnerability_id = self.request.query_params.get("vulnerability_id") |
| 604 | + if vulnerability_id: |
| 605 | + queryset = queryset.filter( |
| 606 | + affected_package_vulnerability__vulnerability__vulnerability_id=vulnerability_id |
| 607 | + ) |
| 608 | + return queryset |
0 commit comments