Merge lp:~cjwatson/launchpad/use-bzr-policy-open into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 19008
Proposed branch: lp:~cjwatson/launchpad/use-bzr-policy-open
Merge into: lp:launchpad
Diff against target: 1498 lines (+107/-835)
17 files modified
constraints.txt (+2/-1)
lib/launchpad_loggerhead/app.py (+2/-2)
lib/lp/code/interfaces/branch.py (+1/-1)
lib/lp/code/model/branch.py (+3/-3)
lib/lp/code/model/tests/test_branch.py (+3/-3)
lib/lp/codehosting/codeimport/tests/test_worker.py (+20/-20)
lib/lp/codehosting/codeimport/worker.py (+13/-13)
lib/lp/codehosting/puller/tests/__init__.py (+1/-1)
lib/lp/codehosting/puller/tests/test_errors.py (+4/-4)
lib/lp/codehosting/puller/tests/test_worker.py (+24/-24)
lib/lp/codehosting/puller/tests/test_worker_formats.py (+2/-2)
lib/lp/codehosting/puller/worker.py (+22/-22)
lib/lp/codehosting/safe_open.py (+0/-354)
lib/lp/codehosting/scanner/tests/test_bzrsync.py (+2/-2)
lib/lp/codehosting/tests/test_safe_open.py (+0/-378)
lib/lp/codehosting/upgrade.py (+7/-4)
scripts/code-import-worker.py (+1/-1)
To merge this branch: bzr merge lp:~cjwatson/launchpad/use-bzr-policy-open
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+368761@code.launchpad.net

Commit message

Use new bzrlib.url_policy_open API for safely opening branches.

Description of the change

Launchpad's safe_open API was fairly generic and has been moved into bzrlib as bzrlib.url_policy_open.

This branch changes Launchpad to use the copy of safe_open that is present in bzrlib, and removes it from Launchpad itself.

This is a resurrection of https://code.launchpad.net/~jelmer/launchpad/use-bzr-policy-open/+merge/112529, updated to current Launchpad and with some bugs fixed.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'constraints.txt'
2--- constraints.txt 2019-06-18 16:52:56 +0000
3+++ constraints.txt 2019-07-09 12:34:22 +0000
4@@ -234,7 +234,8 @@
5 beautifulsoup4[lxml]==4.7.1
6 billiard==3.5.0.5
7 bson==0.3.3
8-bzr==2.6.0.lp.3
9+# lp:~launchpad/bzr/lp
10+bzr==2.6.0.lp.4
11 celery==4.1.1
12 certifi==2019.3.9
13 cffi==1.11.2
14
15=== modified file 'lib/launchpad_loggerhead/app.py'
16--- lib/launchpad_loggerhead/app.py 2018-05-16 14:38:22 +0000
17+++ lib/launchpad_loggerhead/app.py 2019-07-09 12:34:22 +0000
18@@ -14,6 +14,7 @@
19 urlutils,
20 )
21 from bzrlib.transport import get_transport
22+from bzrlib.url_policy_open import open_only_scheme
23 from loggerhead.apps import (
24 favicon_app,
25 static_app,
26@@ -47,7 +48,6 @@
27 LAUNCHPAD_ANONYMOUS,
28 LAUNCHPAD_SERVICES,
29 )
30-from lp.codehosting.safe_open import safe_open
31 from lp.codehosting.vfs import get_lp_server
32 from lp.services.config import config
33 from lp.services.webapp.errorlog import ErrorReportingUtility
34@@ -275,7 +275,7 @@
35 self.log.info("Branch is public")
36
37 try:
38- bzr_branch = safe_open(
39+ bzr_branch = open_only_scheme(
40 lp_server.get_url().strip(':/'), branch_url)
41 except errors.NotBranchError as err:
42 self.log.warning('Not a branch: %s', err)
43
44=== modified file 'lib/lp/code/interfaces/branch.py'
45--- lib/lp/code/interfaces/branch.py 2019-04-17 12:03:22 +0000
46+++ lib/lp/code/interfaces/branch.py 2019-07-09 12:34:22 +0000
47@@ -1012,7 +1012,7 @@
48 You can only call this if a server returned by `get_ro_server` or
49 `get_rw_server` is running.
50
51- :raise lp.codehosting.safe_open.BadUrl: If the branch is stacked
52+ :raise bzrlib.url_policy_open.BadUrl: If the branch is stacked
53 on or a reference to an unacceptable URL.
54 """
55
56
57=== modified file 'lib/lp/code/model/branch.py'
58--- lib/lp/code/model/branch.py 2019-04-17 10:34:13 +0000
59+++ lib/lp/code/model/branch.py 2019-07-09 12:34:22 +0000
60@@ -16,6 +16,7 @@
61
62 from bzrlib import urlutils
63 from bzrlib.revision import NULL_REVISION
64+from bzrlib.url_policy_open import open_only_scheme
65 from lazr.lifecycle.event import ObjectCreatedEvent
66 import pytz
67 import six
68@@ -138,7 +139,6 @@
69 RevisionAuthor,
70 )
71 from lp.code.model.seriessourcepackagebranch import SeriesSourcePackageBranch
72-from lp.codehosting.safe_open import safe_open
73 from lp.registry.enums import PersonVisibility
74 from lp.registry.errors import CannotChangeInformationType
75 from lp.registry.interfaces.accesspolicy import (
76@@ -733,11 +733,11 @@
77
78 def getInternalBzrUrl(self):
79 """See `IBranch`."""
80- return 'lp-internal:///' + self.unique_name
81+ return six.ensure_str('lp-internal:///' + self.unique_name)
82
83 def getBzrBranch(self):
84 """See `IBranch`."""
85- return safe_open('lp-internal', self.getInternalBzrUrl())
86+ return open_only_scheme('lp-internal', self.getInternalBzrUrl())
87
88 @property
89 def display_name(self):
90
91=== modified file 'lib/lp/code/model/tests/test_branch.py'
92--- lib/lp/code/model/tests/test_branch.py 2019-05-22 14:57:45 +0000
93+++ lib/lp/code/model/tests/test_branch.py 2019-07-09 12:34:22 +0000
94@@ -16,6 +16,7 @@
95 from bzrlib.branch import Branch
96 from bzrlib.bzrdir import BzrDir
97 from bzrlib.revision import NULL_REVISION
98+from bzrlib.url_policy_open import BadUrl
99 from pytz import UTC
100 from sqlobject import SQLObjectNotFound
101 from storm.exceptions import LostObjectError
102@@ -116,7 +117,6 @@
103 add_revision_to_branch,
104 BranchHostingFixture,
105 )
106-from lp.codehosting.safe_open import BadUrl
107 from lp.codehosting.vfs.branchfs import get_real_branch_path
108 from lp.registry.enums import (
109 BranchSharingPolicy,
110@@ -3271,7 +3271,7 @@
111 self.useBzrBranches(direct_database=True)
112
113 def test_simple(self):
114- # safe_open returns the underlying bzr branch of a database branch in
115+ # open_only_scheme returns the underlying bzr branch of a database branch in
116 # the simple, unstacked, case.
117 db_branch, tree = self.create_branch_and_tree()
118 # XXX: AaronBentley 2010-08-06 bug=614404: a bzr username is
119@@ -3283,7 +3283,7 @@
120
121 def test_acceptable_stacking(self):
122 # If the underlying bzr branch of a database branch is stacked on
123- # another launchpad branch safe_open returns it.
124+ # another launchpad branch open_only_scheme returns it.
125 db_stacked_on, stacked_on_tree = self.create_branch_and_tree()
126 db_stacked, stacked_tree = self.create_branch_and_tree()
127 stacked_tree.branch.set_stacked_on_url(
128
129=== modified file 'lib/lp/codehosting/codeimport/tests/test_worker.py'
130--- lib/lp/codehosting/codeimport/tests/test_worker.py 2019-05-22 14:57:45 +0000
131+++ lib/lp/codehosting/codeimport/tests/test_worker.py 2019-07-09 12:34:22 +0000
132@@ -36,6 +36,13 @@
133 get_transport,
134 get_transport_from_url,
135 )
136+from bzrlib.url_policy_open import (
137+ _BlacklistPolicy,
138+ AcceptAnythingPolicy,
139+ BadUrl,
140+ BranchOpener,
141+ BranchOpenPolicy,
142+ )
143 from bzrlib.urlutils import (
144 join as urljoin,
145 local_path_from_url,
146@@ -76,13 +83,6 @@
147 ImportDataStore,
148 ToBzrImportWorker,
149 )
150-from lp.codehosting.safe_open import (
151- AcceptAnythingPolicy,
152- BadUrl,
153- BlacklistPolicy,
154- BranchOpenPolicy,
155- SafeBranchOpener,
156- )
157 from lp.codehosting.tests.helpers import create_branch_with_one_revision
158 from lp.services.config import config
159 from lp.services.log.logger import BufferLogger
160@@ -129,7 +129,7 @@
161 def setUp(self):
162 super(WorkerTest, self).setUp()
163 self.disable_directory_isolation()
164- SafeBranchOpener.install_hook()
165+ BranchOpener.install_hook()
166
167 def assertDirectoryTreesEqual(self, directory1, directory2):
168 """Assert that `directory1` has the same structure as `directory2`.
169@@ -1242,7 +1242,7 @@
170 cache_dir = get_cache(uuid).create_cache_dir()
171 cache_dir_contents = os.listdir(cache_dir)
172 self.assertNotEqual([], cache_dir_contents)
173- opener = SafeBranchOpener(worker._opener_policy, worker.probers)
174+ opener = BranchOpener(worker._opener_policy, worker.probers)
175 remote_branch = opener.open(worker.source_details.url)
176 worker.pushBazaarBranch(
177 self.make_branch('.'), remote_branch=remote_branch)
178@@ -1331,7 +1331,7 @@
179 reference_url, target_url = self.createBranchReference()
180 source_details = self.factory.makeCodeImportSourceDetails(
181 url=reference_url, rcstype='bzr')
182- policy = BlacklistPolicy(True, [target_url])
183+ policy = _BlacklistPolicy(True, [target_url])
184 worker = self.makeImportWorker(source_details, opener_policy=policy)
185 self.assertEqual(
186 CodeImportWorkerExitCode.FAILURE_FORBIDDEN, worker.run())
187@@ -1363,15 +1363,15 @@
188 self.policy = CodeImportBranchOpenPolicy("bzr", "bzr")
189
190 def test_follows_references(self):
191- self.assertEqual(True, self.policy.shouldFollowReferences())
192+ self.assertEqual(True, self.policy.should_follow_references())
193
194 def assertBadUrl(self, url):
195- self.assertRaises(BadUrl, self.policy.checkOneURL, url)
196+ self.assertRaises(BadUrl, self.policy.check_one_url, url)
197
198 def assertGoodUrl(self, url):
199- self.policy.checkOneURL(url)
200+ self.policy.check_one_url(url)
201
202- def test_checkOneURL(self):
203+ def test_check_one_url(self):
204 self.assertBadUrl("sftp://somehost/")
205 self.assertBadUrl("/etc/passwd")
206 self.assertBadUrl("file:///etc/passwd")
207@@ -1384,7 +1384,7 @@
208 self.assertGoodUrl("bzr://bzr.example.com/somebzrurl/")
209 self.assertBadUrl("bzr://bazaar.launchpad.test/example")
210
211- def test_checkOneURL_git_to_bzr(self):
212+ def test_check_one_url_git_to_bzr(self):
213 self.policy = CodeImportBranchOpenPolicy("git", "bzr")
214 self.assertBadUrl("/etc/passwd")
215 self.assertBadUrl("file:///etc/passwd")
216@@ -1392,7 +1392,7 @@
217 self.assertGoodUrl("git://git.example.com/repo")
218 self.assertGoodUrl("git://git.launchpad.test/example")
219
220- def test_checkOneURL_git_to_git(self):
221+ def test_check_one_url_git_to_git(self):
222 self.policy = CodeImportBranchOpenPolicy("git", "git")
223 self.assertBadUrl("/etc/passwd")
224 self.assertBadUrl("file:///etc/passwd")
225@@ -1408,7 +1408,7 @@
226 def setUp(self):
227 http_utils.TestCaseWithRedirectedWebserver.setUp(self)
228 self.disable_directory_isolation()
229- SafeBranchOpener.install_hook()
230+ BranchOpener.install_hook()
231 tree = self.make_branch_and_tree('.')
232 self.revid = tree.commit("A commit")
233 self.bazaar_store = BazaarBranchStore(
234@@ -1438,14 +1438,14 @@
235 def __init__(self, new_url):
236 self.new_url = new_url
237
238- def shouldFollowReferences(self):
239+ def should_follow_references(self):
240 return True
241
242- def checkOneURL(self, url):
243+ def check_one_url(self, url):
244 if url.startswith(self.new_url):
245 raise BadUrl(url)
246
247- def transformFallbackLocation(self, branch, url):
248+ def transform_fallback_location(self, branch, url):
249 return urlutils.join(branch.base, url), False
250
251 policy = NewUrlBlacklistPolicy(self.get_new_url())
252
253=== modified file 'lib/lp/codehosting/codeimport/worker.py'
254--- lib/lp/codehosting/codeimport/worker.py 2019-06-14 14:26:30 +0000
255+++ lib/lp/codehosting/codeimport/worker.py 2019-07-09 12:34:22 +0000
256@@ -55,6 +55,11 @@
257 )
258 import bzrlib.ui
259 from bzrlib.upgrade import upgrade
260+from bzrlib.url_policy_open import (
261+ BadUrl,
262+ BranchOpener,
263+ BranchOpenPolicy,
264+ )
265 from bzrlib.urlutils import (
266 join as urljoin,
267 local_path_from_url,
268@@ -81,11 +86,6 @@
269 extract_tarball,
270 )
271 from lp.codehosting.codeimport.uifactory import LoggingUIFactory
272-from lp.codehosting.safe_open import (
273- BadUrl,
274- BranchOpenPolicy,
275- SafeBranchOpener,
276- )
277 from lp.services.config import config
278 from lp.services.propertycache import cachedproperty
279 from lp.services.timeout import (
280@@ -111,8 +111,8 @@
281 self.rcstype = rcstype
282 self.target_rcstype = target_rcstype
283
284- def shouldFollowReferences(self):
285- """See `BranchOpenPolicy.shouldFollowReferences`.
286+ def should_follow_references(self):
287+ """See `BranchOpenPolicy.should_follow_references`.
288
289 We traverse branch references for MIRRORED branches because they
290 provide a useful redirection mechanism and we want to be consistent
291@@ -120,16 +120,16 @@
292 """
293 return True
294
295- def transformFallbackLocation(self, branch, url):
296- """See `BranchOpenPolicy.transformFallbackLocation`.
297+ def transform_fallback_location(self, branch, url):
298+ """See `BranchOpenPolicy.transform_fallback_location`.
299
300 For mirrored branches, we stack on whatever the remote branch claims
301 to stack on, but this URL still needs to be checked.
302 """
303 return urljoin(branch.base, url), True
304
305- def checkOneURL(self, url):
306- """See `BranchOpenPolicy.checkOneURL`.
307+ def check_one_url(self, url):
308+ """See `BranchOpenPolicy.check_one_url`.
309
310 We refuse to mirror Bazaar branches from Launchpad, or any branches
311 from a ssh-like or file URL.
312@@ -729,7 +729,7 @@
313 def _doImport(self):
314 self._logger.info("Starting job.")
315 saved_factory = bzrlib.ui.ui_factory
316- opener = SafeBranchOpener(self._opener_policy, self.probers)
317+ opener = BranchOpener(self._opener_policy, self.probers)
318 bzrlib.ui.ui_factory = LoggingUIFactory(logger=self._logger)
319 try:
320 self._logger.info(
321@@ -1049,7 +1049,7 @@
322 def _doImport(self):
323 self._logger.info("Starting job.")
324 try:
325- self._opener_policy.checkOneURL(self.source_details.url)
326+ self._opener_policy.check_one_url(self.source_details.url)
327 except BadUrl as e:
328 self._logger.info("Invalid URL: %s" % e)
329 return CodeImportWorkerExitCode.FAILURE_FORBIDDEN
330
331=== modified file 'lib/lp/codehosting/puller/tests/__init__.py'
332--- lib/lp/codehosting/puller/tests/__init__.py 2012-04-16 23:02:44 +0000
333+++ lib/lp/codehosting/puller/tests/__init__.py 2019-07-09 12:34:22 +0000
334@@ -16,6 +16,7 @@
335 TestingHTTPServer,
336 TestingThreadingHTTPServer,
337 )
338+from bzrlib.url_policy_open import AcceptAnythingPolicy
339
340 from lp.codehosting.puller.worker import (
341 BranchMirrorer,
342@@ -23,7 +24,6 @@
343 PullerWorker,
344 PullerWorkerProtocol,
345 )
346-from lp.codehosting.safe_open import AcceptAnythingPolicy
347 from lp.codehosting.tests.helpers import LoomTestMixin
348 from lp.testing import TestCaseWithFactory
349
350
351=== modified file 'lib/lp/codehosting/puller/tests/test_errors.py'
352--- lib/lp/codehosting/puller/tests/test_errors.py 2019-05-22 14:57:45 +0000
353+++ lib/lp/codehosting/puller/tests/test_errors.py 2019-07-09 12:34:22 +0000
354@@ -18,6 +18,10 @@
355 UnknownFormatError,
356 UnsupportedFormatError,
357 )
358+from bzrlib.url_policy_open import (
359+ BranchLoopError,
360+ BranchReferenceForbidden,
361+ )
362 from lazr.uri import InvalidURIError
363
364 from lp.code.enums import BranchType
365@@ -29,10 +33,6 @@
366 PullerWorker,
367 PullerWorkerProtocol,
368 )
369-from lp.codehosting.safe_open import (
370- BranchLoopError,
371- BranchReferenceForbidden,
372- )
373 from lp.testing import TestCase
374
375
376
377=== modified file 'lib/lp/codehosting/puller/tests/test_worker.py'
378--- lib/lp/codehosting/puller/tests/test_worker.py 2019-05-22 14:57:45 +0000
379+++ lib/lp/codehosting/puller/tests/test_worker.py 2019-07-09 12:34:22 +0000
380@@ -22,6 +22,12 @@
381 TestCaseWithTransport,
382 )
383 from bzrlib.transport import get_transport
384+from bzrlib.url_policy_open import (
385+ AcceptAnythingPolicy,
386+ BadUrl,
387+ BranchOpener,
388+ BranchOpenPolicy,
389+ )
390
391 from lp.code.enums import BranchType
392 from lp.codehosting.puller.tests import (
393@@ -37,14 +43,8 @@
394 install_worker_ui_factory,
395 MirroredBranchPolicy,
396 PullerWorkerProtocol,
397- SafeBranchOpener,
398 WORKER_ACTIVITY_NETWORK,
399 )
400-from lp.codehosting.safe_open import (
401- AcceptAnythingPolicy,
402- BadUrl,
403- BranchOpenPolicy,
404- )
405 from lp.testing import TestCase
406 from lp.testing.factory import (
407 LaunchpadObjectFactory,
408@@ -86,7 +86,7 @@
409
410 def setUp(self):
411 super(TestPullerWorker, self).setUp()
412- SafeBranchOpener.install_hook()
413+ BranchOpener.install_hook()
414
415 def test_mirror_opener_with_stacked_on_url(self):
416 # A PullerWorker for a mirrored branch gets a MirroredBranchPolicy as
417@@ -277,7 +277,7 @@
418
419 def setUp(self):
420 super(TestReferenceOpener, self).setUp()
421- SafeBranchOpener.install_hook()
422+ BranchOpener.install_hook()
423
424 def createBranchReference(self, url):
425 """Create a pure branch reference that points to the specified URL.
426@@ -318,20 +318,20 @@
427 self.assertEqual(opened_branch.base, target_branch.base)
428
429 def testFollowReferenceValue(self):
430- # SafeBranchOpener.followReference gives the reference value for
431+ # BranchOpener.follow_reference gives the reference value for
432 # a branch reference.
433- opener = SafeBranchOpener(BranchOpenPolicy())
434+ opener = BranchOpener(BranchOpenPolicy())
435 reference_value = 'http://example.com/branch'
436 reference_url = self.createBranchReference(reference_value)
437 self.assertEqual(
438- reference_value, opener.followReference(reference_url))
439+ reference_value, opener.follow_reference(reference_url))
440
441 def testFollowReferenceNone(self):
442- # SafeBranchOpener.followReference gives None for a normal branch.
443+ # BranchOpener.follow_reference gives None for a normal branch.
444 self.make_branch('repo')
445 branch_url = self.get_url('repo')
446- opener = SafeBranchOpener(BranchOpenPolicy())
447- self.assertIs(None, opener.followReference(branch_url))
448+ opener = BranchOpener(BranchOpenPolicy())
449+ self.assertIs(None, opener.follow_reference(branch_url))
450
451
452 class TestMirroredBranchPolicy(TestCase):
453@@ -344,44 +344,44 @@
454 def testNoFileURL(self):
455 policy = MirroredBranchPolicy()
456 self.assertRaises(
457- BadUrlScheme, policy.checkOneURL,
458+ BadUrlScheme, policy.check_one_url,
459 self.factory.getUniqueURL(scheme='file'))
460
461 def testNoUnknownSchemeURLs(self):
462 policy = MirroredBranchPolicy()
463 self.assertRaises(
464- BadUrlScheme, policy.checkOneURL,
465+ BadUrlScheme, policy.check_one_url,
466 self.factory.getUniqueURL(scheme='decorator+scheme'))
467
468 def testNoSSHURL(self):
469 policy = MirroredBranchPolicy()
470 self.assertRaises(
471- BadUrlSsh, policy.checkOneURL,
472+ BadUrlSsh, policy.check_one_url,
473 self.factory.getUniqueURL(scheme='bzr+ssh'))
474
475 def testNoSftpURL(self):
476 policy = MirroredBranchPolicy()
477 self.assertRaises(
478- BadUrlSsh, policy.checkOneURL,
479+ BadUrlSsh, policy.check_one_url,
480 self.factory.getUniqueURL(scheme='sftp'))
481
482 def testNoLaunchpadURL(self):
483 policy = MirroredBranchPolicy()
484 self.assertRaises(
485- BadUrlLaunchpad, policy.checkOneURL,
486+ BadUrlLaunchpad, policy.check_one_url,
487 self.factory.getUniqueURL(host='bazaar.launchpad.test'))
488
489 def testNoHTTPSLaunchpadURL(self):
490 policy = MirroredBranchPolicy()
491 self.assertRaises(
492- BadUrlLaunchpad, policy.checkOneURL,
493+ BadUrlLaunchpad, policy.check_one_url,
494 self.factory.getUniqueURL(
495 host='bazaar.launchpad.test', scheme='https'))
496
497 def testNoOtherHostLaunchpadURL(self):
498 policy = MirroredBranchPolicy()
499 self.assertRaises(
500- BadUrlLaunchpad, policy.checkOneURL,
501+ BadUrlLaunchpad, policy.check_one_url,
502 self.factory.getUniqueURL(host='code.launchpad.test'))
503
504 def testLocalhost(self):
505@@ -389,9 +389,9 @@
506 'codehosting', blacklisted_hostnames='localhost,127.0.0.1')
507 policy = MirroredBranchPolicy()
508 localhost_url = self.factory.getUniqueURL(host='localhost')
509- self.assertRaises(BadUrl, policy.checkOneURL, localhost_url)
510+ self.assertRaises(BadUrl, policy.check_one_url, localhost_url)
511 localhost_url = self.factory.getUniqueURL(host='127.0.0.1')
512- self.assertRaises(BadUrl, policy.checkOneURL, localhost_url)
513+ self.assertRaises(BadUrl, policy.check_one_url, localhost_url)
514
515 def test_no_stacked_on_url(self):
516 # By default, a MirroredBranchPolicy does not stack branches.
517@@ -495,7 +495,7 @@
518
519 def setUp(self):
520 super(TestWorkerProgressReporting, self).setUp()
521- SafeBranchOpener.install_hook()
522+ BranchOpener.install_hook()
523 self.saved_factory = bzrlib.ui.ui_factory
524 self.disable_directory_isolation()
525 self.addCleanup(setattr, bzrlib.ui, 'ui_factory', self.saved_factory)
526
527=== modified file 'lib/lp/codehosting/puller/tests/test_worker_formats.py'
528--- lib/lp/codehosting/puller/tests/test_worker_formats.py 2015-09-28 17:38:45 +0000
529+++ lib/lp/codehosting/puller/tests/test_worker_formats.py 2019-07-09 12:34:22 +0000
530@@ -15,10 +15,10 @@
531 from bzrlib.repofmt.knitpack_repo import RepositoryFormatKnitPack5
532 from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
533 from bzrlib.tests.per_repository import TestCaseWithRepository
534+from bzrlib.url_policy_open import BranchOpener
535
536 import lp.codehosting # For bzr plugins.
537 from lp.codehosting.puller.tests import PullerWorkerMixin
538-from lp.codehosting.safe_open import SafeBranchOpener
539 from lp.codehosting.tests.helpers import LoomTestMixin
540
541
542@@ -29,7 +29,7 @@
543 TestCaseWithRepository.setUp(self)
544 # make_bzrdir relies on this being a relative filesystem path.
545 self._source_branch_path = 'source-branch'
546- SafeBranchOpener.install_hook()
547+ BranchOpener.install_hook()
548 self.worker = self.makePullerWorker(
549 self.get_url(self._source_branch_path),
550 self.get_url('dest-path'))
551
552=== modified file 'lib/lp/codehosting/puller/worker.py'
553--- lib/lp/codehosting/puller/worker.py 2012-06-29 08:40:05 +0000
554+++ lib/lp/codehosting/puller/worker.py 2019-07-09 12:34:22 +0000
555@@ -27,6 +27,13 @@
556 from bzrlib.transport import get_transport
557 import bzrlib.ui
558 from bzrlib.ui import SilentUIFactory
559+from bzrlib.url_policy_open import (
560+ BadUrl,
561+ BranchLoopError,
562+ BranchOpener,
563+ BranchOpenPolicy,
564+ BranchReferenceForbidden,
565+ )
566 from lazr.uri import (
567 InvalidURIError,
568 URI,
569@@ -39,13 +46,6 @@
570 from lp.code.enums import BranchType
571 from lp.codehosting.bzrutils import identical_formats
572 from lp.codehosting.puller import get_lock_id_for_branch_id
573-from lp.codehosting.safe_open import (
574- BadUrl,
575- BranchLoopError,
576- BranchOpenPolicy,
577- BranchReferenceForbidden,
578- SafeBranchOpener,
579- )
580 from lp.services.config import config
581 from lp.services.webapp import errorlog
582
583@@ -75,7 +75,7 @@
584 """Found a URL with an untrusted scheme."""
585
586 def __init__(self, scheme, url):
587- BadUrl.__init__(self, scheme, url)
588+ BadUrl.__init__(self, url)
589 self.scheme = scheme
590
591
592@@ -195,7 +195,7 @@
593 """
594 self.policy = policy
595 self.protocol = protocol
596- self.opener = SafeBranchOpener(policy)
597+ self.opener = BranchOpener(policy)
598 if log is not None:
599 self.log = log
600 else:
601@@ -213,7 +213,7 @@
602 URL must point to a writable location.
603 :return: The destination branch.
604 """
605- return self.opener.runWithTransformFallbackLocationHookInstalled(
606+ return self.opener.run_with_transform_fallback_location_hook_installed(
607 self.policy.createDestinationBranch, source_branch,
608 destination_url)
609
610@@ -552,8 +552,8 @@
611 return None
612 return self.stacked_on_url
613
614- def shouldFollowReferences(self):
615- """See `BranchOpenPolicy.shouldFollowReferences`.
616+ def should_follow_references(self):
617+ """See `BranchOpenPolicy.should_follow_references`.
618
619 We traverse branch references for MIRRORED branches because they
620 provide a useful redirection mechanism and we want to be consistent
621@@ -561,16 +561,16 @@
622 """
623 return True
624
625- def transformFallbackLocation(self, branch, url):
626- """See `BranchOpenPolicy.transformFallbackLocation`.
627+ def transform_fallback_location(self, branch, url):
628+ """See `BranchOpenPolicy.transform_fallback_location`.
629
630 For mirrored branches, we stack on whatever the remote branch claims
631 to stack on, but this URL still needs to be checked.
632 """
633 return urlutils.join(branch.base, url), True
634
635- def checkOneURL(self, url):
636- """See `BranchOpenPolicy.checkOneURL`.
637+ def check_one_url(self, url):
638+ """See `BranchOpenPolicy.check_one_url`.
639
640 We refuse to mirror from Launchpad or a ssh-like or file URL.
641 """
642@@ -619,23 +619,23 @@
643 break
644 return Branch.open_from_transport(dest_transport)
645
646- def shouldFollowReferences(self):
647- """See `BranchOpenerPolicy.shouldFollowReferences`.
648+ def should_follow_references(self):
649+ """See `BranchOpenerPolicy.should_follow_references`.
650
651 We do not traverse references for IMPORTED branches because the
652 code-import system should never produce branch references.
653 """
654 return False
655
656- def transformFallbackLocation(self, branch, url):
657- """See `BranchOpenerPolicy.transformFallbackLocation`.
658+ def transform_fallback_location(self, branch, url):
659+ """See `BranchOpenerPolicy.transform_fallback_location`.
660
661 Import branches should not be stacked, ever.
662 """
663 raise AssertionError("Import branch unexpectedly stacked!")
664
665- def checkOneURL(self, url):
666- """See `BranchOpenerPolicy.checkOneURL`.
667+ def check_one_url(self, url):
668+ """See `BranchOpenerPolicy.check_one_url`.
669
670 If the URL we are mirroring from does not start how we expect the pull
671 URLs of import branches to start, something has gone badly wrong, so
672
673=== removed file 'lib/lp/codehosting/safe_open.py'
674--- lib/lp/codehosting/safe_open.py 2012-08-21 17:34:42 +0000
675+++ lib/lp/codehosting/safe_open.py 1970-01-01 00:00:00 +0000
676@@ -1,354 +0,0 @@
677-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
678-# GNU Affero General Public License version 3 (see the file LICENSE).
679-
680-"""Safe branch opening."""
681-
682-__metaclass__ = type
683-
684-import threading
685-
686-from bzrlib import (
687- errors,
688- trace,
689- urlutils,
690- )
691-from bzrlib.branch import Branch
692-from bzrlib.bzrdir import (
693- BzrProber,
694- RemoteBzrProber,
695- )
696-from bzrlib.transport import (
697- do_catching_redirections,
698- get_transport,
699- )
700-from lazr.uri import URI
701-
702-
703-__all__ = [
704- 'AcceptAnythingPolicy',
705- 'BadUrl',
706- 'BlacklistPolicy',
707- 'BranchLoopError',
708- 'BranchOpenPolicy',
709- 'BranchReferenceForbidden',
710- 'SafeBranchOpener',
711- 'WhitelistPolicy',
712- 'safe_open',
713- ]
714-
715-
716-# TODO JelmerVernooij 2011-08-06: This module is generic enough to be
717-# in bzrlib, and may be of use to others. bug=850843
718-
719-# These are the default probers that SafeBranchOpener will try to use,
720-# unless a different set was specified.
721-
722-DEFAULT_PROBERS = [BzrProber, RemoteBzrProber]
723-
724-
725-class BadUrl(Exception):
726- """Tried to access a branch from a bad URL."""
727-
728-
729-class BranchReferenceForbidden(Exception):
730- """Trying to mirror a branch reference and the branch type does not allow
731- references.
732- """
733-
734-
735-class BranchLoopError(Exception):
736- """Encountered a branch cycle.
737-
738- A URL may point to a branch reference or it may point to a stacked branch.
739- In either case, it's possible for there to be a cycle in these references,
740- and this exception is raised when we detect such a cycle.
741- """
742-
743-
744-class BranchOpenPolicy:
745- """Policy on how to open branches.
746-
747- In particular, a policy determines which branches are safe to open by
748- checking their URLs and deciding whether or not to follow branch
749- references.
750- """
751-
752- def shouldFollowReferences(self):
753- """Whether we traverse references when mirroring.
754-
755- Subclasses must override this method.
756-
757- If we encounter a branch reference and this returns false, an error is
758- raised.
759-
760- :returns: A boolean to indicate whether to follow a branch reference.
761- """
762- raise NotImplementedError(self.shouldFollowReferences)
763-
764- def transformFallbackLocation(self, branch, url):
765- """Validate, maybe modify, 'url' to be used as a stacked-on location.
766-
767- :param branch: The branch that is being opened.
768- :param url: The URL that the branch provides for its stacked-on
769- location.
770- :return: (new_url, check) where 'new_url' is the URL of the branch to
771- actually open and 'check' is true if 'new_url' needs to be
772- validated by checkAndFollowBranchReference.
773- """
774- raise NotImplementedError(self.transformFallbackLocation)
775-
776- def checkOneURL(self, url):
777- """Check the safety of the source URL.
778-
779- Subclasses must override this method.
780-
781- :param url: The source URL to check.
782- :raise BadUrl: subclasses are expected to raise this or a subclass
783- when it finds a URL it deems to be unsafe.
784- """
785- raise NotImplementedError(self.checkOneURL)
786-
787-
788-class BlacklistPolicy(BranchOpenPolicy):
789- """Branch policy that forbids certain URLs."""
790-
791- def __init__(self, should_follow_references, unsafe_urls=None):
792- if unsafe_urls is None:
793- unsafe_urls = set()
794- self._unsafe_urls = unsafe_urls
795- self._should_follow_references = should_follow_references
796-
797- def shouldFollowReferences(self):
798- return self._should_follow_references
799-
800- def checkOneURL(self, url):
801- if url in self._unsafe_urls:
802- raise BadUrl(url)
803-
804- def transformFallbackLocation(self, branch, url):
805- """See `BranchOpenPolicy.transformFallbackLocation`.
806-
807- This class is not used for testing our smarter stacking features so we
808- just do the simplest thing: return the URL that would be used anyway
809- and don't check it.
810- """
811- return urlutils.join(branch.base, url), False
812-
813-
814-class AcceptAnythingPolicy(BlacklistPolicy):
815- """Accept anything, to make testing easier."""
816-
817- def __init__(self):
818- super(AcceptAnythingPolicy, self).__init__(True, set())
819-
820-
821-class WhitelistPolicy(BranchOpenPolicy):
822- """Branch policy that only allows certain URLs."""
823-
824- def __init__(self, should_follow_references, allowed_urls=None,
825- check=False):
826- if allowed_urls is None:
827- allowed_urls = []
828- self.allowed_urls = set(url.rstrip('/') for url in allowed_urls)
829- self.check = check
830-
831- def shouldFollowReferences(self):
832- return self._should_follow_references
833-
834- def checkOneURL(self, url):
835- if url.rstrip('/') not in self.allowed_urls:
836- raise BadUrl(url)
837-
838- def transformFallbackLocation(self, branch, url):
839- """See `BranchOpenPolicy.transformFallbackLocation`.
840-
841- Here we return the URL that would be used anyway and optionally check
842- it.
843- """
844- return urlutils.join(branch.base, url), self.check
845-
846-
847-class SingleSchemePolicy(BranchOpenPolicy):
848- """Branch open policy that rejects URLs not on the given scheme."""
849-
850- def __init__(self, allowed_scheme):
851- self.allowed_scheme = allowed_scheme
852-
853- def shouldFollowReferences(self):
854- return True
855-
856- def transformFallbackLocation(self, branch, url):
857- return urlutils.join(branch.base, url), True
858-
859- def checkOneURL(self, url):
860- """Check that `url` is safe to open."""
861- if URI(url).scheme != self.allowed_scheme:
862- raise BadUrl(url)
863-
864-
865-class SafeBranchOpener(object):
866- """Safe branch opener.
867-
868- All locations that are opened (stacked-on branches, references) are
869- checked against a policy object.
870-
871- The policy object is expected to have the following methods:
872- * checkOneURL
873- * shouldFollowReferences
874- * transformFallbackLocation
875- """
876-
877- _threading_data = threading.local()
878-
879- def __init__(self, policy, probers=None):
880- """Create a new SafeBranchOpener.
881-
882- :param policy: The opener policy to use.
883- :param probers: Optional list of probers to allow.
884- Defaults to local and remote bzr probers.
885- """
886- self.policy = policy
887- self._seen_urls = set()
888- if probers is None:
889- self.probers = list(DEFAULT_PROBERS)
890- else:
891- self.probers = probers
892-
893- @classmethod
894- def install_hook(cls):
895- """Install the ``transformFallbackLocation`` hook.
896-
897- This is done at module import time, but transformFallbackLocationHook
898- doesn't do anything unless the `_active_openers` threading.Local
899- object has a 'opener' attribute in this thread.
900-
901- This is in a module-level function rather than performed at module
902- level so that it can be called in setUp for testing `SafeBranchOpener`
903- as bzrlib.tests.TestCase.setUp clears hooks.
904- """
905- Branch.hooks.install_named_hook(
906- 'transform_fallback_location',
907- cls.transformFallbackLocationHook,
908- 'SafeBranchOpener.transformFallbackLocationHook')
909-
910- def checkAndFollowBranchReference(self, url):
911- """Check URL (and possibly the referenced URL) for safety.
912-
913- This method checks that `url` passes the policy's `checkOneURL`
914- method, and if `url` refers to a branch reference, it checks whether
915- references are allowed and whether the reference's URL passes muster
916- also -- recursively, until a real branch is found.
917-
918- :param url: URL to check
919- :raise BranchLoopError: If the branch references form a loop.
920- :raise BranchReferenceForbidden: If this opener forbids branch
921- references.
922- """
923- while True:
924- if url in self._seen_urls:
925- raise BranchLoopError()
926- self._seen_urls.add(url)
927- self.policy.checkOneURL(url)
928- next_url = self.followReference(url)
929- if next_url is None:
930- return url
931- url = next_url
932- if not self.policy.shouldFollowReferences():
933- raise BranchReferenceForbidden(url)
934-
935- @classmethod
936- def transformFallbackLocationHook(cls, branch, url):
937- """Installed as the 'transform_fallback_location' Branch hook.
938-
939- This method calls `transformFallbackLocation` on the policy object and
940- either returns the url it provides or passes it back to
941- checkAndFollowBranchReference.
942- """
943- try:
944- opener = getattr(cls._threading_data, "opener")
945- except AttributeError:
946- return url
947- new_url, check = opener.policy.transformFallbackLocation(branch, url)
948- if check:
949- return opener.checkAndFollowBranchReference(new_url)
950- else:
951- return new_url
952-
953- def runWithTransformFallbackLocationHookInstalled(
954- self, callable, *args, **kw):
955- assert (self.transformFallbackLocationHook in
956- Branch.hooks['transform_fallback_location'])
957- self._threading_data.opener = self
958- try:
959- return callable(*args, **kw)
960- finally:
961- del self._threading_data.opener
962- # We reset _seen_urls here to avoid multiple calls to open giving
963- # spurious loop exceptions.
964- self._seen_urls = set()
965-
966- def followReference(self, url):
967- """Get the branch-reference value at the specified url.
968-
969- This exists as a separate method only to be overridden in unit tests.
970- """
971- bzrdir = self._open_dir(url)
972- return bzrdir.get_branch_reference()
973-
974- def _open_dir(self, url):
975- """Simple BzrDir.open clone that only uses specific probers.
976-
977- :param url: URL to open
978- :return: ControlDir instance
979- """
980- def redirected(transport, e, redirection_notice):
981- self.policy.checkOneURL(e.target)
982- redirected_transport = transport._redirected_to(
983- e.source, e.target)
984- if redirected_transport is None:
985- raise errors.NotBranchError(e.source)
986- trace.note('%s is%s redirected to %s',
987- transport.base, e.permanently, redirected_transport.base)
988- return redirected_transport
989-
990- def find_format(transport):
991- last_error = errors.NotBranchError(transport.base)
992- for prober_kls in self.probers:
993- prober = prober_kls()
994- try:
995- return transport, prober.probe_transport(transport)
996- except errors.NotBranchError as e:
997- last_error = e
998- else:
999- raise last_error
1000- transport = get_transport(url)
1001- transport, format = do_catching_redirections(find_format, transport,
1002- redirected)
1003- return format.open(transport)
1004-
1005- def open(self, url, ignore_fallbacks=False):
1006- """Open the Bazaar branch at url, first checking for safety.
1007-
1008- What safety means is defined by a subclasses `followReference` and
1009- `checkOneURL` methods.
1010- """
1011- url = self.checkAndFollowBranchReference(url)
1012-
1013- def open_branch(url, ignore_fallbacks):
1014- dir = self._open_dir(url)
1015- return dir.open_branch(ignore_fallbacks=ignore_fallbacks)
1016- return self.runWithTransformFallbackLocationHookInstalled(
1017- open_branch, url, ignore_fallbacks)
1018-
1019-
1020-def safe_open(allowed_scheme, url, ignore_fallbacks=False):
1021- """Open the branch at `url`, only accessing URLs on `allowed_scheme`.
1022-
1023- :raises BadUrl: An attempt was made to open a URL that was not on
1024- `allowed_scheme`.
1025- """
1026- return SafeBranchOpener(SingleSchemePolicy(allowed_scheme)).open(url,
1027- ignore_fallbacks=ignore_fallbacks)
1028-
1029-
1030-SafeBranchOpener.install_hook()
1031
1032=== modified file 'lib/lp/codehosting/scanner/tests/test_bzrsync.py'
1033--- lib/lp/codehosting/scanner/tests/test_bzrsync.py 2019-06-20 13:16:35 +0000
1034+++ lib/lp/codehosting/scanner/tests/test_bzrsync.py 2019-07-09 12:34:22 +0000
1035@@ -14,6 +14,7 @@
1036 )
1037 from bzrlib.tests import TestCaseWithTransport
1038 from bzrlib.uncommit import uncommit
1039+from bzrlib.url_policy_open import BranchOpener
1040 from fixtures import (
1041 FakeLogger,
1042 TempDir,
1043@@ -48,7 +49,6 @@
1044 read_locked,
1045 write_locked,
1046 )
1047-from lp.codehosting.safe_open import SafeBranchOpener
1048 from lp.codehosting.scanner.bzrsync import BzrSync
1049 from lp.services.config import config
1050 from lp.services.database.interfaces import IStore
1051@@ -90,7 +90,7 @@
1052
1053 def setUp(self):
1054 super(BzrSyncTestCase, self).setUp()
1055- SafeBranchOpener.install_hook()
1056+ BranchOpener.install_hook()
1057 self.disable_directory_isolation()
1058 self.useBzrBranches(direct_database=True)
1059 self.makeFixtures()
1060
1061=== removed file 'lib/lp/codehosting/tests/test_safe_open.py'
1062--- lib/lp/codehosting/tests/test_safe_open.py 2018-01-02 16:10:26 +0000
1063+++ lib/lp/codehosting/tests/test_safe_open.py 1970-01-01 00:00:00 +0000
1064@@ -1,378 +0,0 @@
1065-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
1066-# GNU Affero General Public License version 3 (see the file LICENSE).
1067-
1068-"""Tests for the safe branch open code."""
1069-
1070-
1071-__metaclass__ = type
1072-
1073-from bzrlib.branch import (
1074- Branch,
1075- BranchReferenceFormat,
1076- BzrBranchFormat7,
1077- )
1078-from bzrlib.bzrdir import (
1079- BzrDir,
1080- BzrDirMetaFormat1,
1081- BzrProber,
1082- )
1083-from bzrlib.controldir import ControlDirFormat
1084-from bzrlib.errors import NotBranchError
1085-from bzrlib.repofmt.knitpack_repo import RepositoryFormatKnitPack1
1086-from bzrlib.tests import TestCaseWithTransport
1087-from bzrlib.transport import chroot
1088-from lazr.uri import URI
1089-
1090-from lp.codehosting.safe_open import (
1091- BadUrl,
1092- BlacklistPolicy,
1093- BranchLoopError,
1094- BranchReferenceForbidden,
1095- safe_open,
1096- SafeBranchOpener,
1097- WhitelistPolicy,
1098- )
1099-from lp.codehosting.tests.helpers import force_stacked_on_url
1100-from lp.testing import TestCase
1101-
1102-
1103-class TestSafeBranchOpenerCheckAndFollowBranchReference(TestCase):
1104- """Unit tests for `SafeBranchOpener.checkAndFollowBranchReference`."""
1105-
1106- def setUp(self):
1107- super(TestSafeBranchOpenerCheckAndFollowBranchReference, self).setUp()
1108- SafeBranchOpener.install_hook()
1109-
1110- class StubbedSafeBranchOpener(SafeBranchOpener):
1111- """SafeBranchOpener that provides canned answers.
1112-
1113- We implement the methods we need to to be able to control all the
1114- inputs to the `BranchMirrorer.checkSource` method, which is what is
1115- being tested in this class.
1116- """
1117-
1118- def __init__(self, references, policy):
1119- parent_cls = TestSafeBranchOpenerCheckAndFollowBranchReference
1120- super(parent_cls.StubbedSafeBranchOpener, self).__init__(policy)
1121- self._reference_values = {}
1122- for i in range(len(references) - 1):
1123- self._reference_values[references[i]] = references[i + 1]
1124- self.follow_reference_calls = []
1125-
1126- def followReference(self, url):
1127- self.follow_reference_calls.append(url)
1128- return self._reference_values[url]
1129-
1130- def makeBranchOpener(self, should_follow_references, references,
1131- unsafe_urls=None):
1132- policy = BlacklistPolicy(should_follow_references, unsafe_urls)
1133- opener = self.StubbedSafeBranchOpener(references, policy)
1134- return opener
1135-
1136- def testCheckInitialURL(self):
1137- # checkSource rejects all URLs that are not allowed.
1138- opener = self.makeBranchOpener(None, [], set(['a']))
1139- self.assertRaises(
1140- BadUrl, opener.checkAndFollowBranchReference, 'a')
1141-
1142- def testNotReference(self):
1143- # When branch references are forbidden, checkAndFollowBranchReference
1144- # does not raise on non-references.
1145- opener = self.makeBranchOpener(False, ['a', None])
1146- self.assertEqual('a', opener.checkAndFollowBranchReference('a'))
1147- self.assertEqual(['a'], opener.follow_reference_calls)
1148-
1149- def testBranchReferenceForbidden(self):
1150- # checkAndFollowBranchReference raises BranchReferenceForbidden if
1151- # branch references are forbidden and the source URL points to a
1152- # branch reference.
1153- opener = self.makeBranchOpener(False, ['a', 'b'])
1154- self.assertRaises(
1155- BranchReferenceForbidden,
1156- opener.checkAndFollowBranchReference, 'a')
1157- self.assertEqual(['a'], opener.follow_reference_calls)
1158-
1159- def testAllowedReference(self):
1160- # checkAndFollowBranchReference does not raise if following references
1161- # is allowed and the source URL points to a branch reference to a
1162- # permitted location.
1163- opener = self.makeBranchOpener(True, ['a', 'b', None])
1164- self.assertEqual('b', opener.checkAndFollowBranchReference('a'))
1165- self.assertEqual(['a', 'b'], opener.follow_reference_calls)
1166-
1167- def testCheckReferencedURLs(self):
1168- # checkAndFollowBranchReference checks if the URL a reference points
1169- # to is safe.
1170- opener = self.makeBranchOpener(
1171- True, ['a', 'b', None], unsafe_urls=set('b'))
1172- self.assertRaises(
1173- BadUrl, opener.checkAndFollowBranchReference, 'a')
1174- self.assertEqual(['a'], opener.follow_reference_calls)
1175-
1176- def testSelfReferencingBranch(self):
1177- # checkAndFollowBranchReference raises BranchReferenceLoopError if
1178- # following references is allowed and the source url points to a
1179- # self-referencing branch reference.
1180- opener = self.makeBranchOpener(True, ['a', 'a'])
1181- self.assertRaises(
1182- BranchLoopError, opener.checkAndFollowBranchReference, 'a')
1183- self.assertEqual(['a'], opener.follow_reference_calls)
1184-
1185- def testBranchReferenceLoop(self):
1186- # checkAndFollowBranchReference raises BranchReferenceLoopError if
1187- # following references is allowed and the source url points to a loop
1188- # of branch references.
1189- references = ['a', 'b', 'a']
1190- opener = self.makeBranchOpener(True, references)
1191- self.assertRaises(
1192- BranchLoopError, opener.checkAndFollowBranchReference, 'a')
1193- self.assertEqual(['a', 'b'], opener.follow_reference_calls)
1194-
1195-
1196-class TrackingProber(BzrProber):
1197- """Subclass of BzrProber which tracks URLs it has been asked to open."""
1198-
1199- seen_urls = []
1200-
1201- @classmethod
1202- def probe_transport(klass, transport):
1203- klass.seen_urls.append(transport.base)
1204- return BzrProber.probe_transport(transport)
1205-
1206-
1207-class TestSafeBranchOpenerStacking(TestCaseWithTransport):
1208-
1209- def setUp(self):
1210- super(TestSafeBranchOpenerStacking, self).setUp()
1211- SafeBranchOpener.install_hook()
1212-
1213- def makeBranchOpener(self, allowed_urls, probers=None):
1214- policy = WhitelistPolicy(True, allowed_urls, True)
1215- return SafeBranchOpener(policy, probers)
1216-
1217- def makeBranch(self, path, branch_format, repository_format):
1218- """Make a Bazaar branch at 'path' with the given formats."""
1219- bzrdir_format = BzrDirMetaFormat1()
1220- bzrdir_format.set_branch_format(branch_format)
1221- bzrdir = self.make_bzrdir(path, format=bzrdir_format)
1222- repository_format.initialize(bzrdir)
1223- return bzrdir.create_branch()
1224-
1225- def testProbers(self):
1226- # Only the specified probers should be used
1227- b = self.make_branch('branch')
1228- opener = self.makeBranchOpener([b.base], probers=[])
1229- self.assertRaises(NotBranchError, opener.open, b.base)
1230- opener = self.makeBranchOpener([b.base], probers=[BzrProber])
1231- self.assertEqual(b.base, opener.open(b.base).base)
1232-
1233- def testDefaultProbers(self):
1234- # If no probers are specified to the constructor
1235- # of SafeBranchOpener, then a safe set will be used,
1236- # rather than all probers registered in bzr.
1237- self.addCleanup(ControlDirFormat.unregister_prober, TrackingProber)
1238- ControlDirFormat.register_prober(TrackingProber)
1239- # Open a location without any branches, so that all probers are
1240- # tried.
1241- # First, check that the TrackingProber tracks correctly.
1242- TrackingProber.seen_urls = []
1243- opener = self.makeBranchOpener(["."], probers=[TrackingProber])
1244- self.assertRaises(NotBranchError, opener.open, ".")
1245- self.assertEqual(1, len(TrackingProber.seen_urls))
1246- TrackingProber.seen_urls = []
1247- # And make sure it's registered in such a way that BzrDir.open would
1248- # use it.
1249- self.assertRaises(NotBranchError, BzrDir.open, ".")
1250- self.assertEqual(1, len(TrackingProber.seen_urls))
1251- TrackingProber.seen_urls = []
1252- # Make sure that SafeBranchOpener doesn't use it if no
1253- # probers were specified
1254- opener = self.makeBranchOpener(["."])
1255- self.assertRaises(NotBranchError, opener.open, ".")
1256- self.assertEqual(0, len(TrackingProber.seen_urls))
1257-
1258- def testAllowedURL(self):
1259- # checkSource does not raise an exception for branches stacked on
1260- # branches with allowed URLs.
1261- stacked_on_branch = self.make_branch('base-branch')
1262- stacked_branch = self.make_branch('stacked-branch')
1263- stacked_branch.set_stacked_on_url(stacked_on_branch.base)
1264- opener = self.makeBranchOpener(
1265- [stacked_branch.base, stacked_on_branch.base])
1266- # This doesn't raise an exception.
1267- opener.open(stacked_branch.base)
1268-
1269- def testUnstackableRepository(self):
1270- # checkSource treats branches with UnstackableRepositoryFormats as
1271- # being not stacked.
1272- branch = self.makeBranch(
1273- 'unstacked', BzrBranchFormat7(), RepositoryFormatKnitPack1())
1274- opener = self.makeBranchOpener([branch.base])
1275- # This doesn't raise an exception.
1276- opener.open(branch.base)
1277-
1278- def testAllowedRelativeURL(self):
1279- # checkSource passes on absolute urls to checkOneURL, even if the
1280- # value of stacked_on_location in the config is set to a relative URL.
1281- stacked_on_branch = self.make_branch('base-branch')
1282- stacked_branch = self.make_branch('stacked-branch')
1283- stacked_branch.set_stacked_on_url('../base-branch')
1284- opener = self.makeBranchOpener(
1285- [stacked_branch.base, stacked_on_branch.base])
1286- # Note that stacked_on_branch.base is not '../base-branch', it's an
1287- # absolute URL.
1288- self.assertNotEqual('../base-branch', stacked_on_branch.base)
1289- # This doesn't raise an exception.
1290- opener.open(stacked_branch.base)
1291-
1292- def testAllowedRelativeNested(self):
1293- # Relative URLs are resolved relative to the stacked branch.
1294- self.get_transport().mkdir('subdir')
1295- a = self.make_branch('subdir/a')
1296- b = self.make_branch('b')
1297- b.set_stacked_on_url('../subdir/a')
1298- c = self.make_branch('subdir/c')
1299- c.set_stacked_on_url('../../b')
1300- opener = self.makeBranchOpener([c.base, b.base, a.base])
1301- # This doesn't raise an exception.
1302- opener.open(c.base)
1303-
1304- def testForbiddenURL(self):
1305- # checkSource raises a BadUrl exception if a branch is stacked on a
1306- # branch with a forbidden URL.
1307- stacked_on_branch = self.make_branch('base-branch')
1308- stacked_branch = self.make_branch('stacked-branch')
1309- stacked_branch.set_stacked_on_url(stacked_on_branch.base)
1310- opener = self.makeBranchOpener([stacked_branch.base])
1311- self.assertRaises(BadUrl, opener.open, stacked_branch.base)
1312-
1313- def testForbiddenURLNested(self):
1314- # checkSource raises a BadUrl exception if a branch is stacked on a
1315- # branch that is in turn stacked on a branch with a forbidden URL.
1316- a = self.make_branch('a')
1317- b = self.make_branch('b')
1318- b.set_stacked_on_url(a.base)
1319- c = self.make_branch('c')
1320- c.set_stacked_on_url(b.base)
1321- opener = self.makeBranchOpener([c.base, b.base])
1322- self.assertRaises(BadUrl, opener.open, c.base)
1323-
1324- def testSelfStackedBranch(self):
1325- # checkSource raises StackingLoopError if a branch is stacked on
1326- # itself. This avoids infinite recursion errors.
1327- a = self.make_branch('a')
1328- force_stacked_on_url(a, a.base)
1329- opener = self.makeBranchOpener([a.base])
1330- self.assertRaises(BranchLoopError, opener.open, a.base)
1331-
1332- def testLoopStackedBranch(self):
1333- # checkSource raises StackingLoopError if a branch is stacked in such
1334- # a way so that it is ultimately stacked on itself. e.g. a stacked on
1335- # b stacked on a.
1336- a = self.make_branch('a')
1337- b = self.make_branch('b')
1338- a.set_stacked_on_url(b.base)
1339- b.set_stacked_on_url(a.base)
1340- opener = self.makeBranchOpener([a.base, b.base])
1341- self.assertRaises(BranchLoopError, opener.open, a.base)
1342- self.assertRaises(BranchLoopError, opener.open, b.base)
1343-
1344- def testCustomOpener(self):
1345- # A custom function for opening a control dir can be specified.
1346- a = self.make_branch('a')
1347- b = self.make_branch('b')
1348- b.set_stacked_on_url(a.base)
1349-
1350- TrackingProber.seen_urls = []
1351- opener = self.makeBranchOpener(
1352- [a.base, b.base], probers=[TrackingProber])
1353- opener.open(b.base)
1354- self.assertEqual(set(TrackingProber.seen_urls), set([b.base, a.base]))
1355-
1356- def testCustomOpenerWithBranchReference(self):
1357- # A custom function for opening a control dir can be specified.
1358- a = self.make_branch('a')
1359- b_dir = self.make_bzrdir('b')
1360- b = BranchReferenceFormat().initialize(b_dir, target_branch=a)
1361- TrackingProber.seen_urls = []
1362- opener = self.makeBranchOpener(
1363- [a.base, b.base], probers=[TrackingProber])
1364- opener.open(b.base)
1365- self.assertEqual(set(TrackingProber.seen_urls), set([b.base, a.base]))
1366-
1367- def test_ignore_fallbacks(self):
1368- """"Cross-format stacking doesn't error with ignore_fallbacks."""
1369- stacked, stacked_on = make_cross_format_stacked(self)
1370- opener = self.makeBranchOpener([stacked.base, stacked_on.base])
1371- opener.open(stacked.base, ignore_fallbacks=True)
1372-
1373-
1374-def make_cross_format_stacked(test_case):
1375- test_case.get_transport().mkdir('inside')
1376- stacked = test_case.make_branch('inside/stacked', format='1.6')
1377- stacked_on = test_case.make_branch('inside/stacked-on', format='2a')
1378- force_stacked_on_url(stacked, stacked_on.base)
1379- return stacked, stacked_on
1380-
1381-
1382-class TestSafeOpen(TestCaseWithTransport):
1383- """Tests for `safe_open`."""
1384-
1385- def setUp(self):
1386- super(TestSafeOpen, self).setUp()
1387- SafeBranchOpener.install_hook()
1388-
1389- def test_hook_does_not_interfere(self):
1390- # The transform_fallback_location hook does not interfere with regular
1391- # stacked branch access outside of safe_open.
1392- self.make_branch('stacked')
1393- self.make_branch('stacked-on')
1394- Branch.open('stacked').set_stacked_on_url('../stacked-on')
1395- Branch.open('stacked')
1396-
1397- def get_chrooted_scheme(self, relpath):
1398- """Create a server that is chrooted to `relpath`.
1399-
1400- :return: ``(scheme, get_url)`` where ``scheme`` is the scheme of the
1401- chroot server and ``get_url`` returns URLs on said server.
1402- """
1403- transport = self.get_transport(relpath)
1404- chroot_server = chroot.ChrootServer(transport)
1405- chroot_server.start_server()
1406- self.addCleanup(chroot_server.stop_server)
1407-
1408- def get_url(relpath):
1409- return chroot_server.get_url() + relpath
1410-
1411- return URI(chroot_server.get_url()).scheme, get_url
1412-
1413- def test_stacked_within_scheme(self):
1414- # A branch that is stacked on a URL of the same scheme is safe to
1415- # open.
1416- self.get_transport().mkdir('inside')
1417- self.make_branch('inside/stacked')
1418- self.make_branch('inside/stacked-on')
1419- scheme, get_chrooted_url = self.get_chrooted_scheme('inside')
1420- Branch.open(get_chrooted_url('stacked')).set_stacked_on_url(
1421- get_chrooted_url('stacked-on'))
1422- safe_open(scheme, get_chrooted_url('stacked'))
1423-
1424- def test_stacked_outside_scheme(self):
1425- # A branch that is stacked on a URL that is not of the same scheme is
1426- # not safe to open.
1427- self.get_transport().mkdir('inside')
1428- self.get_transport().mkdir('outside')
1429- self.make_branch('inside/stacked')
1430- self.make_branch('outside/stacked-on')
1431- scheme, get_chrooted_url = self.get_chrooted_scheme('inside')
1432- Branch.open(get_chrooted_url('stacked')).set_stacked_on_url(
1433- self.get_url('outside/stacked-on'))
1434- self.assertRaises(
1435- BadUrl, safe_open, scheme, get_chrooted_url('stacked'))
1436-
1437- def test_ignore_fallbacks(self):
1438- """"Cross-format stacking doesn't error with ignore_fallbacks."""
1439- scheme, get_chrooted_url = self.get_chrooted_scheme('inside')
1440- stacked, stacked_on = make_cross_format_stacked(self)
1441- force_stacked_on_url(stacked, get_chrooted_url('stacked-on'))
1442- safe_open(scheme, get_chrooted_url('stacked'), ignore_fallbacks=True)
1443
1444=== modified file 'lib/lp/codehosting/upgrade.py'
1445--- lib/lp/codehosting/upgrade.py 2014-01-30 15:04:06 +0000
1446+++ lib/lp/codehosting/upgrade.py 2019-07-09 12:34:22 +0000
1447@@ -29,6 +29,10 @@
1448 )
1449 from bzrlib.repofmt.groupcompress_repo import RepositoryFormat2aSubtree
1450 from bzrlib.upgrade import upgrade
1451+from bzrlib.url_policy_open import (
1452+ BranchOpener,
1453+ SingleSchemePolicy,
1454+ )
1455
1456 from lp.code.bzr import (
1457 branch_changed,
1458@@ -36,7 +40,6 @@
1459 )
1460 from lp.code.model.branch import Branch
1461 from lp.codehosting.bzrutils import read_locked
1462-from lp.codehosting.safe_open import safe_open
1463 from lp.codehosting.vfs.branchfs import get_real_branch_path
1464 from lp.services.database.interfaces import IStore
1465
1466@@ -52,9 +55,9 @@
1467 self.branch = branch
1468 self.bzr_branch = bzr_branch
1469 if self.bzr_branch is None:
1470- self.bzr_branch = safe_open('lp-internal',
1471- self.branch.getInternalBzrUrl(),
1472- ignore_fallbacks=True)
1473+ opener = BranchOpener(SingleSchemePolicy('lp-internal'))
1474+ self.bzr_branch = opener.open(
1475+ self.branch.getInternalBzrUrl(), ignore_fallbacks=True)
1476 self.target_dir = target_dir
1477 self.target_subdir = os.path.join(
1478 self.target_dir, str(self.branch.id))
1479
1480=== modified file 'scripts/code-import-worker.py'
1481--- scripts/code-import-worker.py 2016-11-03 17:31:43 +0000
1482+++ scripts/code-import-worker.py 2019-07-09 12:34:22 +0000
1483@@ -21,6 +21,7 @@
1484 import sys
1485
1486 from bzrlib.transport import get_transport
1487+from bzrlib.url_policy_open import AcceptAnythingPolicy
1488
1489 from lp.codehosting.codeimport.worker import (
1490 BzrImportWorker,
1491@@ -32,7 +33,6 @@
1492 GitImportWorker,
1493 GitToGitImportWorker,
1494 )
1495-from lp.codehosting.safe_open import AcceptAnythingPolicy
1496 from lp.services import scripts
1497 from lp.services.config import config
1498 from lp.services.timeout import set_default_timeout_function