@@ -221,18 +221,24 @@ def get_affected_by_vulnerabilities(self, package):
221221 """Return a dictionary with advisory as keys and their details, including fixed_by_packages."""
222222 advisories = self .context ["advisory_map" ].get (package .id , [])
223223 impact_map = self .context ["impact_map" ].get (package .id , {})
224+ introduced_patch_map = self .context .get ("introduced_patch_map" , {})
225+ fixed_patch_map = self .context .get ("fixed_patch_map" , {})
224226
225227 if advisories :
226228 result = []
227229
228230 for adv in advisories :
229231 fixed = impact_map .get (adv ["avid" ])
232+ introduced_patches = introduced_patch_map .get ((package .id , adv ["avid" ]), [])
233+ fixed_patches = fixed_patch_map .get ((package .id , adv ["avid" ]), [])
230234 adv .pop ("avid" , None )
231235
232236 result .append (
233237 {
234238 ** adv ,
235239 "fixed_by_packages" : fixed ,
240+ "introduced_by_patch" : introduced_patches ,
241+ "fixed_by_patch" : fixed_patches ,
236242 }
237243 )
238244
@@ -266,7 +272,8 @@ def get_affected_by_vulnerabilities(self, package):
266272 impact = impact_by_avid .get (advisory .avid )
267273 if not impact :
268274 continue
269-
275+ introduced_patches = introduced_patch_map .get ((package .id , advisory .avid ), [])
276+ fixed_patches = fixed_patch_map .get ((package .id , advisory .avid ), [])
270277 result .append (
271278 {
272279 "advisory_id" : advisory .advisory_id .split ("/" )[- 1 ],
@@ -276,9 +283,10 @@ def get_affected_by_vulnerabilities(self, package):
276283 "exploitability" : advisory .exploitability ,
277284 "risk_score" : advisory .risk_score ,
278285 "fixed_by_packages" : [pkg .purl for pkg in impact .fixed_by_packages .all ()],
286+ "introduced_by_patch" : introduced_patches ,
287+ "fixed_by_patch" : fixed_patches ,
279288 }
280289 )
281-
282290 return result
283291
284292 if not advisories :
@@ -456,6 +464,7 @@ def create(self, request, *args, **kwargs):
456464 affected_advisory_map = get_affected_advisories_bulk (page )
457465 fixing_advisory_map = get_fixing_advisories_bulk (page )
458466 impact_map = get_impacts_bulk (page )
467+ introduced_patch_map , fixed_patch_map = get_patches_bulk (page )
459468 serializer = self .get_serializer (
460469 page ,
461470 many = True ,
@@ -464,6 +473,8 @@ def create(self, request, *args, **kwargs):
464473 "advisory_map" : affected_advisory_map ,
465474 "impact_map" : impact_map ,
466475 "fixing_advisory_map" : fixing_advisory_map ,
476+ "introduced_patch_map" : introduced_patch_map ,
477+ "fixed_patch_map" : fixed_patch_map ,
467478 },
468479 )
469480 return self .get_paginated_response (serializer .data )
@@ -673,6 +684,48 @@ def get_impacts_bulk(packages):
673684 return impact_map
674685
675686
687+ def get_patches_bulk (packages ):
688+ """
689+ Returns a tuple of two dicts:
690+ introduced_map: (package_id, advisory_avid) -> list of introduced package_commit_patches dicts
691+ fixed_map: (package_id, advisory_avid) -> list of fixed package_commit_patches dicts
692+ Each package_commit_patches dict contains 'commit_hash' and 'vcs_url'
693+ """
694+ package_ids = [p .id for p in packages ]
695+ if not package_ids :
696+ return {}, {}
697+
698+ impacted_packages_qs = (
699+ ImpactedPackageAffecting .objects .filter (package_id__in = package_ids )
700+ .select_related ("impacted_package__advisory" )
701+ .prefetch_related (
702+ "impacted_package__introduced_by_package_commit_patches" ,
703+ "impacted_package__fixed_by_package_commit_patches" ,
704+ )
705+ )
706+
707+ introduced_patches = defaultdict (list )
708+ fixed_patches = defaultdict (list )
709+
710+ for impacted_pkg_qs in impacted_packages_qs :
711+ pkg_id = impacted_pkg_qs .package_id
712+ impact = impacted_pkg_qs .impacted_package
713+ avid = impact .advisory .avid
714+ key = (pkg_id , avid )
715+
716+ for patch in impact .introduced_by_package_commit_patches .all ():
717+ patch_data = {"commit_hash" : patch .commit_hash , "vcs_url" : patch .vcs_url }
718+ if patch_data not in introduced_patches [key ]:
719+ introduced_patches [key ].append (patch_data )
720+
721+ for patch in impact .fixed_by_package_commit_patches .all ():
722+ patch_data = {"commit_hash" : patch .commit_hash , "vcs_url" : patch .vcs_url }
723+ if patch_data not in fixed_patches [key ]:
724+ fixed_patches [key ].append (patch_data )
725+
726+ return introduced_patches , fixed_patches
727+
728+
676729def get_fixing_advisories_bulk (packages ):
677730 package_ids = [p .id for p in packages ]
678731
0 commit comments