From 13ab47f9345f92b504c7a84c11374bde94503b5a Mon Sep 17 00:00:00 2001 From: nasreenkhannam Date: Mon, 23 Mar 2026 23:59:43 +0530 Subject: [PATCH 1/6] Add SBOM endpoint to ProjectViewSet --- scanpipe/api/views.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scanpipe/api/views.py b/scanpipe/api/views.py index fd7416b85f..893f281ca1 100644 --- a/scanpipe/api/views.py +++ b/scanpipe/api/views.py @@ -136,6 +136,23 @@ class ProjectViewSet( mixins.ListModelMixin, viewsets.GenericViewSet, ): + @action(detail=True, methods=["get"]) +def sbom(self, request, *args, **kwargs): + """ + Return SBOM for a given PURL. + """ + project = self.get_object() + purl = request.query_params.get("purl") + + if not purl: + return ErrorResponse("purl is required") + + # TODO: integrate actual SBOM generation logic + return Response({ + "project": project.name, + "purl": purl, + "sbom": "CycloneDX SBOM will be generated here" + },status=200) """ A viewset that provides the ability to list, get, create, and destroy projects. Multiple actions are available to manage project instances. From 8dd86626ecedf6745b972859f982f7b8a7f303ba Mon Sep 17 00:00:00 2001 From: nasreenkhannam Date: Tue, 24 Mar 2026 00:10:55 +0530 Subject: [PATCH 2/6] Fix SBOM endpoint response handling Signed-off-by: nasreenkhannam --- scanpipe/api/views.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/scanpipe/api/views.py b/scanpipe/api/views.py index 893f281ca1..bf28e5b042 100644 --- a/scanpipe/api/views.py +++ b/scanpipe/api/views.py @@ -136,23 +136,22 @@ class ProjectViewSet( mixins.ListModelMixin, viewsets.GenericViewSet, ): - @action(detail=True, methods=["get"]) + from rest_framework.response import Response +from rest_framework import status + +@action(detail=True, methods=["get"]) def sbom(self, request, *args, **kwargs): - """ - Return SBOM for a given PURL. - """ project = self.get_object() purl = request.query_params.get("purl") if not purl: - return ErrorResponse("purl is required") + return Response({"error": "purl is required"}, status=status.HTTP_400_BAD_REQUEST) - # TODO: integrate actual SBOM generation logic return Response({ "project": project.name, "purl": purl, "sbom": "CycloneDX SBOM will be generated here" - },status=200) + }) """ A viewset that provides the ability to list, get, create, and destroy projects. Multiple actions are available to manage project instances. From a7a0274894e148e8b86175a6c8099e83d314be9a Mon Sep 17 00:00:00 2001 From: nasreenkhannam Date: Tue, 24 Mar 2026 00:23:18 +0530 Subject: [PATCH 3/6] Fix queryset issue in ProjectViewSet --- scanpipe/api/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scanpipe/api/views.py b/scanpipe/api/views.py index bf28e5b042..0cdbc4ca64 100644 --- a/scanpipe/api/views.py +++ b/scanpipe/api/views.py @@ -136,6 +136,8 @@ class ProjectViewSet( mixins.ListModelMixin, viewsets.GenericViewSet, ): + queryset = Project.objects.all() + serializer_class = ProjectSerializer from rest_framework.response import Response from rest_framework import status From 349453e129b0467865cbc87e5227eca6061a9820 Mon Sep 17 00:00:00 2001 From: nasreenkhannam Date: Tue, 24 Mar 2026 01:28:31 +0530 Subject: [PATCH 4/6] Fix indentation for actions Signed-off-by: nasreenkhannam --- scanpipe/api/views.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/scanpipe/api/views.py b/scanpipe/api/views.py index 0cdbc4ca64..3693060523 100644 --- a/scanpipe/api/views.py +++ b/scanpipe/api/views.py @@ -139,21 +139,28 @@ class ProjectViewSet( queryset = Project.objects.all() serializer_class = ProjectSerializer from rest_framework.response import Response + + from rest_framework import status + @action(detail=True, methods=["get"]) def sbom(self, request, *args, **kwargs): project = self.get_object() purl = request.query_params.get("purl") if not purl: - return Response({"error": "purl is required"}, status=status.HTTP_400_BAD_REQUEST) + return Response( + {"error": "purl is required"}, status=status.HTTP_400_BAD_REQUEST + ) - return Response({ - "project": project.name, - "purl": purl, - "sbom": "CycloneDX SBOM will be generated here" - }) + return Response( + { + "project": project.name, + "purl": purl, + "sbom": "CycloneDX SBOM will be generated here", + } + ) """ A viewset that provides the ability to list, get, create, and destroy projects. Multiple actions are available to manage project instances. From ff1543dab347b169484603cb0581a6353a2c75ca Mon Sep 17 00:00:00 2001 From: nasreenkhannam Date: Tue, 24 Mar 2026 01:49:27 +0530 Subject: [PATCH 5/6] fix lint and queryset issue Signed-off-by: nasreenkhannam --- scanpipe/api/views.py | 63 ++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/scanpipe/api/views.py b/scanpipe/api/views.py index 3693060523..bf22d52ae0 100644 --- a/scanpipe/api/views.py +++ b/scanpipe/api/views.py @@ -129,6 +129,8 @@ def filter_names(self, qs, name, value): return qs.filter(lookups) + + class ProjectViewSet( mixins.CreateModelMixin, mixins.RetrieveModelMixin, @@ -136,39 +138,13 @@ class ProjectViewSet( mixins.ListModelMixin, viewsets.GenericViewSet, ): - queryset = Project.objects.all() - serializer_class = ProjectSerializer - from rest_framework.response import Response - - -from rest_framework import status - - -@action(detail=True, methods=["get"]) -def sbom(self, request, *args, **kwargs): - project = self.get_object() - purl = request.query_params.get("purl") - - if not purl: - return Response( - {"error": "purl is required"}, status=status.HTTP_400_BAD_REQUEST - ) - - return Response( - { - "project": project.name, - "purl": purl, - "sbom": "CycloneDX SBOM will be generated here", - } - ) + """ A viewset that provides the ability to list, get, create, and destroy projects. Multiple actions are available to manage project instances. """ - queryset = Project.objects.all() - serializer_class = ProjectSerializer - filterset_class = ProjectFilterSet + def get_queryset(self): return ( @@ -181,15 +157,34 @@ def get_queryset(self): ) ) - @action(detail=True, renderer_classes=[renderers.JSONRenderer]) + @action( + detail=True, + methods=["get"], + url_path="results", + url_name="results", + renderer_classes=[renderers.JSONRenderer], + ) def results(self, request, *args, **kwargs): - """ - Return the results compatible with ScanCode data format. - The content is returned as a stream of JSON content using the - JSONResultsGenerator class. - """ return project_results_json_response(self.get_object()) + @action(detail=True, methods=["get"], url_path="sbom") + def sbom(self, request, *args, **kwargs): + project = self.get_object() + purl = request.query_params.get("purl") + + if not purl: + return Response( + {"error": "purl is required"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + return Response( + { + "project": project.name, + "purl": purl, + "sbom": "CycloneDX SBOM will be generated here", + } + ) @action(detail=True, name="Results (download)") def results_download(self, request, *args, **kwargs): """Return the results in the provided `output_format` as an attachment.""" From 1e237d8d1ec55d13108508f69ae2f9b478a1eac7 Mon Sep 17 00:00:00 2001 From: nasreenkhannam Date: Tue, 24 Mar 2026 01:54:23 +0530 Subject: [PATCH 6/6] Fix indentation for actions --- scanpipe/api/views.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/scanpipe/api/views.py b/scanpipe/api/views.py index bf22d52ae0..fd8680f0aa 100644 --- a/scanpipe/api/views.py +++ b/scanpipe/api/views.py @@ -46,7 +46,6 @@ from scanpipe.api.serializers import ProjectArchiveSerializer from scanpipe.api.serializers import ProjectMessageSerializer from scanpipe.api.serializers import ProjectResetSerializer -from scanpipe.api.serializers import ProjectSerializer from scanpipe.api.serializers import RunSerializer from scanpipe.api.serializers import WebhookSubscriptionSerializer from scanpipe.filters import DependencyFilterSet @@ -129,8 +128,6 @@ def filter_names(self, qs, name, value): return qs.filter(lookups) - - class ProjectViewSet( mixins.CreateModelMixin, mixins.RetrieveModelMixin, @@ -138,14 +135,11 @@ class ProjectViewSet( mixins.ListModelMixin, viewsets.GenericViewSet, ): - """ A viewset that provides the ability to list, get, create, and destroy projects. Multiple actions are available to manage project instances. """ - - def get_queryset(self): return ( super() @@ -157,7 +151,7 @@ def get_queryset(self): ) ) - @action( + @action( detail=True, methods=["get"], url_path="results", @@ -185,6 +179,7 @@ def sbom(self, request, *args, **kwargs): "sbom": "CycloneDX SBOM will be generated here", } ) + @action(detail=True, name="Results (download)") def results_download(self, request, *args, **kwargs): """Return the results in the provided `output_format` as an attachment."""