/[secure-testing]/lib/python/security_db.py
ViewVC logotype

Contents of /lib/python/security_db.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1973 - (show annotations) (download) (as text)
Wed Sep 14 08:59:50 2005 UTC (7 years, 8 months ago) by fw
File MIME type: text/x-python
File size: 28844 byte(s)
Add table version_linear_order, which will enable us to make version
comparisons in pure SQL.

lib/python/security_db.py (DB):
  Add verbose flag to constructor.
(DB.initSchema):
  Add table version_linear_order.  Add version ID fields to tables
  package_notes, source_packages, binary_packages.
(DB._maybeUpdate):
  Use self.verbose.
(DB.availableReleases):
  New method to get a least of releases in the database.
(DB._updateVersions):
  Calculate a linear order of versions.  This will be used to speed up
  the vulnerability rating process.
(DB.calculateVulnerabilities):
  Invoke _updateVersions.  Use self.verbose.

bin/update-vulnerabilities, bin/update-packages:
  Set database verbose flag.
1 # security_db.py -- simple, CVE-driven Debian security bugs database
2 # Copyright (C) 2005 Florian Weimer <fw@deneb.enyo.de>
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18 """This module implements a small database for tracking security bugs.
19
20 Note that the database is always secondary to the text files. The
21 database is only an implementation tool, and not used for maintaining
22 the data.
23
24 The data is kept in a SQLite 3 database.
25
26 FIXME: Document the database schema once it is finished.
27 """
28
29 import apsw
30 import bugs
31 import debian_support
32 import os
33 import re
34 import sys
35 import types
36
37 class InsertError(Exception):
38 """Class for capturing insert errors.
39
40 The 'errors' member collects all error messages.
41 """
42
43 def __init__(self, errors):
44 assert len(errors) > 0, errors
45 assert type(errors) == types.ListType, errors
46 assert type(errors[0])== types.StringType, errors
47 self.errors = errors
48
49 def __str__(self):
50 return self.errors[0] + ' [more...]'
51
52 class DB:
53 """Access to the security database.
54
55 This is a wrapper around an SQLite database object (which is
56 accessible as the "db" member.
57
58 Most operations need a special cursor object, which can be created
59 with a cursor object. The name "cursor" is somewhat of a
60 misnomer because these objects are quite versatile.
61 """
62
63 def __init__(self, name, verbose=False):
64 self.db = apsw.Connection(name)
65 self.verbose = verbose
66
67 def cursor(self):
68 """Creates a new database cursor.
69
70 Also see the writeTxn method."""
71 return self.db.cursor()
72
73 def writeTxn(self):
74 """Creates a cursor for an exclusive transaction.
75
76 No other process may modify the database at the same time.
77 After finishing the work, you should invoke the commit or
78 rollback methods below.
79 """
80 c = self.cursor()
81 c.execute("BEGIN TRANSACTION EXCLUSIVE")
82 return c
83
84 def commit(self, cursor):
85 """Makes the changes in the transaction permanent."""
86 cursor.execute("COMMIT")
87
88 def rollback(self, cursor):
89 """Undos the changes in the transaction."""
90 cursor.execute("ROLLBACK")
91
92 def initSchema(self):
93 """Creates the database schema."""
94 cursor = self.cursor()
95
96 cursor.execute("""CREATE TABLE inodeprints
97 (file TEXT NOT NULL PRIMARY KEY,
98 inodeprint TEXT NOT NULL)""")
99
100 cursor.execute("""CREATE TABLE version_linear_order
101 (id INTEGER NOT NULL PRIMARY KEY,
102 version TEXT NOT NULL UNIQUE)""")
103
104 cursor.execute("""CREATE TABLE source_packages
105 (package TEXT NOT NULL,
106 release TEXT NOT NULL, archive TEXT NOT NULL,
107 version TEXT NOT NULL,
108 version_id INTEGER NOT NULL DEFAULT 0,
109 PRIMARY KEY (package, release, archive));""")
110
111 cursor.execute("""CREATE TABLE binary_packages
112 (package TEXT NOT NULL,
113 release TEXT NOT NULL, archive TEXT NOT NULL,
114 architecture TEXT NOT NULL,
115 version TEXT NOT NULL,
116 version_id INTEGER NOT NULL DEFAULT 0,
117 source TEXT NOT NULL, source_version TEXT NOT NULL,
118 PRIMARY KEY (package, release, archive, architecture));""")
119 cursor.execute("""CREATE INDEX binary_packages_source
120 ON binary_packages(source)""")
121
122 cursor.execute("""CREATE TABLE package_notes
123 (id INTEGER NOT NULL PRIMARY KEY,
124 bug_name TEXT NOT NULL,
125 package TEXT NOT NULL,
126 fixed_version TEXT
127 CHECK (fixed_version IS NULL OR fixed_version <> ''),
128 fixed_version_id INTEGER NOT NULL DEFAULT 0,
129 release TEXT NOT NULL,
130 urgency TEXT NOT NULL)""")
131
132 cursor.execute("""CREATE TABLE debian_bugs
133 (bug INTEGER NOT NULL,
134 note INTEGER NOT NULL,
135 PRIMARY KEY (bug, note))""")
136
137 cursor.execute("""CREATE TABLE bugs
138 (name TEXT NOT NULL PRIMARY KEY,
139 cve_status TEXT NOT NULL
140 CHECK (cve_status IN
141 ('', 'CANDIDATE', 'ASSIGNED', 'RESERVED', 'REJECTED')),
142 not_for_us INTEGER NOT NULL CHECK (not_for_us IN (0, 1)),
143 description TEXT NOT NULL,
144 source_file TEXT NOT NULL,
145 source_line INTEGER NOT NULL)""")
146
147 cursor.execute("""CREATE TABLE bugs_notes
148 (bug_name TEXT NOT NULL CHECK (typ <> ''),
149 typ TEXT NOT NULL CHECK (typ IN ('TODO', 'NOTE')),
150 release TEXT NOT NULL DEFAULT '',
151 comment TEXT NOT NULL CHECK (comment <> ''))""")
152
153 cursor.execute("""CREATE TABLE bugs_xref
154 (source TEXT NOT NULL,
155 target TEXT NOT NULL,
156 normalized_target TEXT NOT NULL DEFAULT '',
157 PRIMARY KEY (source, target))""")
158
159 cursor.execute("""CREATE TABLE bugs_status
160 (bug_name TEXT NOT NULL,
161 release TEXT NOT NULL,
162 note INTEGER NOT NULL,
163 reason TEXT NOT NULL,
164 PRIMARY KEY (bug_name, release, note))""")
165
166 def updateSources(self, cursor, release, archive, packages):
167 """Reads a Sources file and adds it to the database.
168
169 Old records for the same release/archive pair are removed.
170
171 cursor - cursor used to update the database
172 release - Debian release (e.g. sarge)
173 archive - fork of a release (e.g. security)
174 packages - debian_support.PackageFile object with source packages
175 """
176
177 cursor.execute('DELETE FROM source_packages '
178 + 'WHERE release = ? AND archive = ?',
179 (release, archive))
180
181 for pkg in packages:
182 pkg_name = None
183 pkg_version = None
184 for (name, contents) in pkg:
185 if name == "Package":
186 pkg_name = contents
187 elif name == "Version":
188 pkg_version = debian_support.Version(contents)
189 if pkg_name is None:
190 raise SyntaxError\
191 ("package record does not contain package name")
192 if pkg_version is None:
193 raise SyntaxError\
194 ("package record for %s does not contain version"
195 % pkg_name)
196 cursor.execute('INSERT INTO source_packages '
197 + '(package, release, archive, version) '
198 + 'VALUES (?, ?, ?, ?)',
199 (pkg_name, release, archive, str(pkg_version)))
200
201 def updatePackages(self, cursor,
202 release, archive, architecture,
203 packages):
204 """Reads a Packages file and adds it to the database.
205
206 Old records for the same release/archive/architecture
207 triple are removed.
208
209 cursor - cursor used to update the database
210 release - Debian release (e.g. sarge)
211 archive - fork of a release (e.g. security)
212 architecture - architecture of binary packages (e.g. i386)
213 packages - debian_support.PackageFile object with binary packages
214 """
215
216 re_source = re.compile\
217 (r'^([a-zA-Z0-9.+-]+)(?:\s+\(([a-zA-Z0-9.+:-]+)\))?$')
218
219 cursor.execute('DELETE FROM binary_packages '
220 + 'WHERE release = ? AND archive = ? AND architecture = ?',
221 (release, archive, architecture))
222
223
224 for pkg in packages:
225 pkg_name = None
226 pkg_version = None
227 pkg_source = None
228 pkg_source_version = None
229 for (name, contents) in pkg:
230 if name == "Package":
231 pkg_name = contents
232 elif name == "Version":
233 pkg_version = debian_support.Version(contents)
234 elif name == "Source":
235 match = re_source.match(contents)
236 if match is None:
237 raise SyntaxError(('binary package %s references '
238 + 'invalid source package %s') %
239 (pkg_name, `contents`))
240 (pkg_source, pkg_source_version) = match.groups()
241
242 if pkg_name is None:
243 raise SyntaxError\
244 ("binary package record does not contain package name")
245 if pkg_version is None:
246 raise SyntaxError\
247 ("binary record for %s does not contain version"
248 % pkg_name)
249 if pkg_source is None:
250 pkg_source = pkg_name
251 if pkg_source_version is None:
252 pkg_source_version = pkg_version
253
254 cursor.execute('INSERT INTO binary_packages '
255 + '(package, release, archive, architecture,'
256 + 'version, source, source_version) '
257 + 'VALUES (?, ?, ?, ?, ?, ?, ?)',
258 (pkg_name, release, archive, architecture,
259 str(pkg_version),
260 pkg_source, str(pkg_source_version)))
261
262 def filePrint(self, filename):
263 """Returns a fingerprint string for filename."""
264
265 st = os.stat(filename)
266 # The "1" is a version number which can be used to trigger a
267 # re-read if the code has changed in an incompatible way.
268 return `(st.st_size, st.st_ino, st.st_mtime, 1)`
269
270 def _maybeUpdate(self, cursor, args, filename, action):
271 """Internal routine used for conditional update."""
272
273 current_print = self.filePrint(filename)
274
275 for (old_print,) in cursor.execute\
276 ("SELECT inodeprint FROM inodeprints WHERE file = ?", (filename,)):
277 if old_print == current_print:
278 return
279 if self.verbose:
280 print "maybeUpdate: updating", `args`
281 result = apply(action, (cursor,) + args
282 + (debian_support.PackageFile(filename),))
283 cursor.execute("""UPDATE inodeprints SET inodeprint = ?
284 WHERE file = ?""", (current_print, filename))
285 return result
286
287 # No inodeprints entry, load file and add one.
288 result = apply(action, (cursor,) + args
289 + (debian_support.PackageFile(filename),))
290 cursor.execute("""INSERT INTO inodeprints (file, inodeprint)
291 VALUES (?, ?)""", (filename, current_print))
292 return result
293
294
295 def maybeUpdateSources(self, cursor, release, archive, filename):
296 """Reads the Sources file filename if it has been modified."""
297 self._maybeUpdate(cursor, (release, archive), filename,
298 self.updateSources)
299
300 def maybeUpdatePackages(self, cursor, release, archive, arch, filename):
301 """Reads the Packages file filename if it has been modified."""
302 self._maybeUpdate(cursor, (release, archive, arch), filename,
303 self.updatePackages)
304
305 def deleteBugs(self, cursor):
306 """Deletes all record bug reports from the database."""
307 cursor.execute("DELETE FROM package_notes")
308 cursor.execute("DELETE FROM debian_bugs")
309 cursor.execute("DELETE FROM bugs")
310 cursor.execute("DELETE FROM bugs_notes")
311 cursor.execute("DELETE FROM bugs_xref")
312
313 def insertBugs(self, cursor, source):
314 """Reads the CAN/CVE/DSA/DTSA file and writes them to the database."""
315
316 errors = []
317 for bug in source:
318 try:
319 bug.writeDB(cursor)
320 except ValueError, e:
321 errors.append("%s: %d: error: %s"
322 % (bug.source_file, bug.source_line, e))
323 if errors:
324 raise InsertError(errors)
325
326 def finishBugs(self, cursor):
327 """After inserting new bugs, update cross-references.
328
329 Returns a list of warning messages."""
330
331 warnings = []
332
333 # Check that there are no CAN/CVE collisions.
334
335 for b1, b2 in list(cursor.execute\
336 ("""SELECT b1.name, b2.name FROM bugs AS b1, bugs AS b2
337 WHERE b1.name LIKE 'CVE-%'
338 AND b2.name = 'CAN-' || substr(b1.name, 5, 9)""")):
339 b1 = bugs.BugFromDB(cursor, b1)
340 b2 = bugs.BugFromDB(cursor, b2)
341
342 warnings.append("%s:%d: duplicate CVE entries %s and %s"
343 % (b1.source_file, b1.source_line,
344 b1.name, b2.name))
345 warnings.append("%s:%d: location of %s"
346 % (b1.source_file, b1.source_line, b1.name))
347 warnings.append("%s:%d: location of %s"
348 % (b2.source_file, b2.source_line, b2.name))
349
350 # Normalize the CAN/CVE references to the entry which is
351 # actually in the database. After the CAN -> CVE transition,
352 # this can go away (but we should check that the
353 # cross-references are valid).
354
355 for source, target in list(cursor.execute\
356 ("""SELECT source, target FROM bugs_xref
357 WHERE normalized_target = ''""")):
358 if bugs.BugBase.re_cve_name.match(target):
359 can_target = 'CAN-' + target[4:]
360 cve_target = 'CVE-' + target[4:]
361
362 found = False
363 for (t,) in list(cursor.execute("""SELECT name FROM bugs
364 WHERE name IN (?, ?)""", (can_target, cve_target))):
365 cursor.execute("""UPDATE bugs_xref
366 SET normalized_target = ?
367 WHERE source = ? AND target = ?""",
368 (t, source, target))
369 found = True
370 break
371 if not found:
372 b = bugs.BugFromDB(cursor, source)
373 warnings.append\
374 ("%s: %d: reference to unknwown CVE entry %s"
375 % (b.source_file, b.source_line, target))
376
377 # Check that the DSA/DTSA references are valid.
378
379 for source, target in list(cursor.execute
380 ("""SELECT source, target FROM bugs_xref
381 WHERE target LIKE 'DSA%' OR target LIKE 'DTSA%'""")):
382 found = False
383 for (b,) in cursor.execute("SELECT name FROM bugs WHERE name = ?",
384 (target,)):
385 found = True
386 if not found:
387 b = bugs.BugFromDB(cursor, source)
388 warnings.append\
389 ("%s: %d: reference to unknwown advisory %s"
390 % (b.source_file, b.source_line, target))
391
392 return warnings
393
394 def availableReleases(self, cursor=None):
395 """Returns a list of tuples (RELEASE, ARCHIVE, ARCHITECTURE-LIST)."""
396 if cursor is None:
397 cursor = self.cursor()
398
399 releases = {}
400 for r in cursor.execute(
401 "SELECT DISTINCT release, archive FROM source_packages"):
402 releases[r] = ['(sources)']
403
404 for (rel, archive, arch) in cursor.execute(
405 """SELECT DISTINCT release, archive, architecture
406 FROM binary_packages"""):
407 try:
408 releases[(rel, archive)].append(arch)
409 except KeyError:
410 releases[(rel, archive)] = [arch]
411
412 result = []
413 for ((rel, archive), archs) in releases.items():
414 archs.sort()
415 result.append((rel, archive, archs))
416 result.sort()
417
418 return result
419
420 def getVersion(self, cursor, release, package):
421 """Returns the version number for package in release.
422
423 Package can be a source or binary package. Binary package
424 versions take precedence.
425
426 Security updates etc. are not considered."""
427
428 versions = list(cursor.execute(
429 """SELECT version FROM binary_packages
430 WHERE package = ? AND release = ?""", (package, release)))
431 if versions:
432 return min(map(lambda (v,): debian_support.Version(v), versions))
433
434 versions = list(cursor.execute(
435 """SELECT version FROM source_packages
436 WHERE package = ? AND release = ?""", (package, release)))
437 if versions:
438 assert len(versions) == 1
439 return debian_support.Version(versions[0][0])
440
441 return None
442
443 def releaseContainsPackage(self, cursor, release, package):
444 """Returns True if the source or binary package exists in release."""
445 for (c,) in cursor.execute(
446 """SELECT version FROM binary_packages
447 WHERE package = ? AND release = ?""", (package, release)):
448 return True
449 for (c,) in cursor.execute(
450 """SELECT version FROM source_packages
451 WHERE package = ? AND release = ?""", (package, release)):
452 return True
453 return False
454
455 def _updateVersions(self, cursor):
456 """Updates the linear version table."""
457
458 cursor.execute("DELETE FROM version_linear_order");
459
460 if self.verbose:
461 print "updateVersions:"
462 print " reading"
463
464 versions = []
465 for (v,) in cursor.execute(
466 """SELECT DISTINCT *
467 FROM (SELECT fixed_version FROM package_notes
468 WHERE fixed_version IS NOT NULL
469 UNION ALL SELECT version FROM source_packages
470 UNION ALL SELECT version FROM binary_packages)"""):
471 if v is None:
472 continue
473 versions.append(debian_support.Version(v))
474
475 if self.verbose:
476 print " calculating linear oder"
477 versions.sort()
478
479 if self.verbose:
480 print " storing linear order"
481 for v in versions:
482 cursor.execute(
483 "INSERT INTO version_linear_order (version) VALUES (?)",
484 (str(v),))
485
486 if self.verbose:
487 print " updating package notes"
488 cursor.execute(
489 """UPDATE package_notes
490 SET fixed_version_id = (SELECT id FROM version_linear_order
491 WHERE version = package_notes.fixed_version)
492 WHERE fixed_version IS NOT NULL""")
493
494 if self.verbose:
495 print " updating source packages"
496 cursor.execute(
497 """UPDATE source_packages
498 SET version_id = (SELECT id FROM version_linear_order
499 WHERE version = source_packages.version)""")
500
501 if self.verbose:
502 print " updating binary packages"
503 cursor.execute(
504 """UPDATE binary_packages
505 SET version_id = (SELECT id FROM version_linear_order
506 WHERE version = binary_packages.version)""")
507
508 if self.verbose:
509 print " finished"
510
511 def calculateVulnerabilities(self, cursor):
512 """Calculate vulnerable packages.
513
514 To each package note, a release-specific vulnerability status
515 is attached. Currently, only etch/testing is processed.
516 """
517
518 self._updateVersions(cursor)
519
520 if self.verbose:
521 print "calculateVulnerabilities:"
522 print " clearing old data"
523 cursor.execute("DELETE FROM bugs_status")
524
525 def markVulnerable(bug, release, note, reason):
526 cursor.execute("""INSERT INTO bugs_status
527 (bug_name, release, note, reason) VALUES (?, ?, ?, ?)""",
528 (bug.name, release, note, reason))
529
530 def calcVuln(bug):
531 vulnerable = False
532 note_found = False
533
534 for n in bug.notes:
535 # ignore all notes conditioned on releases.
536 if n.release is not None: # assumes 'etch'
537 continue
538 note_found = True
539 v = self.getVersion(cursor, 'etch', n.package)
540 if v is None:
541 # Package is not in testing, go on.
542 continue
543 if n.affects(v):
544 vulnerable = True
545 markVulnerable(b, 'etch', n.id,
546 "%s (%s) is vulnerable, %s"
547 % (n.package, v, n.fixedVersion()))
548
549 if bug.hasTODO():
550 vulnerable = True
551 markVulnerable(b, 'etch', 0, 'TODO items present')
552 elif not note_found:
553 # We found no matching note. Maybe all packages have
554 # been removed?
555 if bug.notes:
556 for n in bug.notes:
557 if self.releaseContainsPackage \
558 (cursor, 'etch', n.package):
559 markVulnerable(b, 'etch', 0,
560 'applicable package note for %s missing'
561 % n.package)
562 vulnerable = True
563 else:
564 vulnerable = True
565 markVulnerable(b, 'etch', 0, 'status is unclear')
566
567 return vulnerable
568
569 # First handle the DSAs. Cache results in DSA_status (used
570 # for CAN/CVE below).
571
572 if self.verbose:
573 print " reading DSAs"
574 bug_names = list(cursor.execute(
575 """SELECT name FROM bugs
576 WHERE name LIKE 'DSA-%' AND NOT not_for_us"""))
577 DSA_status = {}
578 if self.verbose:
579 print " rating DSAs"
580 for (bug_name,) in bug_names:
581 b = bugs.BugFromDB(cursor, bug_name)
582 DSA_status[bug_name] = calcVuln(b)
583
584 # Process the CAN/CVE/FAKE entries. If an entry has no
585 # package annotations, but it references a non-vulnerable DSA,
586 # we assume that the current is not affect either.
587
588 if self.verbose:
589 print " reading other entries"
590 bug_names = list(cursor.execute(
591 """SELECT name FROM bugs
592 WHERE (NOT not_for_us)
593 AND NOT (name LIKE 'DSA-%' OR name LIKE 'DTSA-%')"""))
594 if self.verbose:
595 print " rating other entries"
596 for (bug_name,) in bug_names:
597 b = bugs.BugFromDB(cursor, bug_name)
598 if b.notes:
599 calcVuln(b)
600 continue
601
602 if b.hasTODO():
603 markVulnerable(b, 'etch', 0, 'TODO items present')
604 continue
605
606 dsa_found = False
607 for x in b.xref:
608 if x[0:4] == 'DSA-':
609 dsa_found = True
610 if DSA_status[x]:
611 markVulnerable(b, 'etch', 0,
612 'vulnerability %s referenced' % x)
613 break
614 if not dsa_found:
615 markVulnerable(b, 'etch', 0, 'status is unclear')
616
617 if self.verbose:
618 print " finished"
619
620 def check(self, cursor=None):
621 """Runs a simple consistency check and prints the results."""
622
623 if cursor is None:
624 cursor = self.cursor()
625
626 for (package, release, archive, architecture, source) in\
627 cursor.execute(
628 """SELECT package, release, archive, architecture, source
629 FROM binary_packages
630 WHERE NOT EXISTS
631 (SELECT *
632 FROM source_packages AS sp
633 WHERE sp.package = binary_packages.source
634 AND sp.release = binary_packages.release
635 AND sp.archive = binary_packages.archive)
636 """):
637 print "error: binary package without source package"
638 print " binary package:", package
639 print " release:", release
640 if archive:
641 print " archive:", archive
642 print " architecture:", architecture
643 print " missing source package:", source
644
645 for (package, release, archive, architecture, version,
646 source, source_version) \
647 in cursor.execute("""SELECT binary_packages.package,
648 binary_packages.release, binary_packages.archive,
649 binary_packages.architecture,binary_packages.version,
650 sp.package, sp.version
651 FROM binary_packages, source_packages AS sp
652 WHERE sp.package = binary_packages.source
653 AND sp.release = binary_packages.release
654 AND sp.archive = binary_packages.archive
655 AND sp.version <> binary_packages.source_version"""):
656 relation = cmp(debian_support.Version(version),
657 debian_support.Version(source_version))
658 assert relation <> 0
659 if relation <= 0:
660 print "error: binary package is older than source package"
661 else:
662 print "warning: binary package is newer than source package"
663 print " binary package: %s (%s)" % (package, version)
664 print " source package: %s (%s)" % (source, source_version)
665 print " release:", release
666 if archive:
667 print " archive:", archive
668 print " architecture:", architecture
669
670 def test():
671 import os
672
673 if os.path.exists('test_security.db'):
674 os.unlink('test_security.db')
675 db = DB('test_security.db')
676 db.initSchema()
677
678 data_prefix = '../../data/packages/'
679 cursor = db.writeTxn()
680 db.updateSources(cursor, 'sarge', 'main',
681 debian_support.PackageFile(data_prefix + 'sarge_main_Sources'))
682 db.updatePackages(cursor, 'sarge', 'main', 'i386',
683 debian_support.PackageFile(data_prefix
684 + 'sarge_main_i386_Packages'))
685 db.updatePackages(cursor, 'sarge', 'main', 'ia64',
686 debian_support.PackageFile(data_prefix
687 + 'sarge_main_ia64_Packages'))
688 db.commit(cursor)
689
690 assert str(db.getVersion(cursor, 'sarge', 'ale')) == '0.7.1-1', \
691 db.getVersion(cursor, 'sarge', 'ale')
692
693 # db.check(cursor)
694
695 cursor = db.writeTxn()
696 db.deleteBugs(cursor)
697 db.insertBugs(cursor, bugs.CVEFile('../../data/CAN/list'))
698 db.insertBugs(cursor, bugs.CVEFile('../../data/CVE/list',
699 no_version_needs_note=False))
700 db.insertBugs(cursor, bugs.DSAFile('../../data/DSA/list'))
701 db.insertBugs(cursor, bugs.DTSAFile('../../data/DTSA/list'))
702 db.finishBugs(cursor)
703 db.commit(cursor)
704
705 b = bugs.BugFromDB(cursor, 'CAN-2005-2491')
706 assert b.name == 'CAN-2005-2491', b.name
707 assert b.description == 'Integer overflow in pcre_compile.c in Perl Compatible Regular ...', b.description
708 assert len(b.xref) == 2, b.xref
709 assert not b.not_for_us
710 assert 'DSA-800-1' in b.xref, b.xref
711 assert 'DTSA-10-1' in b.xref, b.xref
712 assert tuple(b.comments) == (('NOTE', 'gnumeric/goffice includes one as well; according to upstream not exploitable in gnumeric,'),
713 ('NOTE', 'new copy will be included any way')),\
714 b.comments
715
716 assert len(b.notes) == 4, len(b.notes)
717
718 for n in b.notes:
719 assert n.release is None
720 if n.package == 'pcre3':
721 assert n.fixed_version == debian_support.Version('6.3-0.1etch1')
722 assert tuple(n.bugs) == (324531,), n.bugs
723 assert n.urgency == bugs.internUrgency('medium')
724 elif n.package == 'python2.1':
725 assert n.fixed_version == debian_support.Version('2.1.3dfsg-3')
726 assert len(n.bugs) == 0, n.bugs
727 assert n.urgency == bugs.internUrgency('medium')
728 elif n.package == 'python2.2':
729 assert n.fixed_version == debian_support.Version('2.2.3dfsg-4')
730 assert len(n.bugs) == 0, n.bugs
731 assert n.urgency == bugs.internUrgency('medium')
732 elif n.package == 'python2.3':
733 assert n.fixed_version == debian_support.Version('2.3.5-8')
734 assert len(n.bugs) == 0, n.bugs
735 assert n.urgency == bugs.internUrgency('medium')
736 else:
737 assert False
738
739 assert bugs.BugFromDB(cursor, 'DSA-311').isKernelOnly()
740
741 if __name__ == "__main__":
742 test()

  ViewVC Help
Powered by ViewVC 1.1.5