/[secure-testing]/bin/tracker_service.py
ViewVC logotype

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3079 - (show annotations) (download) (as text)
Sat Dec 17 11:57:44 2005 UTC (7 years, 5 months ago) by fw
File MIME type: text/script
File size: 42337 byte(s)
bin/tracker_service.py (TrackerService.page_bug):
  Make header more compact.
1 #!/usr/bin/python
2
3 import sys
4 sys.path.insert(0,'../lib/python')
5
6 if len(sys.argv) <> 3:
7 print "usage: python tracker_serivce.py SOCKET-PATH DATABASE-PATH"
8 sys.exit(1)
9 socket_name = sys.argv[1]
10 db_name = sys.argv[2]
11
12 import bugs
13 import re
14 import security_db
15 from web_support import *
16
17 class BugFilter:
18 def __init__(self, params):
19 self.hide_medium_urgency = int(params.get('hide_medium_urgency',
20 (0,))[0])
21 self.hide_non_remote = int(params.get('hide_non_remote',
22 (0,))[0])
23
24 def actions(self, url):
25 """Returns a HTML snippet which can be used to change the filter."""
26 if self.hide_medium_urgency:
27 urg = A(url.updateParams(hide_medium_urgency=None),
28 'Show lower urgencies')
29 else:
30 urg = A(url.updateParams(hide_medium_urgency='1'),
31 'Hide lower urgencies')
32 if self.hide_non_remote:
33 rem = A(url.updateParams(hide_non_remote=None),
34 'Show local vulnerabilities')
35 else:
36 rem = A(url.updateParams(hide_non_remote='1'),
37 'Hide local vulnerabilities')
38 return P(urg, ' ', rem)
39
40 def urgencyFiltered(self, urg):
41 """Returns True if the urgency urg is filtered."""
42 return self.hide_medium_urgency and urg not in ("high", "unknown", "")
43
44 def remoteFiltered(self, remote):
45 """Returns True if the attack range is filtered."""
46 return remote is not None and self.hide_non_remote and not remote
47
48 class TrackerService(WebService):
49 head_contents = compose(STYLE(
50 """h1 { font-size : 144%; }
51 h2 { font-size : 120%; }
52 h3 { font-size : 100%; }
53
54 table { padding-left : 1.5em }
55 td, th { text-align : left;
56 padding-left : 0.25em;
57 padding-right : 0.25em; }
58 td { vertical-align: baseline }
59 span.red { color: red; }
60 span.dangerous { color: rgb(191,127,0); }
61 """), SCRIPT('''var old_query_value = "";
62
63 function selectSearch() {
64 document.searchForm.query.focus();
65 }
66
67 function onSearch(query) {
68 if (old_query_value == "") {
69 if (query.length > 5) {
70 old_query_value = query;
71 document.searchForm.submit();
72 } else {
73 old_query_value = query;
74 }
75 }
76 }
77 ''')).toHTML()
78
79 def __init__(self, socket_name, db_name):
80 WebService.__init__(self, socket_name)
81 self.db = security_db.DB(db_name)
82 self.register('', self.page_home)
83 self.register('*', self.page_object)
84 self.register('redirect/*', self.page_redirect)
85 self.register('source-package/*', self.page_source_package)
86 self.register('binary-package/*', self.page_binary_package)
87 self.register('status/release/oldstable',
88 self.page_status_release_oldstable)
89 self.register('status/release/stable', self.page_status_release_stable)
90 self.register('status/release/testing',
91 self.page_status_release_testing)
92 self.register('status/release/unstable',
93 self.page_status_release_unstable)
94 self.register('status/dtsa-candidates',
95 self.page_status_dtsa_candidates)
96 self.register('status/todo', self.page_status_todo)
97 self.register('status/itp', self.page_status_itp)
98 self.register('data/unknown-packages', self.page_data_unknown_packages)
99 self.register('data/missing-epochs', self.page_data_missing_epochs)
100 self.register('data/releases', self.page_data_releases)
101 self.register('data/funny-versions', self.page_data_funny_versions)
102 self.register('data/fake-names', self.page_data_fake_names)
103 self.register('debsecan/**', self.page_debsecan)
104
105 def page_home(self, path, params, url):
106 query = params.get('query', ('',))[0]
107 if query:
108 if '/' in query:
109 return self.page_not_found(url, query)
110 else:
111 return RedirectResult(url.scriptRelativeFull(query))
112
113 return self.create_page(
114 url, 'Security Bug Tracker',
115 [P(
116 """This is the experimental issue tracker for Debian's testing
117 security team. Keep in mind that this is merely a prototype.
118 Please report any problems to """,
119 A("mailto:fw@deneb.enyo.de", "Florian Weimer"),
120 """.Note that some of the data presented here is known
121 to be wrong (see below), but the data for the testing suite
122 should be fine."""),
123 make_menu(
124 url.scriptRelative,
125 ('status/release/unstable',
126 'Vulnerable packages in the unstable suite'),
127 ('status/release/testing',
128 'Vulnerable packages in the testing suite'),
129 ('status/release/stable',
130 'Vulnerable packages in the stable suite'),
131 ('status/release/oldstable',
132 'Vulnerable packages in the oldstable suite'),
133 ('status/dtsa-candidates', "Candidates for DTSAs"),
134 ('status/todo', 'TODO items'),
135 ('status/itp', 'ITPs with potential security issues'),
136 ('data/unknown-packages',
137 'Packages names not found in the archive'),
138 ('data/fake-names', 'Tracked issues without a CVE name'),
139 ('data/missing-epochs',
140 'Package versions which might lack an epoch'),
141 ('data/funny-versions',
142 'Packages with strange version numbers'),
143 ('data/releases',
144 'Covered Debian releases and architectures (slow)'),
145 self.make_search_button(url)),
146 P("""(You can enter CVE names, Debian bug numbers and package
147 names in the search forms.)"""),
148
149 H2("Data sources"),
150 P("""Data in this tracker comes solely from the bug database
151 which is maintained by Debian's testing security team in their
152 Subversion repository. All external data (this includes
153 Debian bug reports and official Debian security advisories)
154 must be added to this database before it appears here, and there
155 can be some delay before this happens."""),
156 P("""At the moment, the database only contains information which is
157 relevant for tracking the security status of the stable, testing and
158 unstable suites. This means that data for oldstable is likely wrong."""),
159 P('Data marked "NVD" comes from the ',
160 A(url.absolute('http://nvd.nist.gov/'),
161 'National Vulnerability Database'),
162 ' maintained by NIST.'),
163
164 H2("External interfaces"),
165 P("""If you want to automatically open a relevant web page for
166 some object, use the """,
167 CODE(str(url.scriptRelative("redirect/")), EM("object")),
168 """ URL. If no information is contained in this database,
169 the browser is automatically redirected to the corresponding external
170 data source.""")],
171 search_in_page=True)
172
173 def page_object(self, path, params, url):
174 obj = path[0]
175 return self.page_object_or_redirect(url, obj, False)
176
177 def page_redirect(self, path, params, url):
178 obj = path[0]
179 return self.page_object_or_redirect(url, obj, True)
180
181 def page_object_or_redirect(self, url, obj, redirect):
182 c = self.db.cursor()
183
184 if not obj:
185 # Redirect to start page.
186 return RedirectResult(url.scriptRelativeFull(""))
187
188 if 'A' <= obj[0] <= 'Z':
189 # Bug names start with a capital letter.
190 return self.page_bug(url, obj, redirect)
191
192 bugnumber = 0
193 try:
194 bugnumber = int(obj)
195 except ValueError:
196 pass
197 if bugnumber:
198 buglist = list(self.db.getBugsFromDebianBug(c, bugnumber))
199 if buglist:
200 return self.page_debian_bug(url, bugnumber, buglist)
201 if redirect:
202 return RedirectResult(self.url_debian_bug(url, str(bugnumber)),
203 permanent=False)
204
205 if self.db.isSourcePackage(c, obj):
206 return RedirectResult(self.url_source_package(url, obj, full=True))
207 if self.db.isBinaryPackage(c, obj):
208 return RedirectResult(self.url_binary_package(url ,obj, full=True))
209
210 return self.page_not_found(url, obj)
211
212 def page_bug(self, url, name, redirect):
213 # FIXME: Normalize CAN-* to CVE-* when redirecting. Too many
214 # people still use CAN.
215 if redirect and name[0:4] == 'CAN-':
216 name = 'CVE-' + name[4:]
217
218 cursor = self.db.cursor()
219 try:
220 bug = bugs.BugFromDB(cursor, name)
221 except ValueError:
222 if redirect:
223 if name[0:4] == 'CVE-':
224 return RedirectResult(self.url_cve(url, name),
225 permanent=False)
226 return self.page_not_found(url, name)
227 if bug.name <> name or redirect:
228 # Show the normalized bug name in the browser address bar.
229 return RedirectResult(url.scriptRelativeFull(bug.name))
230
231 page = []
232
233 def gen_header():
234 yield B("Name"), bug.name
235
236 source = bug.name.split('-')[0]
237 if source == 'CVE':
238 source_xref = compose(self.make_cve_ref(url, bug.name, 'CVE'),
239 " (",
240 self.make_nvd_ref(url, bug.name,
241 'in NVD'),
242 ")")
243 elif source == 'DSA':
244 source_xref = self.make_dsa_ref(url, bug.name, 'Debian')
245 elif source == 'DTSA':
246 source_xref = 'Debian Testing Security Team'
247 elif source == 'FAKE':
248 source_xref = (
249 'Automatically generated temporary name. Not for external reference.')
250 else:
251 source_xref = None
252
253 if source_xref:
254 yield B("Source"), source_xref
255
256 nvd = self.db.getNVD(cursor, bug.name)
257
258 if nvd and nvd.cve_desc:
259 yield B("Description"), nvd.cve_desc
260 elif bug.description:
261 yield B("Description"), bug.description
262
263 xref = list(self.db.getBugXrefs(cursor, bug.name))
264 if xref:
265 yield B("References"), self.make_xref_list(url, xref)
266
267 if nvd:
268 nvd_range = nvd.rangeString()
269 if nvd.severity:
270 nvd_severity = nvd.severity.lower()
271 if nvd_range:
272 nvd_severity = "%s (attack range: %s)" \
273 % (nvd_severity, nvd_range)
274 yield B("NVD severity"), nvd_severity
275
276 debian_bugs = bug.getDebianBugs(cursor)
277 if debian_bugs:
278 yield (B("Debian Bugs"),
279 self.make_debian_bug_list(url, debian_bugs))
280
281 if not bug.not_for_us:
282 for (release, status, reason) in bug.getStatus(cursor):
283 if status <> 'fixed':
284 reason = self.make_red(reason)
285 yield B('%s status' % release), reason
286
287 page.append(make_table(gen_header()))
288
289 if bug.notes:
290 page.append(H2("Vulnerable and fixed packages"))
291
292 def gen_source():
293 old_pkg = ''
294 for (package, release, version, vulnerable) \
295 in self.db.getSourcePackages(cursor, bug.name):
296 if package == old_pkg:
297 package = ''
298 else:
299 old_pkg = package
300 package = compose(
301 self.make_source_package_ref(url, package),
302 " (", self.make_pts_ref(url, package, 'PTS'), ")")
303 if vulnerable:
304 vuln = self.make_red('vulnerable')
305 version = self.make_red(version)
306 else:
307 vuln = 'fixed'
308
309 yield package, ', '.join(release), version, vuln
310
311 page.append(make_table(gen_source(),
312 caption=("Source Package", "Release", "Version", "Status"),
313 introduction=P('The table below lists information on source packages.')))
314
315 def gen_binary():
316 old_pkg = ''
317 for (packages, releases, version, archs, vulnerable) \
318 in self.db.getBinaryPackages(cursor, bug.name):
319 pkg = ', '.join(packages)
320 if pkg == old_pkg:
321 packages = ''
322 else:
323 old_pkg = pkg
324 packages = self.make_binary_packages_ref(url, packages)
325
326 if vulnerable:
327 vuln = self.make_red('vulnerable')
328 version = self.make_red(version)
329 else:
330 vuln = 'fixed'
331 yield (packages,
332 ', '.join(releases),
333 version, vuln,
334 ', '.join(archs))
335
336 page.append(make_table(gen_binary(),
337 caption=("Binary Package", "Release", "Version", "Status",
338 "Architecures"),
339 introduction=P("The next table lists affected binary packages.")))
340
341 def gen_data():
342 notes_sorted = bug.notes[:]
343 notes_sorted.sort(lambda a, b: cmp(a.package, b.package))
344 for n in notes_sorted:
345 if n.release:
346 rel = str(n.release)
347 else:
348 rel = '(unstable)'
349 urgency = str(n.urgency)
350 if n.fixed_version:
351 ver = str(n.fixed_version)
352 if ver == '0':
353 ver = '(not affected)'
354 urgency = ''
355 else:
356 ver = self.make_red('(unfixed)')
357
358 pkg = n.package
359 pkg_kind = n.package_kind
360 if pkg_kind == 'source':
361 pkg = self.make_source_package_ref(url, pkg)
362 elif pkg_kind == 'binary':
363 pkg = self.make_binary_package_ref(url, pkg)
364 elif pkg_kind == 'itp':
365 pkg_kind = 'ITP'
366 rel = ''
367 ver = ''
368 urgency = ''
369
370 bugs = n.bugs
371 bugs.sort()
372 bugs = make_list(
373 map(lambda x: self.make_debian_bug(url, x), bugs))
374 if n.bug_origin:
375 origin = self.make_xref(url, n.bug_origin)
376 else:
377 origin = ''
378 yield (pkg, pkg_kind, rel, ver, urgency, origin, bugs)
379
380 page.append(
381 make_table(gen_data(),
382 caption=("Package", "Type", "Release", "Fixed Version",
383 "Urgency", "Origin", "Debian Bugs"),
384 introduction=P("The information above is based on the following data on fixed versions.")))
385
386 if bug.comments:
387 page.append(H2("Notes"))
388 def gen_comments():
389 for (t, c) in bug.comments:
390 yield c
391 page.append(make_pre(gen_comments()))
392
393 return self.create_page(url, bug.name, page)
394
395 def page_debian_bug(self, url, bugnumber, buglist):
396 if len(buglist) == 1:
397 # Single issue, redirect.
398 return RedirectResult(url.scriptRelativeFull(buglist[0][0]))
399
400 def gen():
401 for (name, urgency, description) in buglist:
402 if urgency == "unknown":
403 urgency = ""
404 yield self.make_xref(url, name), urgency, description
405
406 return self.create_page(
407 url, "Information related to Debian bug #%d" % bugnumber,
408 [P("The following issues reference to Debian bug ",
409 self.make_debian_bug(url, bugnumber), ":"),
410 make_table(gen(),
411 caption=("Name", "Urgency", "Description"))])
412
413 def page_not_found(self, url, query):
414 return self.create_page(url, 'Not found',
415 [P('Your query ',
416 CODE(query),
417 ' matched no results.')],
418 status=404)
419
420 def page_source_package(self, path, params, url):
421 pkg = path[0]
422
423 def gen_versions():
424 for (releases, version) in self.db.getSourcePackageVersions(
425 self.db.cursor(), pkg):
426 yield ', '.join(releases), version
427 def gen_binary():
428 for (packages, releases, archs, version) \
429 in self.db.getBinaryPackagesForSource(
430 self.db.cursor(), pkg):
431 yield (self.make_binary_packages_ref(url, packages),
432 ', '.join(releases), version, ', '.join(archs))
433 def gen_bug_list(lst):
434 for (bug, description) in lst:
435 yield self.make_xref(url, bug), description
436
437 return self.create_page(
438 url, "Information on source package " + pkg,
439 [make_menu(lambda x: x,
440 (self.url_pts(url, pkg),
441 pkg + ' in the Package Tracking System'),
442 (self.url_debian_bug_pkg(url, pkg),
443 pkg + ' in the Bug Tracking System'),
444 (self.url_testing_status(url, pkg),
445 pkg + ' in the testing migration checker')),
446 H2("Available versions"),
447 make_table(gen_versions(), caption=("Release", "Version")),
448
449 H2("Available binary packages"),
450 make_table(gen_binary(),
451 caption=('Package', 'Release', 'Version', 'Architectures'),
452 replacement="""No binary packages are recorded in this database.
453 This probably means that the package is architecture-specific, and the
454 architecture is currently not tracked."""),
455
456 H2("Open issues"),
457 make_table(gen_bug_list(self.db.getBugsForSourcePackage
458 (self.db.cursor(), pkg, True)),
459 caption=('Bug', 'Description'),
460 replacement='No known open issues.'),
461
462 H2("Resolved issues"),
463 make_table(gen_bug_list(self.db.getBugsForSourcePackage
464 (self.db.cursor(), pkg, False)),
465 caption=('Bug', 'Description'),
466 replacement='No known resolved issues.')])
467
468 def page_binary_package(self, path, params, url):
469 pkg = path[0]
470
471 def gen_versions():
472 for (releases, source, version, archs) \
473 in self.db.getBinaryPackageVersions(self.db.cursor(), pkg):
474 yield (', '.join(releases),
475 self.make_source_package_ref(url, source),
476 version, ', '.join(archs))
477 def gen_bug_list(lst):
478 for (bug, description) in lst:
479 yield self.make_xref(url, bug), description
480
481 return self.create_page(
482 url, "Information on binary package " + pkg,
483 [make_menu(lambda x: x,
484 (self.url_debian_bug_pkg(url, pkg),
485 pkg + ' in the Bug Tracking System')),
486 H2("Available versions"),
487 make_table(gen_versions(),
488 caption=("Release", "Source", "Version", "Architectures")),
489
490 H2("Open issues"),
491 make_table(gen_bug_list(self.db.getBugsForBinaryPackage
492 (self.db.cursor(), pkg, True)),
493 caption=('Bug', 'Description'),
494 replacement='No known open issues.'),
495
496 H2("Resolved issues"),
497 make_table(gen_bug_list(self.db.getBugsForBinaryPackage
498 (self.db.cursor(), pkg, False)),
499 caption=('Bug', 'Description'),
500 replacement='No known resolved issues.'),
501
502 H2("Non-issues"),
503 make_table(gen_bug_list(self.db.getNonBugsForBinaryPackage
504 (self.db.cursor(), pkg)),
505 caption=('Bug', 'Description'),
506 replacement="""No known issues which do not affect
507 this package, but still reference it.""")])
508
509 def page_status_release_stable_oldstable(self, release, params, url):
510 assert release in ('stable', 'oldstable')
511
512 bf = BugFilter(params)
513
514 def gen():
515 old_pkg_name = ''
516 for (pkg_name, bug_name, archive, urgency, remote) in \
517 self.db.cursor().execute(
518 """SELECT package, bug, section, urgency, remote
519 FROM %s_status""" % release):
520 if bf.urgencyFiltered(urgency):
521 continue
522 if bf.remoteFiltered(remote):
523 continue
524
525 if pkg_name == old_pkg_name:
526 pkg_name = ''
527 else:
528 old_pkg_name = pkg_name
529 if archive <> 'main':
530 pkg_name = "%s (%s)" % (pkg_name, archive)
531
532 if remote is None:
533 remote = ''
534 elif remote:
535 remote = 'yes'
536 else:
537 remote = 'no'
538
539 if urgency == 'unknown':
540 urgency = ''
541 elif urgency == 'high':
542 urgency = self.make_red(urgency)
543
544 yield pkg_name, self.make_xref(url, bug_name), urgency, remote
545
546 return self.create_page(
547 url, 'Vulnerable source packages in the %s suite' % release,
548 [bf.actions(url),
549 make_table(gen(), caption=("Package", "Bug", "Urgency",
550 "Remote"))])
551
552 def page_status_release_stable(self, path, params, url):
553 return self.page_status_release_stable_oldstable('stable', params, url)
554 def page_status_release_oldstable(self, path, params, url):
555 return self.page_status_release_stable_oldstable('oldstable',
556 params, url)
557
558 def page_status_release_testing(self, path, params, url):
559 bf = BugFilter(params)
560
561 def gen():
562 old_pkg_name = ''
563 for (pkg_name, bug_name, archive, urgency,
564 sid_vulnerable, ts_fixed, remote) in self.db.cursor().execute(
565 """SELECT package, bug, section, urgency, unstable_vulnerable,
566 testing_security_fixed, remote
567 FROM testing_status"""):
568 if bf.urgencyFiltered(urgency):
569 continue
570 if bf.remoteFiltered(remote):
571 continue
572
573 if pkg_name == old_pkg_name:
574 pkg_name = ''
575 else:
576 old_pkg_name = pkg_name
577 if archive <> 'main':
578 pkg_name = "%s (%s)" % (pkg_name, archive)
579
580 if remote is None:
581 remote = ''
582 elif remote:
583 remote = 'yes'
584 else:
585 remote = 'no'
586
587 if ts_fixed:
588 status = 'fixed in testing-security'
589 else:
590 if sid_vulnerable:
591 status = self.make_red('unstable is vulnerable')
592 else:
593 status = self.make_dangerous('fixed in unstable')
594
595 if urgency == 'unknown':
596 urgency = ''
597
598 yield (pkg_name, self.make_xref(url, bug_name),
599 urgency, remote, status)
600
601 return self.create_page(
602 url, 'Vulnerable source packages in the testing suite',
603 [make_menu(url.scriptRelative,
604 ("status/dtsa-candidates", "Candidates for DTSAs")),
605 bf.actions(url),
606 make_table(gen(), caption=("Package", "Bug", "Urgency",
607 "Remote"))])
608
609 def page_status_release_unstable(self, path, params, url):
610 bf = BugFilter(params)
611
612 def gen():
613 old_pkg_name = ''
614 for (pkg_name, bug_name, section, urgency, remote) \
615 in self.db.cursor().execute(
616 """SELECT DISTINCT sp.name, st.bug_name,
617 sp.archive, st.urgency,
618 (SELECT range_remote FROM nvd_data
619 WHERE cve_name = st.bug_name)
620 FROM source_package_status AS st, source_packages AS sp
621 WHERE st.vulnerable AND st.urgency <> 'unimportant'
622 AND sp.rowid = st.package AND sp.release = 'sid'
623 AND sp.subrelease = ''
624 ORDER BY sp.name, st.bug_name"""):
625 if bf.urgencyFiltered(urgency):
626 continue
627 if bf.remoteFiltered(remote):
628 continue
629
630 if pkg_name == old_pkg_name:
631 pkg_name = ''
632 else:
633 old_pkg_name = pkg_name
634 if section <> 'main':
635 pkg_name = "%s (%s)" % (pkg_name, section)
636 else:
637 pkg_name = self.make_xref(url, pkg_name)
638
639 if remote is None:
640 remote = ''
641 elif remote:
642 remote = 'yes'
643 else:
644 remote = 'no'
645
646 if urgency == 'unknown':
647 urgency = ''
648 elif urgency == 'high':
649 urgency = self.make_red(urgency)
650
651 yield pkg_name, self.make_xref(url, bug_name), urgency, remote
652
653
654 return self.create_page(
655 url, 'Vulnerable source packages in the unstable suite',
656 [P("""Note that the list below is based on source packages.
657 This means that packages are not listed here once a new,
658 fixed source version has been uploaded to the archive, even
659 if there are still some vulnerably binary packages present
660 in the archive."""),
661 bf.actions(url),
662 make_table(gen(), caption=('Package', 'Bug', 'Urgency',
663 'Remote'))])
664
665 def page_status_dtsa_candidates(self, path, params, url):
666 bf = BugFilter(params)
667
668 def gen():
669 old_pkg_name = ''
670 for (pkg_name, bug_name, archive, urgency, stable_later,
671 remote) \
672 in self.db.cursor().execute(
673 """SELECT package, bug, section, urgency,
674 (SELECT testing.version_id < stable.version_id
675 FROM source_packages AS testing, source_packages AS stable
676 WHERE testing.name = testing_status.package
677 AND testing.release = 'etch'
678 AND testing.subrelease = ''
679 AND testing.archive = testing_status.section
680 AND stable.name = testing_status.package
681 AND stable.release = 'sarge'
682 AND stable.subrelease = 'security'
683 AND stable.archive = testing_status.section),
684 (SELECT range_remote FROM nvd_data
685 WHERE cve_name = bug)
686 FROM testing_status
687 WHERE (NOT unstable_vulnerable)
688 AND (NOT testing_security_fixed)"""):
689 if bf.urgencyFiltered(urgency):
690 continue
691 if bf.remoteFiltered(remote):
692 continue
693
694 if pkg_name == old_pkg_name:
695 pkg_name = ''
696 migration = ''
697 else:
698 old_pkg_name = pkg_name
699 migration = A(self.url_testing_status(url, pkg_name),
700 "check")
701 if archive <> 'main':
702 pkg_name = "%s (%s)" % (pkg_name, archive)
703 else:
704 pkg_name = self.make_source_package_ref(url, pkg_name)
705
706 if remote is None:
707 remote = ''
708 elif remote:
709 remote = 'yes'
710 else:
711 remote = 'no'
712
713 if urgency == 'unknown':
714 urgency = ''
715 elif urgency == 'high':
716 urgency = self.make_red(urgency)
717
718 if stable_later:
719 notes = "(fixed in stable?)"
720 else:
721 notes = ''
722
723 yield (pkg_name, migration, self.make_xref(url, bug_name),
724 urgency, remote, notes)
725
726 return self.create_page(
727 url, "Candidates for DTSAs",
728 [P("""The table below lists packages which are fixed
729 in unstable, but unfixed in testing. Use the testing migration
730 checker to find out why they have not entered testing yet."""),
731 make_menu(url.scriptRelative,
732 ("status/release/testing",
733 "List of vulnerable packages in testing")),
734 bf.actions(url),
735 make_table(gen(),
736 caption=("Package", "Migration", "Bug", "Urgency",
737 "Remote"))])
738
739 def page_status_todo(self, path, params, url):
740 def gen():
741 for (bug, description) in self.db.getTODOs():
742 yield self.make_xref(url, bug), description
743 return self.create_page(
744 url, "Bugs with TODO items",
745 [make_table(gen(),
746 caption=("Bug", "Description"))])
747
748 def page_status_itp(self, path, params, url):
749 def gen():
750 old_pkg = ''
751 for pkg, bugs, debian_bugs in self.db.getITPs(self.db.cursor()):
752 if pkg == old_pkg:
753 pkg = ''
754 else:
755 old_pkg = pkg
756 yield (pkg, self.make_xref_list(url, bugs),
757 self.make_debian_bug_list(url, debian_bugs))
758 return self.create_page(
759 url, "ITPs with potential security issues",
760 [make_table(gen(), caption=("Package", "Issue", "Debian Bugs"),
761 replacement="No ITP bugs are currently known.")])
762
763 def page_data_unknown_packages(self, path, params, url):
764 def gen():
765 for name, bugs in self.db.getUnknownPackages(self.db.cursor()):
766 yield name, self.make_xref_list(url, bugs)
767 return self.create_page(
768 url, "Unknown packages",
769 [P("""Sometimes, a package referenced in a bug report
770 cannot be found in the database. This can be the result of a spelling
771 return web_supporterror, or a historic entry refers to a
772 return web_supportpackage which is no longer in the archive."""),
773 make_table(gen(), caption=("Package", "Bugs"),
774 replacement="No unknown packages are referenced in the database.")])
775
776 def page_data_missing_epochs(self, path, params, url):
777 def gen():
778 old_bug = ''
779 old_pkg = ''
780 for bug, pkg, ver1, ver2 in self.db.cursor().execute(
781 """SELECT DISTINCT bug_name, n.package,
782 n.fixed_version, sp.version
783 FROM package_notes AS n, source_packages AS sp
784 WHERE n.package_kind = 'source'
785 AND n.fixed_version NOT LIKE '%:%'
786 AND n.fixed_version <> '0'
787 AND n.bug_origin = ''
788 AND sp.name = n.package
789 AND sp.version LIKE '%:%'
790 ORDER BY bug_name, package"""):
791 if bug == old_bug:
792 bug = ''
793 else:
794 old_bug = bug
795 old_pkg = ''
796 bug = self.make_xref(url, bug)
797 if pkg == old_pkg:
798 pkg = ''
799 else:
800 old_pkg = pkg
801 pkg = self.make_source_package_ref(url, pkg)
802 yield bug, pkg, ver1, ver2
803
804 return self.create_page(
805 url, "Missing epochs in package versions",
806 [make_table(gen(),
807 caption=("Bug", "Package", "Version 1", "Version 2"),
808 replacement="No source package version with missing epochs.")])
809
810 def page_data_releases(self, path, params, url):
811 def gen():
812 for (rel, subrel, archive, sources, archs) \
813 in self.db.availableReleases():
814 if sources:
815 sources = 'yes'
816 else:
817 sources = 'no'
818 yield rel, subrel, archive, sources, make_list(archs)
819 return self.create_page(
820 url, "Available releases",
821 [P("""The security issue database is checked against
822 the Debian releases listed in the table below."""),
823 make_table(gen(),
824 caption=("Release", "Subrelease", "Archive",
825 "Sources", "Architectures"))])
826
827 def page_data_funny_versions(self, path, params, url):
828 def gen():
829 for name, release, archive, version, source_version \
830 in self.db.getFunnyPackageVersions():
831 yield name, release, archive, source_version, version
832
833 return self.create_page(
834 url, "Version conflicts between source/binary packages",
835 [P("""The table below lists source packages
836 which have a binary package of the same name, but with a different
837 version. This means that extra care is necessary to determine
838 the version of a package which has been fixed. (Note that
839 the bug tracker prefers source versions to binary versions
840 in this case.)"""),
841 make_table(gen(),
842 caption=("Package",
843 "Release",
844 "Archive",
845 "Source Version",
846 "Binary Version")),
847 P("""Technically speaking, these version numbering is fine,
848 but it makes version-based bug tracking quite difficult for these packages."""),
849 P("""There are many binary packages which are built from source
850 packages with different version numbering schemes. However, as
851 long as none of the binary packages carries the same name as the
852 source package, most confusion is avoided or can be easily
853 explained.""")])
854
855 def page_data_fake_names(self, path, params, url):
856 def gen():
857 for (bug, description) in self.db.getFakeBugs():
858 yield self.make_xref(url, bug), description
859 return self.create_page(
860 url, "Automatically generated issue names",
861 [P("""Some issues have not been assigned CVE names, but are still
862 tracked by this database. In this case, the system automatically assigns
863 a unique name. These names are not stable and can change when the database
864 is updated, so they should not be used in external references."""),
865 P('''The automatically generated names come in two flavors:
866 the first kind starts with the string "''', CODE("FAKE-000000-"),
867 '''". This means that no Debian bug has been assigned to this
868 issue (or a bug has been created and is not recorded in this database).
869 In the second kind of names, there is a Debian bug for the issue, and the "''',
870 CODE("000000"), '''"part of the name is replaced with the
871 Debian bug number.'''),
872 make_table(gen(),
873 caption=("Bug", "Description"))])
874
875 def page_debsecan(self, path, params, url):
876 obj = '/'.join(path)
877 data = self.db.getDebsecan(obj)
878 if data:
879 return BinaryResult(data)
880 else:
881 return self.create_page(
882 url, "Object not found",
883 [P("The requested debsecan object has not been found.")],
884 status=404)
885
886 def create_page(self, url, title, body, search_in_page=False, status=200):
887 append = body.append
888 append(HR())
889 if not search_in_page:
890 append(self.make_search_button(url))
891 append(P(A(url.scriptRelative(""), "Home"),
892 " - ", A(url.absolute("http://secure-testing.debian.net/"),
893 "Testing Security Team"),
894 " - ", A(url.absolute("http://www.debian.org/security/"),
895 "Debian Security"),
896 " - ", A(url.absolute
897 ("http://www.enyo.de/fw/impressum.html"),
898 "Imprint")))
899 if search_in_page:
900 on_load = "selectSearch()"
901 else:
902 on_load = None
903 return HTMLResult(self.add_title(title, body,
904 head_contents=self.head_contents,
905 body_attribs={'onload': on_load}),
906 doctype=self.html_dtd(),
907 status=status)
908
909 def make_search_button(self, url):
910 return FORM("Search for package or bug name: ",
911 INPUT(type='text', name='query',
912 onkeyup="onSearch(this.value)",
913 onmousemove="onSearch(this.value)"),
914 INPUT(type='submit', value='Go'),
915 method='get',
916 action=url.scriptRelative(''))
917
918 def url_cve(self, url, name):
919 return url.absolute("http://cve.mitre.org/cgi-bin/cvename.cgi",
920 name=name)
921 def url_nvd(self, url, name):
922 return url.absolute("http://nvd.nist.gov/nvd.cfm",
923 cvename=name)
924
925 def url_dsa(self, url, dsa, re_dsa=re.compile(r'^DSA-(\d+)(?:-\d+)?$')):
926 match = re_dsa.match(dsa)
927 if match:
928 # We must determine the year because there is no generic URL.
929 (number,) = match.groups()
930 for (date,) in self.db.cursor().execute(
931 "SELECT release_date FROM bugs WHERE name = ?", (dsa,)):
932 (y, m, d) = date.split('-')
933 return url.absolute("http://www.debian.org/security/%d/dsa-%d"
934 % (int(y), int(number)))
935 return None
936
937 def url_debian_bug(self, url, debian):
938 return url.absolute("http://bugs.debian.org/cgi-bin/bugreport.cgi",
939 bug=str(debian))
940 def url_debian_bug_pkg(self, url, debian):
941 return url.absolute("http://bugs.debian.org/cgi-bin/pkgreport.cgi",
942 pkg=debian)
943 def url_pts(self, url, package):
944 return url.absolute("http://packages.qa.debian.org/common/index.html",
945 src=package)
946 def url_testing_status(self, url, package):
947 return url.absolute("http://bjorn.haxx.se/debian/testing.pl",
948 package=package)
949 def url_source_package(self, url, package, full=False):
950 if full:
951 return url.scriptRelativeFull("source-package/" + package)
952 else:
953 return url.scriptRelative("source-package/" + package)
954 def url_binary_package(self, url, package, full=False):
955 if full:
956 return url.scriptRelativeFull("binary-package/" + package)
957 else:
958 return url.scriptRelative("binary-package/" + package)
959
960 def make_xref(self, url, name):
961 return A(url.scriptRelative(name), name)
962
963 def make_xref_list(self, url, lst, separator=', '):
964 return make_list(map(lambda x: self.make_xref(url, x), lst), separator)
965
966 def make_debian_bug(self, url, debian):
967 return A(self.url_debian_bug(url, debian), str(debian))
968 def make_debian_bug_list(self, url, lst):
969 return make_list(map(lambda x: self.make_debian_bug(url, x), lst))
970
971 def make_cve_ref(self, url, cve, name=None):
972 if name is None:
973 name = cve
974 return A(self.url_cve(url, cve), name)
975
976 def make_nvd_ref(self, url, cve, name=None):
977 if name is None:
978 name = cve
979 return A(self.url_nvd(url, cve), name)
980
981 def make_dsa_ref(self, url, dsa, name=None):
982 if name is None:
983 name = dsa
984 u = self.url_dsa(url, dsa)
985 if u:
986 return A(u, name)
987 else:
988 return name
989
990 def make_pts_ref(self, url, pkg, name=None):
991 if name is None:
992 name = pkg
993 return A(self.url_pts(url, pkg), name)
994
995 def make_source_package_ref(self, url, pkg, title=None):
996 if title is None:
997 title = pkg
998 return A(self.url_source_package(url, pkg), title)
999 def make_binary_package_ref(self, url, pkg, title=None):
1000 if title is None:
1001 title = pkg
1002 return A(self.url_binary_package(url, pkg), title)
1003 def make_binary_packages_ref(self, url, lst):
1004 assert type(lst) <> types.StringType
1005 return make_list(map(lambda x: self.make_binary_package_ref(url, x),
1006 lst))
1007
1008 def make_red(self, contents):
1009 return SPAN(contents, _class="red")
1010
1011 def make_dangerous(self, contents):
1012 return SPAN(contents, _class="dangerous")
1013
1014 def pre_dispatch(self):
1015 self.db.refresh()
1016
1017 TrackerService(socket_name, db_name).run()

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5