@@ -17,26 +17,27 @@ The first step in writing a vulnerability report for a Pulp `content unit` is to
1717package [ ` ecosystem ` ] ( https://google.github.io/osv.dev/post-v1-query/#parameters ) by checking
1818[ https://ossf.github.io/osv-schema/#defined-ecosystems ] ( https://ossf.github.io/osv-schema/#defined-ecosystems ) .
1919
20- The next step is to create a function at the top level of the module, so it can be loaded in pulpcore,
21- that will be run as a Pulp task. This function should add a dictionary (the ` osv_data ` created through
22- ` build_osv_data ` function in the following sample) to the ` pulpcore.app.tasks.vulnerability_report.content_queue ` queue.
20+ The next step is to create an async function at the top level of the module (so it can be
21+ loaded in pulpcore) that will be run as a Pulp task. This async function should return a generator
22+ object with a dictionary containing the ` osv_data ` (created through ` build_osv_data ` function in the following sample),
23+ and also the ` Content ` and ` RepositoryVersion ` objects.
2324
2425Here is an example of a function with the above steps:
2526
2627``` python
27- from pulpcore.plugin.tasking import content_queue
28-
29- def get_content_from_repo_version ( repo_version_pk : str ):
30- """
31- Populate content_queue Queue with the content_units found in RepositoryVersion
32- """
33- repo_version = RepositoryVersion.objects.get( pk = repo_version_pk )
34- ecosystem = " PyPI "
35- for content_unit in repo_version.content:
36- content = content_unit.cast( )
37- osv_data = build_osv_data(content.name, ecosystem, content.version)
38- content_queue.put(osv_data)
39- content_queue.put( None ) # signal that there are no more content_units
28+ async def get_content_from_repo_version ( repo_version_pk : str ):
29+ repo_version = await sync_to_async(RepositoryVersion.objects.get)( pk = repo_version_pk)
30+ content_units = await sync_to_async( list )(repo_version.content.all())
31+
32+ for content_unit in content_units:
33+ content = await sync_to_async(content_unit.cast)()
34+ content_name = await sync_to_async( lambda : content.name)( )
35+ content_version = await sync_to_async( lambda : content.version)()
36+ ecosystem = " PyPI "
37+ repo_content_osv_data = build_osv_data(content_name, ecosystem, content_version )
38+ repo_content_osv_data[ " repo_version " ] = repo_version
39+ repo_content_osv_data[ " content " ] = content
40+ yield repo_content_osv_data
4041
4142def build_osv_data (name , ecosystem , version = None ):
4243 osv_data = {" package" : {" name" : name, " ecosystem" : ecosystem}}
@@ -46,9 +47,7 @@ def build_osv_data(name, ecosystem, version=None):
4647```
4748
4849
49- Now that we have the function to populate the ` content_queue ` queue, we need to create a ` ViewSet `
50- to dispatch a task with it:
51-
50+ Now that we have the async generator function, we need to create a ` ViewSet ` to dispatch a task with it:
5251
5352!!! note
5453 In the following sample, we are not defining the permissions to access the endpoint.
@@ -65,7 +64,6 @@ from my_plugin.app.viewsets import get_content_from_repo_version
6564
6665class MyPluginVulnerabilityReport (VulnerabilityReportViewSet ):
6766
68- endpoint_name = " vuln_report"
6967 queryset = VulnerabilityReport.objects.all()
7068 serializer_class = VulnerabilityReportSerializer
7169
@@ -81,14 +79,18 @@ class MyPluginVulnerabilityReport(VulnerabilityReportViewSet):
8179 repo_version = serializer.validated_data[" repo_version" ]
8280
8381 # we need to pass the function as string because dispatch() args only accepts JSON serializable content
84- content_queue_func = f " { get_content_from_repo_version.__module__ } . { get_content_from_repo_version.__name__ } "
82+ func = f " { get_content_from_repo_version.__module__ } . { get_content_from_repo_version.__name__ } "
8583
8684 task = dispatch(
8785 check_content,
8886 shared_resources = [repo_version.repository],
89- kwargs = { " func " : content_queue_func , [repo_version.pk]}
87+ args = [func , [repo_version.pk]],
9088 )
9189 return OperationPostponedResponse(task, request)
90+
91+ @ classmethod
92+ def routable (cls ):
93+ return True
9294```
9395
9496Here is a sample for the ` MyPluginVulnerabilityReportSerializer ` where we serialize the
0 commit comments