2121
2222from errata .managers import ErratumManager
2323from packages .models import Package , PackageUpdate
24- from packages .utils import find_evr , get_matching_packages
24+ from packages .utils import find_evr , get_matching_packages_q
2525from security .models import CVE , Reference
2626from security .utils import get_or_create_cve , get_or_create_reference
2727from util import get_url
@@ -64,34 +64,32 @@ def get_absolute_url(self):
6464
6565 def scan_for_security_updates (self ):
6666 if self .e_type == 'security' :
67- for package in self .fixed_packages .all ():
68- affected_updates = PackageUpdate . objects . filter (
69- newpackage = package ,
70- security = False ,
67+ fixed_pks = list ( self .fixed_packages .values_list ( 'pk' , flat = True ))
68+ if fixed_pks :
69+ self . _mark_updates_security (
70+ PackageUpdate . objects . filter ( newpackage__in = fixed_pks , security = False )
7171 )
72- for affected_update in affected_updates :
73- affected_update .security = True
74- try :
75- affected_update .save ()
76- except IntegrityError as e :
77- error_message (text = e )
78- # a version of this update already exists that is
79- # marked as a security update, so delete this one
80- affected_update .delete ()
81- for package in self .affected_packages .all ():
82- affected_updates = PackageUpdate .objects .filter (
83- oldpackage = package ,
84- security = False ,
72+ affected_pks = list (self .affected_packages .values_list ('pk' , flat = True ))
73+ if affected_pks :
74+ self ._mark_updates_security (
75+ PackageUpdate .objects .filter (oldpackage__in = affected_pks , security = False )
8576 )
86- for affected_update in affected_updates :
87- affected_update .security = True
88- try :
89- affected_update .save ()
90- except IntegrityError as e :
91- error_message (text = e )
92- # a version of this update already exists that is
93- # marked as a security update, so delete this one
94- affected_update .delete ()
77+
78+ def _mark_updates_security (self , updates ):
79+ """ Mark a queryset of PackageUpdates as security updates.
80+ Handles IntegrityError by deleting duplicates.
81+ """
82+ try :
83+ updates .update (security = True )
84+ except IntegrityError :
85+ # fall back to individual saves to handle duplicates
86+ for update in updates :
87+ update .security = True
88+ try :
89+ update .save ()
90+ except IntegrityError as e :
91+ error_message (text = e )
92+ update .delete ()
9593
9694 def fetch_osv_dev_data (self ):
9795 osv_dev_url = f'https://api.osv.dev/v1/vulns/{ self .name } '
@@ -104,15 +102,19 @@ def fetch_osv_dev_data(self):
104102 self .parse_osv_dev_data (osv_dev_json )
105103
106104 def parse_osv_dev_data (self , osv_dev_json ):
105+ from django .db .models import Q
107106 name = osv_dev_json .get ('id' )
108107 if name != self .name :
109108 error_message (text = f'Erratum name mismatch - { self .name } != { name } ' )
110109 return
111110 related = osv_dev_json .get ('related' )
112111 if related :
112+ cves = []
113113 for vuln in related :
114114 if vuln .startswith ('CVE' ):
115- self .add_cve (vuln )
115+ cves .append (vuln )
116+ for cve_id in cves :
117+ self .add_cve (cve_id )
116118 affected = osv_dev_json .get ('affected' )
117119 if not affected :
118120 return
@@ -129,30 +131,29 @@ def parse_osv_dev_data(self, osv_dev_json):
129131 for match in matching_packages :
130132 fixed_packages .add (match )
131133 affected_versions = package .get ('versions' )
132- if not affected_versions :
134+ if not affected_versions or not fixed_packages :
133135 continue
134- for package in fixed_packages :
136+ for fp in fixed_packages :
137+ q = Q ()
135138 for version in affected_versions :
136139 epoch , ver , rel = find_evr (version )
137- matching_packages = get_matching_packages (
138- name = package .name ,
139- epoch = epoch ,
140- version = ver ,
141- release = rel ,
142- arch = package .arch ,
143- p_type = package .packagetype ,
144- )
145- for match in matching_packages :
146- affected_packages .add (match )
140+ q |= Q (epoch = epoch , version = ver , release = rel )
141+ matching_packages = get_matching_packages_q (
142+ name = fp .name ,
143+ q = q ,
144+ arch = fp .arch ,
145+ p_type = fp .packagetype ,
146+ )
147+ affected_packages .update (matching_packages )
147148 self .add_affected_packages (affected_packages )
148149
149150 def add_fixed_packages (self , packages ):
150- for package in packages :
151- self .fixed_packages .add (package )
151+ if packages :
152+ self .fixed_packages .add (* packages )
152153
153154 def add_affected_packages (self , packages ):
154- for package in packages :
155- self .affected_packages .add (package )
155+ if packages :
156+ self .affected_packages .add (* packages )
156157
157158 def add_cve (self , cve_id ):
158159 """ Add a CVE to an Erratum object
0 commit comments