Merge lp:~stevenk/launchpad/sanity-check-bugwatch-bug-id into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 16116
Proposed branch: lp:~stevenk/launchpad/sanity-check-bugwatch-bug-id
Merge into: lp:launchpad
Diff against target: 186 lines (+31/-19)
4 files modified
lib/lp/bugs/interfaces/bugtracker.py (+1/-3)
lib/lp/bugs/interfaces/bugwatch.py (+1/-3)
lib/lp/bugs/model/bugwatch.py (+15/-12)
lib/lp/bugs/tests/test_bugwatch.py (+14/-1)
To merge this branch: bzr merge lp:~stevenk/launchpad/sanity-check-bugwatch-bug-id
Reviewer Review Type Date Requested Status
Ian Booth (community) Approve
Review via email: mp+128625@code.launchpad.net

Commit message

Change the parsing methods that check if a remote URL for a bugwatch is valid to only accept bug numbers that are all digits.

Description of the change

Change the parsing methods that check if a remote URL for a bugwatch is valid. From what I can see, before I started this branch, only debbugs actually gave an error if the bug id supplied is not all digits, and the Trac and RoundUp parsers did something *awesome* and truncated the URL at the first non-digit character.

I think I've sorted it out so all parsers (except the e-mail address parser for obvious reasons) will croak when the remote bug id is not all digits. The LoC count can come off my something like -1000 count, but I have removed the pylint garbage and a comment that didn't add value in the slightest.

To post a comment you must log in.
Revision history for this message
Ian Booth (wallyworld) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/interfaces/bugtracker.py'
2--- lib/lp/bugs/interfaces/bugtracker.py 2012-01-01 02:58:52 +0000
3+++ lib/lp/bugs/interfaces/bugtracker.py 2012-10-09 06:00:12 +0000
4@@ -1,8 +1,6 @@
5-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
6+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9-# pylint: disable-msg=E0211,E0213
10-
11 """Bug tracker interfaces."""
12
13 __metaclass__ = type
14
15=== modified file 'lib/lp/bugs/interfaces/bugwatch.py'
16--- lib/lp/bugs/interfaces/bugwatch.py 2012-01-01 02:58:52 +0000
17+++ lib/lp/bugs/interfaces/bugwatch.py 2012-10-09 06:00:12 +0000
18@@ -1,8 +1,6 @@
19-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
20+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
21 # GNU Affero General Public License version 3 (see the file LICENSE).
22
23-# pylint: disable-msg=E0211,E0213
24-
25 """Bug watch interfaces."""
26
27 __metaclass__ = type
28
29=== modified file 'lib/lp/bugs/model/bugwatch.py'
30--- lib/lp/bugs/model/bugwatch.py 2012-06-29 08:40:05 +0000
31+++ lib/lp/bugs/model/bugwatch.py 2012-10-09 06:00:12 +0000
32@@ -1,8 +1,6 @@
33 # Copyright 2009-2012 Canonical Ltd. This software is licensed under the
34 # GNU Affero General Public License version 3 (see the file LICENSE).
35
36-# pylint: disable-msg=E0611,W0212
37-
38 __metaclass__ = type
39 __all__ = [
40 'BugWatch',
41@@ -20,7 +18,6 @@
42 from lazr.lifecycle.snapshot import Snapshot
43 from lazr.uri import find_uris_in_text
44 from pytz import utc
45-# SQL imports
46 from sqlobject import (
47 ForeignKey,
48 SQLObjectNotFound,
49@@ -495,6 +492,8 @@
50 remote_bug = query['issue']
51 else:
52 return None
53+ if remote_bug is None or not remote_bug.isdigit():
54+ return None
55 base_path = path[:-len(bug_page)]
56 base_url = urlunsplit((scheme, host, base_path, '', ''))
57 return base_url, remote_bug
58@@ -504,9 +503,8 @@
59 bug_page = 'view.php'
60 if not path.endswith(bug_page):
61 return None
62- if query.get('id'):
63- remote_bug = query['id']
64- else:
65+ remote_bug = query.get('id')
66+ if remote_bug is None or not remote_bug.isdigit():
67 return None
68 base_path = path[:-len(bug_page)]
69 base_url = urlunsplit((scheme, host, base_path, '', ''))
70@@ -539,7 +537,7 @@
71
72 def parseRoundupURL(self, scheme, host, path, query):
73 """Extract the RoundUp base URL and bug ID."""
74- match = re.match(r'(.*/)issue(\d+)', path)
75+ match = re.match(r'(.*/)issue(\d+)$', path)
76 if not match:
77 return None
78 base_path = match.group(1)
79@@ -569,13 +567,15 @@
80
81 base_path = match.group(1)
82 remote_bug = query['id']
83+ if remote_bug is None or not remote_bug.isdigit():
84+ return None
85
86 base_url = urlunsplit((scheme, host, base_path, '', ''))
87 return base_url, remote_bug
88
89 def parseTracURL(self, scheme, host, path, query):
90 """Extract the Trac base URL and bug ID."""
91- match = re.match(r'(.*/)ticket/(\d+)', path)
92+ match = re.match(r'(.*/)ticket/(\d+)$', path)
93 if not match:
94 return None
95 base_path = match.group(1)
96@@ -605,6 +605,8 @@
97 return None
98
99 remote_bug = query['aid']
100+ if remote_bug is None or not remote_bug.isdigit():
101+ return None
102
103 # There's only one global SF instance registered in Launchpad,
104 # so we return that if the hostnames match.
105@@ -638,6 +640,8 @@
106 # a value, so we simply use the first and only key we come
107 # across as a best-effort guess.
108 remote_bug = query.popitem()[0]
109+ if remote_bug is None or not remote_bug.isdigit():
110+ return None
111
112 if host in savannah_hosts:
113 return savannah_tracker.baseurl, remote_bug
114@@ -669,7 +673,7 @@
115 if path != '/bug.php' or len(query) != 1:
116 return None
117 remote_bug = query.get('id')
118- if remote_bug is None:
119+ if remote_bug is None or not remote_bug.isdigit():
120 return None
121 base_url = urlunsplit((scheme, host, '/', '', ''))
122 return base_url, remote_bug
123@@ -687,7 +691,7 @@
124 return None
125
126 remote_bug = query.get('id')
127- if remote_bug is None:
128+ if remote_bug is None or not remote_bug.isdigit():
129 return None
130
131 tracker_path = path_match.groupdict()['base_path']
132@@ -708,9 +712,8 @@
133 if not bugtracker_data:
134 continue
135 base_url, remote_bug = bugtracker_data
136- bugtrackerset = getUtility(IBugTrackerSet)
137 # Check whether we have a registered bug tracker already.
138- bugtracker = bugtrackerset.queryByBaseURL(base_url)
139+ bugtracker = getUtility(IBugTrackerSet).queryByBaseURL(base_url)
140
141 if bugtracker is not None:
142 return bugtracker, remote_bug
143
144=== modified file 'lib/lp/bugs/tests/test_bugwatch.py'
145--- lib/lp/bugs/tests/test_bugwatch.py 2012-08-08 07:23:58 +0000
146+++ lib/lp/bugs/tests/test_bugwatch.py 2012-10-09 06:00:12 +0000
147@@ -1,4 +1,4 @@
148-# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
149+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
150 # GNU Affero General Public License version 3 (see the file LICENSE).
151
152 """Tests for BugWatchSet."""
153@@ -9,6 +9,7 @@
154 datetime,
155 timedelta,
156 )
157+import re
158 import unittest
159 from urlparse import urlunsplit
160
161@@ -122,6 +123,14 @@
162 self.fail(
163 "NoBugTrackerFound wasn't raised by extractBugTrackerAndBug")
164
165+ def test_invalid_bug_number(self):
166+ # Replace the second digit of the remote bug id with an E, which all
167+ # parsers will reject as invalid.
168+ invalid_url = re.sub(r'(\d)\d', r'\1E', self.bug_url, count=1)
169+ self.assertRaises(
170+ UnrecognizedBugTrackerURL,
171+ self.bugwatch_set.extractBugTrackerAndBug, invalid_url)
172+
173
174 class MantisExtractBugTrackerAndBugTest(
175 ExtractBugTrackerAndBugTestBase, unittest.TestCase):
176@@ -339,6 +348,10 @@
177 self.bugwatch_set.extractBugTrackerAndBug,
178 url='this\.is@@a.bad.email.address')
179
180+ def test_invalid_bug_number(self):
181+ # Test does not make sense for email addresses.
182+ pass
183+
184
185 class PHPProjectBugTrackerExtractBugTrackerAndBugTest(
186 ExtractBugTrackerAndBugTestBase, unittest.TestCase):