[Secure-testing-commits] r1977 - bin lib/python

Florian Weimer fw at costa.debian.org
Wed Sep 14 13:27:20 UTC 2005


Author: fw
Date: 2005-09-14 13:27:19 +0000 (Wed, 14 Sep 2005)
New Revision: 1977

Modified:
   bin/update-vulnerabilities
   lib/python/bugs.py
   lib/python/security_db.py
Log:
Ongoing work to implement version tracking.  The current approach does
not scale with the number of architectures, though.

lib/python/security_db.py (DB):
  Add nicknames member.
(DB.initSchema):
  Add nicknames and package_status tables.
  Add index package_notes_bug.
(DB._synthesizeReleases):
  New method to build testing etc. distributions.
(DB.calculateVulnerabilities):
  Update to use new tables.  Return list of problems detected.

lib/python/bugs.py (PackageNote.releaseStatus):
  New method to check for affected releases.

bin/update-vulnerabilities:
  Print list of detected problems.


Modified: bin/update-vulnerabilities
===================================================================
--- bin/update-vulnerabilities	2005-09-14 13:21:11 UTC (rev 1976)
+++ bin/update-vulnerabilities	2005-09-14 13:27:19 UTC (rev 1977)
@@ -28,5 +28,10 @@
 assert os.path.exists(db_file)
 db = security_db.DB(db_file, verbose=True)
 c = db.writeTxn()
-db.calculateVulnerabilities(c)
+warnings = db.calculateVulnerabilities(c)
+if warnings:
+    db.rollback(c)
+    for x in warnings:
+        print x
+    sys.exit(1)
 db.commit(c)

Modified: lib/python/bugs.py
===================================================================
--- lib/python/bugs.py	2005-09-14 13:21:11 UTC (rev 1976)
+++ lib/python/bugs.py	2005-09-14 13:27:19 UTC (rev 1977)
@@ -103,6 +103,26 @@
         else:
             return "unfixed"
 
+    def releaseStatus(self, cursor):
+        """Returns a pair of lists (VULNERABLE, NON-VULNERABLE).
+
+        The lists consits of triples (release, archive, architecture).
+        """
+
+        vulnerable = []
+        non_vulnerable  = []
+        
+        for (release, archive, architecture, vuln) in cursor.execute(
+            """SELECT release, archive, architecture, vulnerable
+            FROM package_status WHERE note = ?""", (self.id,)):
+            t = (release, archive,architecture)
+            if vuln:
+                vulnerable.append(t)
+            else:
+                non_vulnerable.append(t)
+
+        return (vulnerable, non_vulnerable)
+        
     def writeDB(self, cursor, bug_name):
         """Writes the object to an SQLite database.
 

Modified: lib/python/security_db.py
===================================================================
--- lib/python/security_db.py	2005-09-14 13:21:11 UTC (rev 1976)
+++ lib/python/security_db.py	2005-09-14 13:27:19 UTC (rev 1977)
@@ -63,6 +63,9 @@
     def __init__(self, name, verbose=False):
         self.db = apsw.Connection(name)
         self.verbose = verbose
+        self.nicknames = {'etch': 'testing',
+                          'sarge' : 'stable',
+                          'woody': 'oldstable'}
 
     def cursor(self):
         """Creates a new database cursor.
@@ -97,6 +100,13 @@
         (file TEXT NOT NULL PRIMARY KEY,
          inodeprint TEXT NOT NULL)""")
 
+        cursor.execute(
+            """CREATE TABLE nicknames
+            (realname TEXT NOT NULL,
+            nickname TEXT NOT NULL)""")
+        cursor.executemany("INSERT INTO nicknames VALUES (?, ?)",
+                           self.nicknames.items())
+
         cursor.execute("""CREATE TABLE version_linear_order
         (id INTEGER NOT NULL PRIMARY KEY,
          version TEXT NOT NULL UNIQUE)""")
@@ -128,6 +138,8 @@
          fixed_version_id INTEGER NOT NULL DEFAULT 0,
          release TEXT NOT NULL,
          urgency TEXT NOT NULL)""")
+        cursor.execute(
+            "CREATE INDEX package_notes_bug ON package_notes(bug_name)")
 
         cursor.execute("""CREATE TABLE debian_bugs
         (bug INTEGER NOT NULL,
@@ -163,6 +175,23 @@
          reason TEXT NOT NULL,
          PRIMARY KEY (bug_name, release, note))""")
          
+        cursor.execute("""CREATE TABLE package_status
+        (note INTEGER NOT NULL,
+        release TEXT NOT NULL,
+        archive TEXT NOT NULL,
+        architecture TEXT NOT NULL,
+        vulnerable INTEGER NOT NULL,
+        bug_name TEXT NOT NULL,
+        package TEXT NOT NULL,
+        source TEXT NOT NULL,
+        PRIMARY KEY (note, release, archive, architecture))""")
+        cursor.execute(
+            "CREATE INDEX package_status_bug ON package_status(bug_name)")
+        cursor.execute(
+            "CREATE INDEX package_status_package ON package_status(package)")
+        cursor.execute(
+            "CREATE INDEX package_status_source ON package_status(source)")
+
     def updateSources(self, cursor, release, archive, packages):
         """Reads a Sources file and adds it to the database.
 
@@ -290,8 +319,7 @@
         cursor.execute("""INSERT INTO inodeprints (file, inodeprint)
         VALUES (?, ?)""", (filename, current_print))
         return result
-        
-    
+
     def maybeUpdateSources(self, cursor, release, archive, filename):
         """Reads the Sources file filename if it has been modified."""
         self._maybeUpdate(cursor, (release, archive), filename,
@@ -508,17 +536,183 @@
         if self.verbose:
             print "  finished"
         
+    def _synthesizeReleases(self, cursor):
+        """Creates the package lists for testing, stable and oldstable.
+
+        These package lists include security updates.
+        """
+
+        if self.verbose:
+            print "synthesizeReleases:"
+            print "  clear old data"
+            print "    source packages"
+        cursor.execute(
+            """DELETE FROM source_packages
+            WHERE release IN ('stable', 'oldstable', 'testing')""")
+        if self.verbose:
+            print "    binary packages"
+        cursor.execute(
+            """DELETE FROM binary_packages
+            WHERE release IN ('stable', 'oldstable', 'testing')""")
+
+        for (realname, nickname) in self.nicknames.items():
+            if self.verbose:
+                print "  synthesize %s to %s" % (realname, nickname)
+                print "    source packages"
+            cursor.execute(
+                """INSERT INTO source_packages 
+                SELECT package, ?, archive, '', MAX(version_id) AS vid
+                FROM source_packages WHERE release IN (?, ?)
+                GROUP BY package, archive""",
+                (nickname, realname, realname + '-security'))
+            
+            if self.verbose:
+                print "    binary packages"
+            cursor.execute(
+                """INSERT INTO binary_packages 
+                SELECT DISTINCT package, ?, archive, architecture, '',
+                MAX (version_id) AS vid, source, source_version
+                FROM binary_packages WHERE release IN (?, ?)
+                GROUP BY package, archive, architecture""",
+                (nickname, realname, realname + '-security'))
+
+        if self.verbose:
+            print "  patch version strings"
+            print "    source packages"
+        cursor.execute(
+            """UPDATE source_packages
+            SET version = (SELECT version FROM version_linear_order
+            WHERE id = version_id)
+            WHERE version = ''""")
+        if self.verbose:
+            print "    binary packages"
+        cursor.execute(
+            """UPDATE binary_packages
+            SET version = (SELECT version FROM version_linear_order
+            WHERE id = version_id)
+            WHERE version = ''""")
+
+        if self.verbose:
+            print "  finished"
+
     def calculateVulnerabilities(self, cursor):
         """Calculate vulnerable packages.
 
         To each package note, a release-specific vulnerability status
         is attached.  Currently, only etch/testing is processed.
+
+        Returns a list strings describing inconsistencies.
         """
 
+        result = []
+
         self._updateVersions(cursor)
+        self._synthesizeReleases(cursor)
 
         if self.verbose:
             print "calculateVulnerabilities:"
+            print "  check for version consistency in package notes"
+        for (bug_name, pkg_name, rel, unstable_ver, rel_ver) \
+                in list(cursor.execute(
+        """SELECT a.bug_name, a.package, a.release,
+        a.fixed_version, b.fixed_version
+        FROM package_notes a, package_notes b
+        WHERE a.bug_name = b.bug_name AND a.package = b.package
+        AND a.release = '' AND b.release <> ''
+        AND a.fixed_version_id < b.fixed_version_id""")):
+            b = bugs.BugFromDB(cursor, bug_name)
+            result.append("%s:%d: inconsistent versions for package %s"
+                          % (b.source_file, b.source_line, pkg_name))
+            result.append("%s:%d: unstable: %s"
+                          % (b.source_file, b.source_line, rel_ver))
+            result.append("%s:%d: release %s: %s"
+                          % (b.source_file, b.source_line, `rel`, rel_ver))
+
+        if self.verbose:
+            print "  create temporary tables"
+        cursor.execute(
+            """CREATE TEMPORARY TABLE tmp_bug_releases
+            (bug_name TEXT NOT NULL,
+            release TEXT NOT NULL,
+            PRIMARY KEY (bug_name, release))""")
+        for (bug_name, release) in list(cursor.execute(
+            """SELECT DISTINCT bug_name, release FROM package_notes
+            WHERE release <> ''""")):
+            data = [(bug_name, release),
+                    (bug_name, release + '-security')]
+            try:
+                data.append((bug_name, self.nicknames[release]))
+            except KeyError:
+                pass
+            cursor.executemany("INSERT INTO tmp_bug_releases VALUES (?, ?)",
+                               data)
+
+        if self.verbose:
+            print "  remove old status"
+        cursor.execute("DELETE FROM package_status")
+        if self.verbose:
+            print "  calculate package status"
+            print "    source packages (unqualified)"
+
+        # If there is a single package note qualified with a specific
+        # release, ignore all the unqualified annotations (even for
+        # other packages).  This is implemented by looking at the
+        # tmp_bug_releases table.
+        
+        cursor.execute(
+            """INSERT INTO package_status
+            SELECT n.id, p.release, p.archive, '' AS architecture,
+            p.version_id < n.fixed_version_id,
+            n.bug_name, p.package, p.package AS source
+            FROM package_notes AS n, source_packages AS p
+            WHERE n.release = '' AND p.package = n.package
+            AND NOT EXISTS (SELECT * FROM tmp_bug_releases AS t
+                            WHERE t.bug_name = n.bug_name
+                            AND t.release = n.release)""")
+        if self.verbose:
+            print "    source packages (qualified)"
+        cursor.execute(
+            """INSERT INTO package_status
+            SELECT n.id, p.release, p.archive, '' AS architecture,
+            p.version_id < n.fixed_version_id,
+            n.bug_name, p.package, p.package AS source
+            FROM package_notes AS n, source_packages AS p
+            WHERE p.package = n.package
+            AND (p.release = n.release
+                 OR p.release = n.release || '-security'
+                 OR p.release = (SELECT nickname FROM nicknames
+                                 WHERE realname = n.release))""")
+
+        # Same story for binary packages.
+            
+        if self.verbose:
+            print "    binary packages"
+        cursor.execute(
+            """INSERT INTO package_status
+            SELECT n.id, p.release, p.archive, p.architecture,
+            p.version_id < n.fixed_version_id AS fixed,
+            n.bug_name, p.package, p.source
+            FROM package_notes AS n, binary_packages AS p
+            WHERE n.release = '' AND p.package = n.package
+            AND NOT EXISTS (SELECT * FROM tmp_bug_releases AS t
+                            WHERE t.bug_name = n.bug_name
+                            AND t.release = n.release)""")
+        if self.verbose:
+            print "    binary packages (qualified)"
+        cursor.execute(
+            """INSERT INTO package_status
+            SELECT n.id, p.release, p.archive, p.architecture AS architecture,
+            p.version_id < n.fixed_version_id,
+            n.bug_name, p.package, p.package AS source
+            FROM package_notes AS n, binary_packages AS p
+            WHERE p.package = n.package
+            AND (p.release = n.release
+                 OR p.release = n.release || '-security'
+                 OR p.release = (SELECT nickname FROM nicknames
+                                 WHERE realname = n.release))""")
+        
+
+        if self.verbose:
             print "  clearing old data"
         cursor.execute("DELETE FROM bugs_status")
 
@@ -617,6 +811,8 @@
         if self.verbose:
             print "  finished"
 
+        return result
+
     def check(self, cursor=None):
         """Runs a simple consistency check and prints the results."""
 




More information about the Secure-testing-commits mailing list