@@ -2750,18 +2750,6 @@ class AdvisoryV2(models.Model):
27502750 help_text = "Raw advisory data as collected from the upstream datasource." ,
27512751 )
27522752
2753- affecting_packages = models .ManyToManyField (
2754- "PackageV2" ,
2755- related_name = "affected_by_advisories" ,
2756- help_text = "A list of packages that are affected by this advisory." ,
2757- )
2758-
2759- fixed_by_packages = models .ManyToManyField (
2760- "PackageV2" ,
2761- related_name = "fixing_advisories" ,
2762- help_text = "A list of packages that are reported by this advisory." ,
2763- )
2764-
27652753 status = models .IntegerField (
27662754 choices = AdvisoryStatusType .choices , default = AdvisoryStatusType .PUBLISHED
27672755 )
@@ -2816,18 +2804,17 @@ def get_absolute_url(self):
28162804 """
28172805 return reverse ("advisory_details" , args = [self .avid ])
28182806
2819- def to_advisory_data (self ) -> "AdvisoryDataV2" :
2820- from vulnerabilities .importer import AdvisoryDataV2
2821- from vulnerabilities .importer import AffectedPackage
2807+ def to_advisory_data (self ) -> "AdvisoryData" :
2808+ from vulnerabilities .importer import AdvisoryData
28222809 from vulnerabilities .importer import ReferenceV2
28232810
2824- return AdvisoryDataV2 (
2811+ return AdvisoryData (
28252812 aliases = [item .alias for item in self .aliases .all ()],
28262813 summary = self .summary ,
28272814 affected_packages = [
2828- AffectedPackage . from_dict ( pkg ) for pkg in self .affected_packages if pkg
2815+ impacted . to_affected_package ( ) for impacted in self .impacted_packages . all ()
28292816 ],
2830- references = [ReferenceV2 .from_dict (ref ) for ref in self .references ],
2817+ references_v2 = [ReferenceV2 .from_dict (ref ) for ref in self .references ],
28312818 date_published = self .date_published ,
28322819 weaknesses = self .weaknesses ,
28332820 severities = self .severities ,
@@ -2841,66 +2828,69 @@ def get_aliases(self):
28412828 """
28422829 return self .aliases .all ()
28432830
2844- def aggregate_fixed_and_affected_packages (self ):
2845- from vulnerabilities .utils import get_purl_version_class
2846-
2847- sorted_fixed_by_packages = self .fixed_by_packages .filter (is_ghost = False ).order_by (
2848- "type" , "namespace" , "name" , "qualifiers" , "subpath"
2849- )
2850-
2851- if sorted_fixed_by_packages :
2852- sorted_fixed_by_packages .first ().calculate_version_rank
2831+ alias = get_aliases
28532832
2854- sorted_affected_packages = self .affecting_packages .all ()
28552833
2856- if sorted_affected_packages :
2857- sorted_affected_packages .first ().calculate_version_rank
2834+ class ImpactedPackage (models .Model ):
2835+ """
2836+ Represents a single impact for an advisory, including affected range and fixed version and
2837+ associated package relations.
2838+ """
28582839
2859- grouped_fixed_by_packages = {
2860- key : list (group )
2861- for key , group in groupby (
2862- sorted_fixed_by_packages ,
2863- key = attrgetter ("type" , "namespace" , "name" , "qualifiers" , "subpath" ),
2864- )
2865- }
2840+ advisory = models .ForeignKey (
2841+ AdvisoryV2 ,
2842+ related_name = "impacted_packages" ,
2843+ on_delete = models .CASCADE ,
2844+ )
28662845
2867- all_affected_fixed_by_matches = []
2846+ base_purl = models .CharField (
2847+ max_length = 500 ,
2848+ blank = True ,
2849+ help_text = "Version less PURL related to impacted range." ,
2850+ )
28682851
2869- for sorted_affected_package in sorted_affected_packages :
2870- affected_fixed_by_matches = {
2871- "affected_package" : sorted_affected_package ,
2872- "matched_fixed_by_packages" : [] ,
2873- }
2852+ affecting_vers = models . CharField (
2853+ max_length = 500 ,
2854+ blank = True ,
2855+ help_text = "VersionRange expression for package vulnerable to this impact." ,
2856+ )
28742857
2875- # Build the key to find matching group
2876- key = (
2877- sorted_affected_package .type ,
2878- sorted_affected_package .namespace ,
2879- sorted_affected_package .name ,
2880- sorted_affected_package .qualifiers ,
2881- sorted_affected_package .subpath ,
2882- )
2858+ fixed_vers = models .CharField (
2859+ max_length = 500 ,
2860+ blank = True ,
2861+ help_text = "VersionRange expression for packages fixing the vulnerable package in this impact." ,
2862+ )
28832863
2884- # Get matching group from pre-grouped fixed_by_packages
2885- matching_fixed_packages = grouped_fixed_by_packages .get (key , [])
2864+ affecting_packages = models .ManyToManyField (
2865+ "PackageV2" ,
2866+ related_name = "affected_in_impacts" ,
2867+ help_text = "Packages vulnerable to this impact." ,
2868+ )
28862869
2887- # Get version classes for comparison
2888- affected_version_class = get_purl_version_class (sorted_affected_package )
2889- affected_version = affected_version_class (sorted_affected_package .version )
2870+ fixed_by_packages = models .ManyToManyField (
2871+ "PackageV2" ,
2872+ related_name = "fixed_in_impacts" ,
2873+ help_text = "Packages vulnerable to this impact." ,
2874+ )
28902875
2891- # Compare versions and filter valid matches
2892- matched_fixed_by_packages = [
2893- fixed_by_package .purl
2894- for fixed_by_package in matching_fixed_packages
2895- if get_purl_version_class (fixed_by_package )(fixed_by_package .version )
2896- > affected_version
2897- ]
2876+ class Meta :
2877+ indexes = [
2878+ models .Index (fields = ["affecting_vers" ]),
2879+ models .Index (fields = ["fixed_vers" ]),
2880+ ]
28982881
2899- affected_fixed_by_matches ["matched_fixed_by_packages" ] = matched_fixed_by_packages
2900- all_affected_fixed_by_matches .append (affected_fixed_by_matches )
2901- return sorted_fixed_by_packages , sorted_affected_packages , all_affected_fixed_by_matches
2882+ def to_affected_package (self ):
2883+ """Return `AffectedPackageV2` data from the impact."""
2884+ from vulnerabilities .importer import AffectedPackageV2
2885+ from vulnerabilities .utils import purl_to_dict
29022886
2903- alias = get_aliases
2887+ return AffectedPackageV2 .from_dict (
2888+ affected_pkg = {
2889+ "package" : purl_to_dict (self .base_purl ),
2890+ "affected_version_range" : self .affecting_vers ,
2891+ "fixed_version_range" : self .fixed_vers ,
2892+ }
2893+ )
29042894
29052895
29062896class ToDoRelatedAdvisory (models .Model ):
0 commit comments