[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