| 2 |
|
|
| 3 |
import sys |
import sys |
| 4 |
sys.path.insert(0,'../lib/python') |
sys.path.insert(0,'../lib/python') |
|
|
|
|
if len(sys.argv) <> 3: |
|
|
print "usage: python tracker_serivce.py SOCKET-PATH DATABASE-PATH" |
|
|
sys.exit(1) |
|
|
socket_name = sys.argv[1] |
|
|
db_name = sys.argv[2] |
|
|
|
|
| 5 |
import bugs |
import bugs |
| 6 |
import re |
import re |
| 7 |
import security_db |
import security_db |
| 8 |
from web_support import * |
from web_support import * |
| 9 |
|
|
| 10 |
class TrackerService(WebService): |
if len(sys.argv) not in (3, 5): |
| 11 |
|
print "usage: python tracker_service.py SOCKET-PATH DATABASE-PATH" |
| 12 |
|
print " python tracker_service.py URL HOST PORT DATABASE-PATH" |
| 13 |
|
sys.exit(1) |
| 14 |
|
if len(sys.argv) == 3: |
| 15 |
|
socket_name = sys.argv[1] |
| 16 |
|
db_name = sys.argv[2] |
| 17 |
|
webservice_base_class = WebService |
| 18 |
|
else: |
| 19 |
|
server_base_url = sys.argv[1] |
| 20 |
|
server_address = sys.argv[2] |
| 21 |
|
server_port = int(sys.argv[3]) |
| 22 |
|
socket_name = (server_base_url, server_address, server_port) |
| 23 |
|
db_name = sys.argv[4] |
| 24 |
|
webservice_base_class = WebServiceHTTP |
| 25 |
|
|
| 26 |
|
class BugFilter: |
| 27 |
|
default_action_list = [("hide_medium_urgency", "lower urgencies"), |
| 28 |
|
("hide_non_remote", "local vulnerabilities")] |
| 29 |
|
def __init__(self, params, action_list=None): |
| 30 |
|
if action_list is None: |
| 31 |
|
self.action_list = self.default_action_list |
| 32 |
|
else: |
| 33 |
|
self.action_list = action_list |
| 34 |
|
self.params = {} |
| 35 |
|
for (prop, desc) in self.action_list: |
| 36 |
|
self.params[prop] = int(params.get(prop, (0,))[0]) |
| 37 |
|
|
| 38 |
|
def actions(self, url): |
| 39 |
|
"""Returns a HTML snippet which can be used to change the filter.""" |
| 40 |
|
|
| 41 |
|
l = [] |
| 42 |
|
for (prop, desc) in self.action_list: |
| 43 |
|
if self.params[prop]: |
| 44 |
|
a = A(url.updateParamsDict({prop : None}), |
| 45 |
|
'Show ' + desc) |
| 46 |
|
else: |
| 47 |
|
a = A(url.updateParamsDict({prop : '1'}), |
| 48 |
|
'Hide ' + desc) |
| 49 |
|
l.append(a) |
| 50 |
|
l.append(' ') |
| 51 |
|
|
| 52 |
|
return apply(P, l[:-1]) |
| 53 |
|
|
| 54 |
|
def urgencyFiltered(self, urg): |
| 55 |
|
"""Returns True if the urgency urg is filtered.""" |
| 56 |
|
return self.params['hide_medium_urgency'] \ |
| 57 |
|
and urg not in ("high", "unknown", "") |
| 58 |
|
|
| 59 |
|
def remoteFiltered(self, remote): |
| 60 |
|
"""Returns True if the attack range is filtered.""" |
| 61 |
|
return remote is not None and self.params['hide_non_remote'] \ |
| 62 |
|
and not remote |
| 63 |
|
|
| 64 |
|
class BugFilterNoDSA(BugFilter): |
| 65 |
|
def __init__(self, params): |
| 66 |
|
BugFilter.__init__(self, params, self.default_action_list |
| 67 |
|
+ [('hide_nodsa', 'non-DSA vulnerabilities')]) |
| 68 |
|
self.hide_nodsa = int(params.get('hide_nodsa',(0,))[0]) |
| 69 |
|
|
| 70 |
|
def nodsaFiltered(self, nodsa): |
| 71 |
|
"""Returns True if no DSA will be issued for the bug.""" |
| 72 |
|
return nodsa and self.params['hide_nodsa'] |
| 73 |
|
|
| 74 |
|
class TrackerService(webservice_base_class): |
| 75 |
head_contents = compose(STYLE( |
head_contents = compose(STYLE( |
| 76 |
"""h1 { font-size : 144%; } |
"""h1 { font-size : 144%; } |
| 77 |
h2 { font-size : 120%; } |
h2 { font-size : 120%; } |
| 103 |
''')).toHTML() |
''')).toHTML() |
| 104 |
|
|
| 105 |
def __init__(self, socket_name, db_name): |
def __init__(self, socket_name, db_name): |
| 106 |
WebService.__init__(self, socket_name) |
webservice_base_class.__init__(self, socket_name) |
| 107 |
self.db = security_db.DB(db_name) |
self.db = security_db.DB(db_name) |
| 108 |
self.register('', self.page_home) |
self.register('', self.page_home) |
| 109 |
self.register('*', self.page_object) |
self.register('*', self.page_object) |
| 110 |
self.register('redirect/*', self.page_redirect) |
self.register('redirect/*', self.page_redirect) |
| 111 |
self.register('source-package/*', self.page_source_package) |
self.register('source-package/*', self.page_source_package) |
| 112 |
self.register('binary-package/*', self.page_binary_package) |
self.register('binary-package/*', self.page_binary_package) |
| 113 |
|
self.register('status/release/oldstable', |
| 114 |
|
self.page_status_release_oldstable) |
| 115 |
self.register('status/release/stable', self.page_status_release_stable) |
self.register('status/release/stable', self.page_status_release_stable) |
| 116 |
|
self.register('status/release/stable-backports', |
| 117 |
|
self.page_status_release_stable_backports) |
| 118 |
|
self.register('status/release/oldstable-backports', |
| 119 |
|
self.page_status_release_oldstable_backports) |
| 120 |
self.register('status/release/testing', |
self.register('status/release/testing', |
| 121 |
self.page_status_release_testing) |
self.page_status_release_testing) |
| 122 |
self.register('status/release/unstable', |
self.register('status/release/unstable', |
| 127 |
self.register('status/itp', self.page_status_itp) |
self.register('status/itp', self.page_status_itp) |
| 128 |
self.register('data/unknown-packages', self.page_data_unknown_packages) |
self.register('data/unknown-packages', self.page_data_unknown_packages) |
| 129 |
self.register('data/missing-epochs', self.page_data_missing_epochs) |
self.register('data/missing-epochs', self.page_data_missing_epochs) |
| 130 |
|
self.register('data/latently-vulnerable', |
| 131 |
|
self.page_data_latently_vulnerable) |
| 132 |
self.register('data/releases', self.page_data_releases) |
self.register('data/releases', self.page_data_releases) |
| 133 |
self.register('data/funny-versions', self.page_data_funny_versions) |
self.register('data/funny-versions', self.page_data_funny_versions) |
| 134 |
|
self.register('data/fake-names', self.page_data_fake_names) |
| 135 |
|
self.register('debsecan/**', self.page_debsecan) |
| 136 |
|
self.register('data/report', self.page_report) |
| 137 |
|
|
| 138 |
def page_home(self, path, params, url): |
def page_home(self, path, params, url): |
| 139 |
query = params.get('query', ('',))[0] |
query = params.get('query', ('',))[0] |
| 146 |
return self.create_page( |
return self.create_page( |
| 147 |
url, 'Security Bug Tracker', |
url, 'Security Bug Tracker', |
| 148 |
[P( |
[P( |
| 149 |
"""This is the experimental issue tracker for Debian's testing |
"""The data in this tracker comes solely from the bug database maintained |
| 150 |
security team. Keep in mind that this is merely a prototype. |
by Debian's security team located in the testing-security Subversion """, |
| 151 |
Please report any problems to """, |
A("http://svn.debian.org/wsvn/secure-testing/data", "repository"), |
| 152 |
A("mailto:fw@deneb.enyo.de", "Florian Weimer"), |
""". The data represented here is derived from: """, |
| 153 |
""".Note that some of the data presented here is known |
A("http://www.debian.org/security/#DSAS", "DSAs"), |
| 154 |
to be wrong (see below), but the data for the testing suite |
""" issued by the Security Team; issues tracked in the """, |
| 155 |
should be fine."""), |
A("http://cve.mitre.org/cve/", "CVE database"), |
| 156 |
make_menu( |
""", issues tracked in the """, |
| 157 |
|
A("http://nvd.nist.gov/", "National Vulnerability Database"), |
| 158 |
|
""" (NVD), maintained by NIST; and security issues |
| 159 |
|
discovered in Debian packages as reported in the BTS."""), |
| 160 |
|
P("""All external data (including Debian bug reports and official Debian |
| 161 |
|
security advisories) must be added to this database before it appears |
| 162 |
|
here. Please help us keep this information up-to-date by """, |
| 163 |
|
A(url.scriptRelative("data/report"), "reporting"), |
| 164 |
|
""" any discrepancies or change of states that you are |
| 165 |
|
aware of and/or help us improve the quality of this information by """, |
| 166 |
|
A(url.scriptRelative("data/report"), "participating"), |
| 167 |
|
"."), |
| 168 |
|
make_menu( |
| 169 |
url.scriptRelative, |
url.scriptRelative, |
|
('status/release/stable', |
|
|
'Vulnerable packages in the stable suite'), |
|
|
('status/release/testing', |
|
|
'Vulnerable packages in the testing suite'), |
|
| 170 |
('status/release/unstable', |
('status/release/unstable', |
| 171 |
'Vulnerable packages in the unstable suite'), |
'Vulnerable packages in the unstable suite'), |
| 172 |
|
('status/release/testing', |
| 173 |
|
'Vulnerable packages in the testing suite'), |
| 174 |
|
('status/release/stable', |
| 175 |
|
'Vulnerable packages in the stable suite'), |
| 176 |
|
('status/release/oldstable', |
| 177 |
|
'Vulnerable packages in the old stable suite'), |
| 178 |
|
('status/release/stable-backports', |
| 179 |
|
'Vulnerable packages in backports for stable'), |
| 180 |
|
('status/release/oldstable-backports', |
| 181 |
|
'Vulnerable packages in backports for oldstable'), |
| 182 |
('status/dtsa-candidates', "Candidates for DTSAs"), |
('status/dtsa-candidates', "Candidates for DTSAs"), |
| 183 |
('status/todo', 'TODO items'), |
('status/todo', 'TODO items'), |
| 184 |
('status/itp', 'ITPs with potential security issues'), |
('status/itp', 'ITPs with potential security issues'), |
| 185 |
('data/unknown-packages', |
('data/unknown-packages', |
| 186 |
'Packages names not found in the archive'), |
'Packages names not found in the archive'), |
| 187 |
|
('data/fake-names', 'Tracked issues without a CVE name'), |
| 188 |
('data/missing-epochs', |
('data/missing-epochs', |
| 189 |
'Package versions which might lack an epoch'), |
'Package versions which might lack an epoch'), |
| 190 |
|
('data/latently-vulnerable', |
| 191 |
|
'Packages which are latently vulnerable in unstable'), |
| 192 |
('data/funny-versions', |
('data/funny-versions', |
| 193 |
'Packages with strange version numbers'), |
'Packages with strange version numbers'), |
| 194 |
('data/releases', |
('data/releases', |
| 195 |
'Covered Debian releases and architectures (slow)'), |
'Covered Debian releases and architectures (slow)'), |
| 196 |
self.make_search_button(url)), |
self.make_search_button(url)), |
| 197 |
P("""(You can enter CAN/CVE names, Debian bug numbers and package |
P("""(You can enter CVE names, Debian bug numbers and package |
| 198 |
names in the search forms.)"""), |
names in the search forms.)"""), |
| 199 |
|
|
|
H2("Data sources"), |
|
|
P("""Data in this tracker comes solely from the bug database |
|
|
which is maintained by Debian's testing security team in their |
|
|
Subversion repository. All external data (this includes |
|
|
Debian bug reports and official Debian security advisories) |
|
|
must be added to this database before it appears here, and there |
|
|
can be some delay before this happens."""), |
|
|
P("""At the moment, the database only contains information which is |
|
|
relevant for tracking the security status of the stable, testing and |
|
|
unstable suites. This means that data for oldstable is likely wrong."""), |
|
|
P('Data marked "NVD" comes from the ', |
|
|
A(url.absolute('http://nvd.nist.gov/'), |
|
|
'National Vulnerability Database'), |
|
|
' maintained by NIST.'), |
|
|
|
|
| 200 |
H2("External interfaces"), |
H2("External interfaces"), |
| 201 |
P("""If you want to automatically open a relevant web page for |
P("""If you want to automatically open a relevant web page for |
| 202 |
some object, use the """, |
some object, use the """, |
| 220 |
if not obj: |
if not obj: |
| 221 |
# Redirect to start page. |
# Redirect to start page. |
| 222 |
return RedirectResult(url.scriptRelativeFull("")) |
return RedirectResult(url.scriptRelativeFull("")) |
|
|
|
|
if 'A' <= obj[0] <= 'Z': |
|
|
# Bug names start with a capital letter. |
|
|
return self.page_bug(url, obj, redirect) |
|
| 223 |
|
|
| 224 |
|
# Attempt to decode a bug number. TEMP-nnn bugs (but not |
| 225 |
|
# TEMP-nnn-mmm bugs) are treated as bug references, too. |
| 226 |
bugnumber = 0 |
bugnumber = 0 |
| 227 |
|
fake_bug = False |
| 228 |
try: |
try: |
| 229 |
bugnumber = int(obj) |
if obj[0:5] == 'FAKE-' or obj[0:5] == 'TEMP-': |
| 230 |
|
bugnumber = int(obj[5:]) |
| 231 |
|
fake_bug = True |
| 232 |
|
else: |
| 233 |
|
bugnumber = int(obj) |
| 234 |
except ValueError: |
except ValueError: |
| 235 |
pass |
pass |
| 236 |
if bugnumber: |
if bugnumber: |
| 237 |
buglist = list(self.db.getBugsFromDebianBug(c, bugnumber)) |
buglist = list(self.db.getBugsFromDebianBug(c, bugnumber)) |
| 238 |
if buglist: |
if buglist: |
| 239 |
return self.page_debian_bug(url, bugnumber, buglist) |
return self.page_debian_bug(url, bugnumber, buglist, fake_bug) |
| 240 |
if redirect: |
if redirect: |
| 241 |
return RedirectResult(self.url_debian_bug(url, str(bugnumber)), |
return RedirectResult(self.url_debian_bug(url, str(bugnumber)), |
| 242 |
permanent=False) |
permanent=False) |
| 243 |
|
|
| 244 |
|
if 'A' <= obj[0] <= 'Z': |
| 245 |
|
# Bug names start with a capital letter. |
| 246 |
|
return self.page_bug(url, obj, redirect) |
| 247 |
|
|
| 248 |
if self.db.isSourcePackage(c, obj): |
if self.db.isSourcePackage(c, obj): |
| 249 |
return RedirectResult(self.url_source_package(url, obj, full=True)) |
return RedirectResult(self.url_source_package(url, obj, full=True)) |
| 250 |
if self.db.isBinaryPackage(c, obj): |
if self.db.isBinaryPackage(c, obj): |
| 253 |
return self.page_not_found(url, obj) |
return self.page_not_found(url, obj) |
| 254 |
|
|
| 255 |
def page_bug(self, url, name, redirect): |
def page_bug(self, url, name, redirect): |
| 256 |
|
# FIXME: Normalize CAN-* to CVE-* when redirecting. Too many |
| 257 |
|
# people still use CAN. |
| 258 |
|
if redirect and name[0:4] == 'CAN-': |
| 259 |
|
name = 'CVE-' + name[4:] |
| 260 |
|
|
| 261 |
cursor = self.db.cursor() |
cursor = self.db.cursor() |
| 262 |
try: |
try: |
| 263 |
bug = bugs.BugFromDB(cursor, name) |
bug = bugs.BugFromDB(cursor, name) |
| 264 |
except ValueError: |
except ValueError: |
| 265 |
if redirect: |
if redirect: |
| 266 |
if name[0:4] in ('CAN-', 'CVE-'): |
if name[0:4] == 'CVE-': |
| 267 |
return RedirectResult(self.url_cve(url, name), |
return RedirectResult(self.url_cve(url, name), |
| 268 |
permanent=False) |
permanent=False) |
| 269 |
return self.page_not_found(url, name) |
return self.page_not_found(url, name) |
| 277 |
yield B("Name"), bug.name |
yield B("Name"), bug.name |
| 278 |
|
|
| 279 |
source = bug.name.split('-')[0] |
source = bug.name.split('-')[0] |
| 280 |
if source in ('CAN', 'CVE'): |
if source == 'CVE': |
| 281 |
source_xref = compose(self.make_cve_ref(url, bug.name, 'CVE'), |
source_xref = compose(self.make_cve_ref(url, bug.name, 'CVE'), |
| 282 |
" (", |
" (", |
| 283 |
self.make_nvd_ref(url, bug.name, |
self.make_nvd_ref(url, bug.name, |
| 287 |
source_xref = self.make_dsa_ref(url, bug.name, 'Debian') |
source_xref = self.make_dsa_ref(url, bug.name, 'Debian') |
| 288 |
elif source == 'DTSA': |
elif source == 'DTSA': |
| 289 |
source_xref = 'Debian Testing Security Team' |
source_xref = 'Debian Testing Security Team' |
| 290 |
elif source == 'FAKE': |
elif source == 'TEMP': |
| 291 |
source_xref = ( |
source_xref = ( |
| 292 |
'Automatically generated temporary name. Not for external reference.') |
'Automatically generated temporary name. Not for external reference.') |
| 293 |
else: |
else: |
| 296 |
if source_xref: |
if source_xref: |
| 297 |
yield B("Source"), source_xref |
yield B("Source"), source_xref |
| 298 |
|
|
| 299 |
if bug.description: |
nvd = self.db.getNVD(cursor, bug.name) |
| 300 |
|
|
| 301 |
|
if nvd and nvd.cve_desc: |
| 302 |
|
yield B("Description"), nvd.cve_desc |
| 303 |
|
elif bug.description: |
| 304 |
yield B("Description"), bug.description |
yield B("Description"), bug.description |
| 305 |
|
|
| 306 |
xref = list(self.db.getBugXrefs(cursor, bug.name)) |
xref = list(self.db.getBugXrefs(cursor, bug.name)) |
| 307 |
if xref: |
if xref: |
| 308 |
yield B("References"), self.make_xref_list(url, xref) |
yield B("References"), self.make_xref_list(url, xref) |
| 309 |
|
|
|
nvd = self.db.getNVD(cursor, bug.name) |
|
| 310 |
if nvd: |
if nvd: |
|
if nvd.severity: |
|
|
yield B("NVD severity"), nvd.severity.lower() |
|
| 311 |
nvd_range = nvd.rangeString() |
nvd_range = nvd.rangeString() |
| 312 |
if nvd_range: |
if nvd.severity: |
| 313 |
yield B("NVD attack range"), nvd_range |
nvd_severity = nvd.severity.lower() |
| 314 |
|
if nvd_range: |
| 315 |
|
nvd_severity = "%s (attack range: %s)" \ |
| 316 |
|
% (nvd_severity, nvd_range) |
| 317 |
|
yield B("NVD severity"), nvd_severity |
| 318 |
|
|
| 319 |
debian_bugs = bug.getDebianBugs(cursor) |
debian_bugs = bug.getDebianBugs(cursor) |
| 320 |
if debian_bugs: |
if debian_bugs: |
| 325 |
for (release, status, reason) in bug.getStatus(cursor): |
for (release, status, reason) in bug.getStatus(cursor): |
| 326 |
if status <> 'fixed': |
if status <> 'fixed': |
| 327 |
reason = self.make_red(reason) |
reason = self.make_red(reason) |
| 328 |
yield B('Status of %s' % release), reason |
yield B('Debian/%s' % release), reason |
| 329 |
|
|
| 330 |
page.append(make_table(gen_header())) |
page.append(make_table(gen_header())) |
| 331 |
|
|
| 435 |
|
|
| 436 |
return self.create_page(url, bug.name, page) |
return self.create_page(url, bug.name, page) |
| 437 |
|
|
| 438 |
def page_debian_bug(self, url, bugnumber, buglist): |
def page_debian_bug(self, url, bugnumber, buglist, fake_bug): |
| 439 |
|
if fake_bug: |
| 440 |
|
new_buglist = [] |
| 441 |
|
for b in buglist: |
| 442 |
|
(bug_name, urgency, description) = b |
| 443 |
|
if bug_name[0:5] == 'FAKE-' or bug_name[0:5] == 'TEMP-': |
| 444 |
|
new_buglist.append(b) |
| 445 |
|
if len(new_buglist) > 0: |
| 446 |
|
# Only replace the bug list if there are still fake |
| 447 |
|
# bug reports. |
| 448 |
|
buglist = new_buglist |
| 449 |
|
|
| 450 |
if len(buglist) == 1: |
if len(buglist) == 1: |
| 451 |
# Single issue, redirect. |
# Single issue, redirect. |
| 452 |
return RedirectResult(url.scriptRelativeFull(buglist[0][0])) |
return RedirectResult(url.scriptRelativeFull(buglist[0][0])) |
| 457 |
urgency = "" |
urgency = "" |
| 458 |
yield self.make_xref(url, name), urgency, description |
yield self.make_xref(url, name), urgency, description |
| 459 |
|
|
| 460 |
|
if fake_bug: |
| 461 |
|
intro = """The URL you used contained a non-stable name |
| 462 |
|
based on a Debian bug number. This name cannot be mapped to a specific |
| 463 |
|
issue. """ |
| 464 |
|
else: |
| 465 |
|
intro = "" |
| 466 |
|
|
| 467 |
return self.create_page( |
return self.create_page( |
| 468 |
url, "Information related to Debian bug #%d" % bugnumber, |
url, "Information related to Debian bug #%d" % bugnumber, |
| 469 |
[P("The following issues reference to Debian bug ", |
[P(intro + "The following issues reference to Debian bug ", |
| 470 |
self.make_debian_bug(url, bugnumber), ":"), |
self.make_debian_bug(url, bugnumber), ":"), |
| 471 |
make_table(gen(), |
make_table(gen(), |
| 472 |
caption=("Name", "Urgency", "Description"))]) |
caption=("Name", "Urgency", "Description"))]) |
| 478 |
' matched no results.')], |
' matched no results.')], |
| 479 |
status=404) |
status=404) |
| 480 |
|
|
| 481 |
|
def page_report(self, path, params, url): |
| 482 |
|
return self.create_page( |
| 483 |
|
url, 'Reporting discrepancies in the data', |
| 484 |
|
[P("""The data in this tracker is always in flux, as bugs are fixed and new |
| 485 |
|
issues disclosed, the data contained herein is updated. We strive to |
| 486 |
|
maintain complete and accurate state information, and appreciate any |
| 487 |
|
updates in status, information or new issues."""), |
| 488 |
|
P("There are three ways that you can report updates to this information:"), |
| 489 |
|
make_numbered_list( |
| 490 |
|
[P("""IRC: We can be found at """, |
| 491 |
|
CODE("irc.oftc.net"), |
| 492 |
|
", ", |
| 493 |
|
CODE("#debian-security"), |
| 494 |
|
""". If you have information to report, please go ahead and join |
| 495 |
|
the channel and tell us. Please feel free to state the issue, |
| 496 |
|
regardless if there is someone who has acknowledged you. Many of us |
| 497 |
|
idle on this channel and may not be around when you join, but we read |
| 498 |
|
the backlog and will see what you have said. If you require a |
| 499 |
|
response, do not forget to let us know how to get a hold of you."""), |
| 500 |
|
P("Mailing list: Our mailing list is: ", |
| 501 |
|
A("mailto:debian-security-tracker@lists.debian.org", |
| 502 |
|
"debian-security-tracker@lists.debian.org")), |
| 503 |
|
P("""Helping out: We welcome people who wish to join us in tracking |
| 504 |
|
issues. The process is designed to be easy to learn and participate, |
| 505 |
|
please read our """, |
| 506 |
|
A("http://svn.debian.org/wsvn/secure-testing/doc/narrative_introduction?op=file&rev=0&sc=0", |
| 507 |
|
"Introduction"), |
| 508 |
|
""" to get familiar with how things work. Join us on |
| 509 |
|
our mailing list, and on IRC and request to be added to the Alioth """, |
| 510 |
|
A("http://alioth.debian.org/projects/secure-testing/", "project"), |
| 511 |
|
""". We are really quite friendly. If you have a |
| 512 |
|
question about how things work, don't be afraid to ask, we would like |
| 513 |
|
to improve our documentation and procedures, so feedback is welcome.""")])]) |
| 514 |
|
|
| 515 |
def page_source_package(self, path, params, url): |
def page_source_package(self, path, params, url): |
| 516 |
pkg = path[0] |
pkg = path[0] |
| 517 |
|
|
| 601 |
replacement="""No known issues which do not affect |
replacement="""No known issues which do not affect |
| 602 |
this package, but still reference it.""")]) |
this package, but still reference it.""")]) |
| 603 |
|
|
| 604 |
def page_status_release_stable(self, path, params, url): |
def page_status_release_stable_oldstable(self, release, params, url): |
| 605 |
|
assert release in ('stable', 'oldstable') |
| 606 |
|
|
| 607 |
|
bf = BugFilterNoDSA(params) |
| 608 |
|
|
| 609 |
def gen(): |
def gen(): |
| 610 |
old_pkg_name = '' |
old_pkg_name = '' |
| 611 |
for (pkg_name, bug_name, archive, urgency, remote) in \ |
for (pkg_name, bug_name, archive, urgency, remote, no_dsa) in \ |
| 612 |
self.db.cursor().execute( |
self.db.cursor().execute( |
| 613 |
"""SELECT package, bug, section, urgency, remote |
"""SELECT package, bug, section, urgency, remote, no_dsa |
| 614 |
FROM stable_status"""): |
FROM %s_status""" % release): |
| 615 |
|
if bf.urgencyFiltered(urgency): |
| 616 |
|
continue |
| 617 |
|
if bf.remoteFiltered(remote): |
| 618 |
|
continue |
| 619 |
|
if bf.nodsaFiltered(no_dsa): |
| 620 |
|
continue |
| 621 |
|
|
| 622 |
if pkg_name == old_pkg_name: |
if pkg_name == old_pkg_name: |
| 623 |
pkg_name = '' |
pkg_name = '' |
| 624 |
else: |
else: |
| 634 |
remote = 'no' |
remote = 'no' |
| 635 |
|
|
| 636 |
if urgency == 'unknown': |
if urgency == 'unknown': |
| 637 |
urgency = '' |
if no_dsa: |
| 638 |
|
urgency = 'no DSA' |
| 639 |
|
else: |
| 640 |
|
urgency = '' |
| 641 |
elif urgency == 'high': |
elif urgency == 'high': |
| 642 |
urgency = self.make_red(urgency) |
urgency = self.make_red(urgency) |
| 643 |
|
else: |
| 644 |
|
if no_dsa: |
| 645 |
|
urgency = urgency + '*' |
| 646 |
|
|
| 647 |
yield pkg_name, self.make_xref(url, bug_name), urgency, remote |
yield pkg_name, self.make_xref(url, bug_name), urgency, remote |
| 648 |
|
|
| 649 |
return self.create_page( |
return self.create_page( |
| 650 |
url, 'Vulnerable source packages in the stable suite', |
url, 'Vulnerable source packages in the %s suite' % release, |
| 651 |
[make_table(gen(), caption=("Package", "Bug", "Urgency", |
[bf.actions(url), |
| 652 |
"Remote"))]) |
make_table(gen(), caption=("Package", "Bug", "Urgency", |
| 653 |
|
"Remote")), |
| 654 |
|
P('''(If a "*" is included in the urgency field, no DSA is planned |
| 655 |
|
for this vulnerability.)''')]) |
| 656 |
|
|
| 657 |
|
def page_status_release_stable(self, path, params, url): |
| 658 |
|
return self.page_status_release_stable_oldstable('stable', params, url) |
| 659 |
|
def page_status_release_oldstable(self, path, params, url): |
| 660 |
|
return self.page_status_release_stable_oldstable('oldstable', |
| 661 |
|
params, url) |
| 662 |
|
|
| 663 |
def page_status_release_testing(self, path, params, url): |
def page_status_release_testing(self, path, params, url): |
| 664 |
|
bf = BugFilterNoDSA(params) |
| 665 |
|
|
| 666 |
def gen(): |
def gen(): |
| 667 |
old_pkg_name = '' |
old_pkg_name = '' |
| 668 |
for (pkg_name, bug_name, archive, urgency, |
for (pkg_name, bug_name, archive, urgency, |
| 669 |
sid_vulnerable, ts_fixed, remote) in self.db.cursor().execute( |
sid_vulnerable, ts_fixed, remote, no_dsa) \ |
| 670 |
|
in self.db.cursor().execute( |
| 671 |
"""SELECT package, bug, section, urgency, unstable_vulnerable, |
"""SELECT package, bug, section, urgency, unstable_vulnerable, |
| 672 |
testing_security_fixed, remote |
testing_security_fixed, remote, no_dsa |
| 673 |
FROM testing_status"""): |
FROM testing_status"""): |
| 674 |
|
if bf.urgencyFiltered(urgency): |
| 675 |
|
continue |
| 676 |
|
if bf.remoteFiltered(remote): |
| 677 |
|
continue |
| 678 |
|
if bf.nodsaFiltered(no_dsa): |
| 679 |
|
continue |
| 680 |
|
|
| 681 |
if pkg_name == old_pkg_name: |
if pkg_name == old_pkg_name: |
| 682 |
pkg_name = '' |
pkg_name = '' |
| 683 |
else: |
else: |
| 710 |
url, 'Vulnerable source packages in the testing suite', |
url, 'Vulnerable source packages in the testing suite', |
| 711 |
[make_menu(url.scriptRelative, |
[make_menu(url.scriptRelative, |
| 712 |
("status/dtsa-candidates", "Candidates for DTSAs")), |
("status/dtsa-candidates", "Candidates for DTSAs")), |
| 713 |
|
bf.actions(url), |
| 714 |
make_table(gen(), caption=("Package", "Bug", "Urgency", |
make_table(gen(), caption=("Package", "Bug", "Urgency", |
| 715 |
"Remote"))]) |
"Remote"))]) |
| 716 |
|
|
| 717 |
def page_status_release_unstable(self, path, params, url): |
def page_status_release_unstable_like(self, path, params, url, |
| 718 |
|
rel, title): |
| 719 |
|
bf = BugFilter(params) |
| 720 |
|
|
| 721 |
def gen(): |
def gen(): |
| 722 |
old_pkg_name = '' |
old_pkg_name = '' |
| 723 |
for (pkg_name, bug_name, section, urgency) \ |
for (pkg_name, bug_name, section, urgency, remote) \ |
| 724 |
in self.db.cursor().execute( |
in self.db.cursor().execute( |
| 725 |
"""SELECT DISTINCT sp.name, st.bug_name, |
"""SELECT DISTINCT sp.name, st.bug_name, |
| 726 |
sp.archive, st.urgency |
sp.archive, st.urgency, |
| 727 |
|
(SELECT range_remote FROM nvd_data |
| 728 |
|
WHERE cve_name = st.bug_name) |
| 729 |
FROM source_package_status AS st, source_packages AS sp |
FROM source_package_status AS st, source_packages AS sp |
| 730 |
WHERE st.vulnerable AND st.urgency <> 'unimportant' |
WHERE st.vulnerable AND st.urgency <> 'unimportant' |
| 731 |
AND sp.rowid = st.package AND sp.release = 'sid' |
AND sp.rowid = st.package AND sp.release = ? |
| 732 |
AND sp.subrelease = '' |
AND sp.subrelease = '' |
| 733 |
ORDER BY sp.name, st.bug_name"""): |
ORDER BY sp.name, st.bug_name""", (rel,)): |
| 734 |
|
if bf.urgencyFiltered(urgency): |
| 735 |
|
continue |
| 736 |
|
if bf.remoteFiltered(remote): |
| 737 |
|
continue |
| 738 |
|
|
| 739 |
if pkg_name == old_pkg_name: |
if pkg_name == old_pkg_name: |
| 740 |
pkg_name = '' |
pkg_name = '' |
| 741 |
else: |
else: |
| 745 |
else: |
else: |
| 746 |
pkg_name = self.make_xref(url, pkg_name) |
pkg_name = self.make_xref(url, pkg_name) |
| 747 |
|
|
| 748 |
|
if remote is None: |
| 749 |
|
remote = '' |
| 750 |
|
elif remote: |
| 751 |
|
remote = 'yes' |
| 752 |
|
else: |
| 753 |
|
remote = 'no' |
| 754 |
|
|
| 755 |
if urgency == 'unknown': |
if urgency == 'unknown': |
| 756 |
urgency = '' |
urgency = '' |
| 757 |
elif urgency == 'high': |
elif urgency == 'high': |
| 758 |
urgency = self.make_red(urgency) |
urgency = self.make_red(urgency) |
| 759 |
|
|
| 760 |
yield pkg_name, self.make_xref(url, bug_name), urgency |
yield pkg_name, self.make_xref(url, bug_name), urgency, remote |
|
|
|
|
|
|
| 761 |
return self.create_page( |
return self.create_page( |
| 762 |
url, 'Vulnerable source packages in the testing suite', |
url, title, |
| 763 |
[P("""Note that the list below is based on source packages. |
[P("""Note that the list below is based on source packages. |
| 764 |
This means that packages are not listed here once a new, |
This means that packages are not listed here once a new, |
| 765 |
fixed source version has been uploaded to the archive, even |
fixed source version has been uploaded to the archive, even |
| 766 |
if there are still some vulnerably binary packages present |
if there are still some vulnerably binary packages present |
| 767 |
in the archive."""), |
in the archive."""), |
| 768 |
make_table(gen(), caption=('Package', 'Bug', 'Urgency'))]) |
bf.actions(url), |
| 769 |
|
make_table(gen(), caption=('Package', 'Bug', 'Urgency', |
| 770 |
|
'Remote'))]) |
| 771 |
|
|
| 772 |
|
def page_status_release_unstable(self, path, params, url): |
| 773 |
|
return self.page_status_release_unstable_like( |
| 774 |
|
path, params, url, |
| 775 |
|
title='Vulnerable source packages in the unstable suite', |
| 776 |
|
rel='sid') |
| 777 |
|
|
| 778 |
|
def page_status_release_stable_backports(self, path, params, url): |
| 779 |
|
return self.page_status_release_unstable_like( |
| 780 |
|
path, params, url, |
| 781 |
|
title='Vulnerable source packages among backports for stable', |
| 782 |
|
rel='lenny-backports') |
| 783 |
|
|
| 784 |
|
def page_status_release_oldstable_backports(self, path, params, url): |
| 785 |
|
return self.page_status_release_unstable_like( |
| 786 |
|
path, params, url, |
| 787 |
|
title='Vulnerable source packages among backports for oldstable', |
| 788 |
|
rel='etch-backports') |
| 789 |
|
|
| 790 |
def page_status_dtsa_candidates(self, path, params, url): |
def page_status_dtsa_candidates(self, path, params, url): |
| 791 |
|
bf = BugFilter(params) |
| 792 |
|
|
| 793 |
def gen(): |
def gen(): |
| 794 |
old_pkg_name = '' |
old_pkg_name = '' |
| 795 |
for (pkg_name, bug_name, archive, urgency, stable_later) \ |
for (pkg_name, bug_name, archive, urgency, stable_later, |
| 796 |
|
remote) \ |
| 797 |
in self.db.cursor().execute( |
in self.db.cursor().execute( |
| 798 |
"""SELECT package, bug, section, urgency, |
"""SELECT package, bug, section, urgency, |
| 799 |
(SELECT testing.version_id < stable.version_id |
(SELECT testing.version_id < stable.version_id |
| 800 |
FROM source_packages AS testing, source_packages AS stable |
FROM source_packages AS testing, source_packages AS stable |
| 801 |
WHERE testing.name = testing_status.package |
WHERE testing.name = testing_status.package |
| 802 |
AND testing.release = 'etch' |
AND testing.release = 'squeeze' |
| 803 |
AND testing.subrelease = '' |
AND testing.subrelease = '' |
| 804 |
AND testing.archive = testing_status.section |
AND testing.archive = testing_status.section |
| 805 |
AND stable.name = testing_status.package |
AND stable.name = testing_status.package |
| 806 |
AND stable.release = 'sarge' |
AND stable.release = 'lenny' |
| 807 |
AND stable.subrelease = 'security' |
AND stable.subrelease = 'security' |
| 808 |
AND stable.archive = testing_status.section) |
AND stable.archive = testing_status.section), |
| 809 |
|
(SELECT range_remote FROM nvd_data |
| 810 |
|
WHERE cve_name = bug) |
| 811 |
FROM testing_status |
FROM testing_status |
| 812 |
WHERE (NOT unstable_vulnerable) |
WHERE (NOT unstable_vulnerable) |
| 813 |
AND (NOT testing_security_fixed)"""): |
AND (NOT testing_security_fixed)"""): |
| 814 |
|
if bf.urgencyFiltered(urgency): |
| 815 |
|
continue |
| 816 |
|
if bf.remoteFiltered(remote): |
| 817 |
|
continue |
| 818 |
|
|
| 819 |
if pkg_name == old_pkg_name: |
if pkg_name == old_pkg_name: |
| 820 |
pkg_name = '' |
pkg_name = '' |
| 821 |
migration = '' |
migration = '' |
| 828 |
else: |
else: |
| 829 |
pkg_name = self.make_source_package_ref(url, pkg_name) |
pkg_name = self.make_source_package_ref(url, pkg_name) |
| 830 |
|
|
| 831 |
|
if remote is None: |
| 832 |
|
remote = '' |
| 833 |
|
elif remote: |
| 834 |
|
remote = 'yes' |
| 835 |
|
else: |
| 836 |
|
remote = 'no' |
| 837 |
|
|
| 838 |
if urgency == 'unknown': |
if urgency == 'unknown': |
| 839 |
urgency = '' |
urgency = '' |
| 840 |
elif urgency == 'high': |
elif urgency == 'high': |
| 846 |
notes = '' |
notes = '' |
| 847 |
|
|
| 848 |
yield (pkg_name, migration, self.make_xref(url, bug_name), |
yield (pkg_name, migration, self.make_xref(url, bug_name), |
| 849 |
urgency, notes) |
urgency, remote, notes) |
| 850 |
|
|
| 851 |
return self.create_page( |
return self.create_page( |
| 852 |
url, "Candidates for DTSAs", |
url, "Candidates for DTSAs", |
| 853 |
[P("""The table below lists packages which are fixed |
[P("""The table below lists packages which are fixed |
| 854 |
in unstable, but unfixed in testing. Use the testing migration |
in unstable, but unfixed in testing. Use the testing migration |
| 855 |
return web_supporttracker to find out why they have not entered |
checker to find out why they have not entered testing yet."""), |
|
return web_supporttesting yet."""), |
|
| 856 |
make_menu(url.scriptRelative, |
make_menu(url.scriptRelative, |
| 857 |
("status/release/testing", |
("status/release/testing", |
| 858 |
"List of vulnerable packages in testing")), |
"List of vulnerable packages in testing")), |
| 859 |
|
bf.actions(url), |
| 860 |
make_table(gen(), |
make_table(gen(), |
| 861 |
caption=("Package", "Migration", "Bug", "Urgency"))]) |
caption=("Package", "Migration", "Bug", "Urgency", |
| 862 |
|
"Remote"))]) |
| 863 |
|
|
| 864 |
def page_status_todo(self, path, params, url): |
def page_status_todo(self, path, params, url): |
| 865 |
|
hide_check = params.get('hide_check', False) |
| 866 |
|
if hide_check: |
| 867 |
|
flags = A(url.updateParamsDict({'hide_check' : None}), |
| 868 |
|
'Show "check" TODOs') |
| 869 |
|
else: |
| 870 |
|
flags = A(url.updateParamsDict({'hide_check' : '1'}), |
| 871 |
|
'Hide "check" TODOs') |
| 872 |
|
|
| 873 |
def gen(): |
def gen(): |
| 874 |
for (bug, description) in self.db.getTODOs(): |
for (bug, description) in self.db.getTODOs(hide_check=hide_check): |
| 875 |
yield self.make_xref(url, bug), description |
yield self.make_xref(url, bug), description |
| 876 |
return self.create_page( |
return self.create_page( |
| 877 |
url, "Bugs with TODO items", |
url, "Bugs with TODO items", |
| 878 |
[make_table(gen(), |
[P(flags), |
| 879 |
|
make_table(gen(), |
| 880 |
caption=("Bug", "Description"))]) |
caption=("Bug", "Description"))]) |
| 881 |
|
|
| 882 |
def page_status_itp(self, path, params, url): |
def page_status_itp(self, path, params, url): |
| 902 |
url, "Unknown packages", |
url, "Unknown packages", |
| 903 |
[P("""Sometimes, a package referenced in a bug report |
[P("""Sometimes, a package referenced in a bug report |
| 904 |
cannot be found in the database. This can be the result of a spelling |
cannot be found in the database. This can be the result of a spelling |
| 905 |
return web_supporterror, or a historic entry refers to a |
error, or a historic entry refers to a |
| 906 |
return web_supportpackage which is no longer in the archive."""), |
package which is no longer in the archive."""), |
| 907 |
make_table(gen(), caption=("Package", "Bugs"), |
make_table(gen(), caption=("Package", "Bugs"), |
| 908 |
replacement="No unknown packages are referenced in the database.")]) |
replacement="No unknown packages are referenced in the database.")]) |
| 909 |
|
|
| 941 |
caption=("Bug", "Package", "Version 1", "Version 2"), |
caption=("Bug", "Package", "Version 1", "Version 2"), |
| 942 |
replacement="No source package version with missing epochs.")]) |
replacement="No source package version with missing epochs.")]) |
| 943 |
|
|
| 944 |
|
def page_data_latently_vulnerable(self, path, params, url): |
| 945 |
|
def gen(): |
| 946 |
|
for pkg, bugs in self.db.cursor().execute( |
| 947 |
|
"""SELECT package, string_set(bug_name) |
| 948 |
|
FROM package_notes AS p1 |
| 949 |
|
WHERE release <> '' |
| 950 |
|
AND (bug_name LIKE 'CVE-%' OR bug_name LIKE 'TEMP-%') |
| 951 |
|
AND NOT EXISTS (SELECT 1 FROM package_notes AS p2 |
| 952 |
|
WHERE p2.bug_name = p1.bug_name |
| 953 |
|
AND p2.package = p1.package |
| 954 |
|
AND release = '') |
| 955 |
|
AND EXISTS (SELECT 1 FROM source_packages |
| 956 |
|
WHERE name = p1.package AND release = 'sid') |
| 957 |
|
GROUP BY package |
| 958 |
|
ORDER BY package"""): |
| 959 |
|
pkg = self.make_source_package_ref(url, pkg) |
| 960 |
|
bugs = bugs.split(',') |
| 961 |
|
yield pkg, self.make_xref_list(url, bugs) |
| 962 |
|
|
| 963 |
|
def gen_unimportant(): |
| 964 |
|
for pkg, bugs in self.db.cursor().execute( |
| 965 |
|
"""SELECT package, string_set(bug_name) |
| 966 |
|
FROM package_notes AS p1 |
| 967 |
|
WHERE release <> '' |
| 968 |
|
AND urgency <> 'unimportant' |
| 969 |
|
AND (bug_name LIKE 'CVE-%' OR bug_name LIKE 'TEMP-%') |
| 970 |
|
AND EXISTS (SELECT 1 FROM package_notes AS p2 |
| 971 |
|
WHERE p2.bug_name = p1.bug_name |
| 972 |
|
AND p2.package = p1.package |
| 973 |
|
AND release = '') |
| 974 |
|
AND NOT EXISTS (SELECT 1 FROM package_notes AS p2 |
| 975 |
|
WHERE p2.bug_name = p1.bug_name |
| 976 |
|
AND p2.package = p1.package |
| 977 |
|
AND urgency <> 'unimportant' |
| 978 |
|
AND release = '') |
| 979 |
|
AND EXISTS (SELECT 1 FROM source_packages |
| 980 |
|
WHERE name = p1.package AND release = 'sid') |
| 981 |
|
GROUP BY package |
| 982 |
|
ORDER BY package"""): |
| 983 |
|
pkg = self.make_source_package_ref(url, pkg) |
| 984 |
|
bugs = bugs.split(',') |
| 985 |
|
yield pkg, self.make_xref_list(url, bugs) |
| 986 |
|
|
| 987 |
|
return self.create_page( |
| 988 |
|
url, "Latently vulnerable packages in unstable", |
| 989 |
|
[P( |
| 990 |
|
"""A package is latently vulnerable in unstable if it is vulnerable in |
| 991 |
|
any release, and there is no package note for the same vulnerability |
| 992 |
|
and package in unstable (and the package is still available in |
| 993 |
|
unstable, of course)."""), |
| 994 |
|
make_table(gen(), |
| 995 |
|
caption=("Package", "Bugs"), |
| 996 |
|
replacement="No latently vulnerable packages were found."), |
| 997 |
|
P( |
| 998 |
|
"""The next table lists issues which are marked unimportant for |
| 999 |
|
unstable, but for which release-specific annotations exist which are |
| 1000 |
|
not unimportant."""), |
| 1001 |
|
make_table(gen_unimportant(), |
| 1002 |
|
caption=("Package", "Bugs"), |
| 1003 |
|
replacement= |
| 1004 |
|
"No packages with unimportant latent vulnerabilities were found."), |
| 1005 |
|
]) |
| 1006 |
|
|
| 1007 |
def page_data_releases(self, path, params, url): |
def page_data_releases(self, path, params, url): |
| 1008 |
def gen(): |
def gen(): |
| 1009 |
for (rel, subrel, archive, sources, archs) \ |
for (rel, subrel, archive, sources, archs) \ |
| 1048 |
long as none of the binary packages carries the same name as the |
long as none of the binary packages carries the same name as the |
| 1049 |
source package, most confusion is avoided or can be easily |
source package, most confusion is avoided or can be easily |
| 1050 |
explained.""")]) |
explained.""")]) |
| 1051 |
|
|
| 1052 |
|
def page_data_fake_names(self, path, params, url): |
| 1053 |
|
def gen(): |
| 1054 |
|
for (bug, description) in self.db.getFakeBugs(): |
| 1055 |
|
yield self.make_xref(url, bug), description |
| 1056 |
|
return self.create_page( |
| 1057 |
|
url, "Automatically generated issue names", |
| 1058 |
|
[P("""Some issues have not been assigned CVE names, but are still |
| 1059 |
|
tracked by this database. In this case, the system automatically assigns |
| 1060 |
|
a unique name. These names are not stable and can change when the database |
| 1061 |
|
is updated, so they should not be used in external references."""), |
| 1062 |
|
P('''The automatically generated names come in two flavors: |
| 1063 |
|
the first kind starts with the string "''', CODE("TEMP-000000-"), |
| 1064 |
|
'''". This means that no Debian bug has been assigned to this |
| 1065 |
|
issue (or a bug has been created and is not recorded in this database). |
| 1066 |
|
In the second kind of names, there is a Debian bug for the issue, and the "''', |
| 1067 |
|
CODE("000000"), '''"part of the name is replaced with the |
| 1068 |
|
Debian bug number.'''), |
| 1069 |
|
make_table(gen(), |
| 1070 |
|
caption=("Bug", "Description"))]) |
| 1071 |
|
|
| 1072 |
|
def page_debsecan(self, path, params, url): |
| 1073 |
|
obj = '/'.join(path) |
| 1074 |
|
data = self.db.getDebsecan(obj) |
| 1075 |
|
if data: |
| 1076 |
|
return BinaryResult(data) |
| 1077 |
|
else: |
| 1078 |
|
return self.create_page( |
| 1079 |
|
url, "Object not found", |
| 1080 |
|
[P("The requested debsecan object has not been found.")], |
| 1081 |
|
status=404) |
| 1082 |
|
|
| 1083 |
def create_page(self, url, title, body, search_in_page=False, status=200): |
def create_page(self, url, title, body, search_in_page=False, status=200): |
| 1084 |
append = body.append |
append = body.append |
| 1109 |
onkeyup="onSearch(this.value)", |
onkeyup="onSearch(this.value)", |
| 1110 |
onmousemove="onSearch(this.value)"), |
onmousemove="onSearch(this.value)"), |
| 1111 |
INPUT(type='submit', value='Go'), |
INPUT(type='submit', value='Go'), |
| 1112 |
|
' ', |
| 1113 |
|
A(url.scriptRelative("data/report"), "Reporting problems"), |
| 1114 |
method='get', |
method='get', |
| 1115 |
action=url.scriptRelative('')) |
action=url.scriptRelative('')) |
| 1116 |
|
|
| 1118 |
return url.absolute("http://cve.mitre.org/cgi-bin/cvename.cgi", |
return url.absolute("http://cve.mitre.org/cgi-bin/cvename.cgi", |
| 1119 |
name=name) |
name=name) |
| 1120 |
def url_nvd(self, url, name): |
def url_nvd(self, url, name): |
| 1121 |
return url.absolute("http://nvd.nist.gov/nvd.cfm", |
return url.absolute("http://web.nvd.nist.gov/view/vuln/detail", |
| 1122 |
cvename=name) |
vulnId=name) |
| 1123 |
|
|
| 1124 |
def url_dsa(self, url, dsa, re_dsa=re.compile(r'^DSA-(\d+)(?:-\d+)?$')): |
def url_dsa(self, url, dsa, re_dsa=re.compile(r'^DSA-(\d+)(?:-\d+)?$')): |
| 1125 |
match = re_dsa.match(dsa) |
match = re_dsa.match(dsa) |
| 1143 |
return url.absolute("http://packages.qa.debian.org/common/index.html", |
return url.absolute("http://packages.qa.debian.org/common/index.html", |
| 1144 |
src=package) |
src=package) |
| 1145 |
def url_testing_status(self, url, package): |
def url_testing_status(self, url, package): |
| 1146 |
return url.absolute("http://bjorn.haxx.se/debian/testing.pl", |
return url.absolute("http://release.debian.org/migration/testing.pl", |
| 1147 |
package=package) |
package=package) |
| 1148 |
def url_source_package(self, url, package, full=False): |
def url_source_package(self, url, package, full=False): |
| 1149 |
if full: |
if full: |