Author: fw Date: 2005-09-21 06:08:51 +0000 (Wed, 21 Sep 2005) New Revision: 2062 Modified: lib/python/security_db.py Log: lib/python/security_db.py (DB.calculateVulnerabilities): Factor out testing and unstable code. (DB._calcUnstable): New. Mostly unchanged from the verison in calculateVulnerabilities. (DB._calcTesting): Rewritten from scratch. Now works on source packages. Should be more reliable. Modified: lib/python/security_db.py ==================================================================--- lib/python/security_db.py 2005-09-21 04:03:03 UTC (rev 2061) +++ lib/python/security_db.py 2005-09-21 06:08:51 UTC (rev 2062) @@ -1030,184 +1030,104 @@ for (bug_name,) in cursor.execute( "SELECT name FROM bugs WHERE NOT not_for_us"): - # Calculate status for unstable. Only source package - # status is relevant here. + self._calcUnstable(c, bug_name) + self._calcTesting(c, bug_name) - def handle_unstable(): - unstable_packages = [] - for (package,) in c.execute( - """SELECT DISTINCT sp.name - FROM package_notes AS n, - source_package_status AS st, source_packages AS sp - WHERE n.bug_name = ? AND n.urgency <> ''unimportant'' - AND n.release = '''' - AND st.note = n.id AND st.vulnerable - AND sp.rowid = st.package AND sp.release = ''sid'' - ORDER BY sp.name""", - (bug_name,)): - unstable_packages.append(package) + return result - if unstable_packages: - if len(unstable_packages) == 1: - pkgs = ("package %s is vulnerable" - % unstable_packages[0]) - else: - pkgs = ("packages %s are vulnerable" - % '', ''.join(unstable_packages)) - c.execute("""INSERT INTO bug_status - (bug_name, release, status, reason) - VALUES (?, ''unstable'', ''vulnerable'', ?)""", - (bug_name, pkgs)) - else: - c.execute("""INSERT INTO bug_status - (bug_name, release, status, reason) - VALUES (?, ''unstable'', ''fixed'', - ''not known to be vulnerable'')""", - (bug_name,)) - handle_unstable() + def _calcUnstable(self, cursor, bug_name): + """Update bug_status with bug_name for unstable.""" + + vulnerable_packages = [] + for (package,) in cursor.execute( + """SELECT DISTINCT sp.name + FROM package_notes AS n, + source_package_status AS st, source_packages AS sp + WHERE n.bug_name = ? AND n.urgency <> ''unimportant'' + AND n.release = '''' + AND st.note = n.id AND st.vulnerable + AND sp.rowid = st.package AND sp.release = ''sid'' + ORDER BY sp.name""", + (bug_name,)): + vulnerable_packages.append(package) - # The algorith below roughly proceeds as follows: - # - # For each package: - # Is this package in testing/unstable? If not, exit. - # - # Differentiate between the following cases: - # For all architectures with security support, the - # package in testing is not vulnerable (fully fixed) - # - # For all architectures with security support, the - # package is not vulnerable in testing or - # testing-security, and there exists a package (on a - # security support architecture) which is vulnerable - # in testing (partially fixed) - # - # There exists an architecture with security support - # where the package is fixed in testing, and there - # exists a non-vulnerable architecture in testing - # (should not happen, partially-fixed) - # - # Same as the preceding case, but including - # test-security; this can actually happen - # (partially-fixed, secure-testing is out-of-date on - # some architectures) - # - # There exists an architecture with security support - # where the package is fixed in unstable, and all - # packages in testing are vulnerable, and the - # package is in testing (fixed in unstable) - # - # For some supported architecture the package is in - # testing, and vulnerable. It is - # - # The package is not in testing on any supported - # architecture, - # - # At least this is the plan. The code below probably does - # something slightly different. 8-( + if vulnerable_packages: + if len(vulnerable_packages) == 1: + pkgs = "package %s is vulnerable" % vulnerable_packages[0] + else: + pkgs = ("packages %s are vulnerable" + % '', ''.join(vulnerable_packages)) + cursor.execute("""INSERT INTO bug_status + (bug_name, release, status, reason) + VALUES (?, ''unstable'', ''vulnerable'', ?)""", + (bug_name, pkgs)) + else: + cursor.execute("""INSERT INTO bug_status + (bug_name, release, status, reason) + VALUES (?, ''unstable'', ''fixed'', + ''not known to be vulnerable'')""", + (bug_name,)) - available_archs = {} - vulnerable_in_other = {} - vulnerable_in_testing = {} - fixed_in_testing = {} - fixed_in_security = {} + def _calcTesting(self, cursor, bug_name): + """Update bug_status with bug_name for unstable.""" - def record_archs_per_package(dict, pkg, archs): - if not dict.has_key(pkg): - dict[pkg] = {} - for arch in archs.split('',''): - dict[pkg][arch] = True - - for (pkg_name, release, subrelease, archs, vulnerable) \ - in c.execute( - """SELECT DISTINCT - p.name, p.release, p.subrelease, p.archs, vulnerable - FROM binary_package_status AS s, binary_packages AS p - WHERE s.bug_name = ? AND p.rowid = s.package""", (bug_name,)): - if not binary_packages_in_testing.has_key(pkg_name): - continue + # Note that there is at most one source package per + # note/release/subrelease triple, but we should check that + # here. (A separate test is needed.) - record_archs_per_package(available_archs, pkg_name, archs) + status = {'''' : {}, ''security'' : {}} + for (package, note, subrelease, vulnerable) in cursor.execute( + """SELECT DISTINCT sp.name, n.id, sp.subrelease, + st.vulnerable + FROM package_notes AS n, + source_package_status AS st, source_packages AS sp + WHERE n.bug_name = ? AND n.urgency <> ''unimportant'' + AND st.note = n.id + AND sp.rowid = st.package AND sp.release = ''etch'' + AND sp.subrelease IN ('''', ''security'') + ORDER BY sp.name""", + (bug_name,)): + status[subrelease][(package, note)] = vulnerable - if release == ''etch'': - if vulnerable: - record_archs_per_package(vulnerable_in_testing, - pkg_name, archs) - else: - if subrelease == '''': - record_archs_per_package(fixed_in_testing, - pkg_name, archs) - record_archs_per_package(fixed_in_security, - pkg_name, archs) - elif subrelease == ''security'': - record_archs_per_package(fixed_in_security, - pkg_name, archs) - elif vulnerable: - record_archs_per_package(vulnerable_in_other, - pkg_name, archs) + # Check if any packages in plain testing are vulnerable, and + # if all of those have been fixed in the security archive. + fixed_in_security = True + pkgs = {} + for ((package, note), vulnerable) in status[''''].items(): + if vulnerable: + pkgs[package] = True + if status[''security''].get((package, note), True): + fixed_in_security = False - def record(status, reason): - if status <> ''vulnerable'': - ((has_todo,),) = c.execute( - """SELECT EXISTS (SELECT * FROM bugs_notes - WHERE bug_name = ? AND typ = ''TODO'')""", - (bug_name,)) - if has_todo: - status = ''todo'' - reason = ''see notes below'' - - c.execute( - """INSERT INTO bug_status - (bug_name, release, status, reason) - VALUES (?, ''testing'', ?, ?)""", - (bug_name, status, reason)) + pkgs = pkgs.keys() + pkgs.sort() + if len(pkgs) == 0: + if len(status[''''].keys()) == 0: + msg = "not known to be vulnerable" + else: + msg = "not vulnerable" + cursor.execute("""INSERT INTO bug_status + (bug_name, release, status, reason) + VALUES (?, ''testing'', ''fixed'', ?)""", + (bug_name, msg)) + return - if len(available_archs.keys()) == 0: - record(''fixed'', - ''package(s) neither in testing nor in unstable'') - continue + if len(pkgs) == 1: + pkgs = "package " + pkgs[0] + " is " + else: + pkgs = "packages " + ", ".join(pkgs) + " are " + if fixed_in_security: + pkgs += "fixed in testing-security" + status = "partially-fixed" + else: + pkgs += "vulnerable" + status = "vulnerable" - totally_unfixed_packages = [] - testing_missing_archs = {} - security_missing_archs = {} - for (pkg_name, archs) in vulnerable_in_other.items(): - fixed_somewhere = False - for arch in archs.keys(): - if fixed_in_testing.get(pkg_name, {}).has_key(arch): - fixed_somewhere = True - else: - testing_missing_archs[arch] = True - if fixed_in_security.get(pkg_name, {}).has_key(arch): - fixed_somewhere = True - else: - security_missing_archs[arch] = True - if not fixed_somewhere: - totally_unfixed_packages.append(pkg_name) - - if totally_unfixed_packages: - totally_unfixed_packages.sort() - if len(totally_unfixed_packages) == 1: - record(''vulnerable'', ''package %s is vulnerable'' - % totally_unfixed_packages[0]) - else: - record(''vulnerable'', ''packages %s are vulnerable'' - % '', ''.join(totally_unfixed_packages)) - continue + cursor.execute("""INSERT INTO bug_status + (bug_name, release, status, reason) + VALUES (?, ''testing'', ?, ?)""", + (bug_name, status, pkgs)) - if security_missing_archs.keys(): - record(''partially-fixed'', - ''fixed via testing-security, '' - + ''but architectures out of date: '' - + '', ''.join(security_missing_archs.keys())) - continue - - if testing_missing_archs.keys(): - record(''partially-fixed'', ''fixed in testing-security'') - continue - - record(''fixed'', ''packages are not vulnerable'') - - return result - def getSourcePackageVersions(self, cursor, pkg): """A generator which returns tuples (RELEASE-LIST, VERSION), the available versions of the source package pkg."""