~bzr-pqm/bzr/bzr.dev

1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
1
# Copyright (C) 2005 by Canonical Ltd
2
# -*- coding: utf-8 -*-
3
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
19
"""Tests for bzr setting permissions.
20
21
Files which are created underneath .bzr/ should inherit its permissions.
22
So if the directory is group writable, the files and subdirs should be as well.
23
24
In the future, when we have Repository/Branch/Checkout information, the
25
permissions should be inherited individually, rather than all be the same.
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
26
"""
27
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
28
# TODO: jam 20051215 There are no tests for ftp yet, because we have no ftp server
29
# TODO: jam 20051215 Currently the default behavior for 'bzr branch' is just 
30
#                    defined by the local umask. This isn't terrible, is it
31
#                    the truly desired behavior?
32
 
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
33
import os
34
import sys
35
import stat
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
36
from StringIO import StringIO
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
37
38
from bzrlib.branch import Branch
1185.65.23 by Robert Collins
update tests somewhat
39
from bzrlib.lockable_files import LockableFiles
1534.4.28 by Robert Collins
first cut at merge from integration.
40
from bzrlib.tests import TestCaseWithTransport, TestSkipped
1185.50.20 by John Arbash Meinel
merge permissions branch, also fixup tests so they are lined up with bzr.dev to help prevent conflicts.
41
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
1530.1.17 by Robert Collins
Move check_mode to TestCase.assertMode to make it generally accessible.
42
from bzrlib.transport import get_transport
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
43
from bzrlib.workingtree import WorkingTree
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
44
45
46
def chmod_r(base, file_mode, dir_mode):
47
    """Recursively chmod from a base directory"""
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
48
    assert os.path.isdir(base)
49
    os.chmod(base, dir_mode)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
50
    for root, dirs, files in os.walk(base):
51
        for d in dirs:
52
            p = os.path.join(root, d)
53
            os.chmod(p, dir_mode)
54
        for f in files:
55
            p = os.path.join(root, f)
56
            os.chmod(p, file_mode)
57
58
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
59
def check_mode_r(test, base, file_mode, dir_mode, include_base=True):
60
    """Check that all permissions match
61
62
    :param test: The TestCase being run
63
    :param base: The path to the root directory to check
64
    :param file_mode: The mode for all files
65
    :param dir_mode: The mode for all directories
66
    :param include_base: If false, only check the subdirectories
67
    """
68
    assert os.path.isdir(base)
1530.1.17 by Robert Collins
Move check_mode to TestCase.assertMode to make it generally accessible.
69
    t = get_transport(".")
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
70
    if include_base:
1530.1.21 by Robert Collins
Review feedback fixes.
71
        test.assertTransportMode(t, base, dir_mode)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
72
    for root, dirs, files in os.walk(base):
73
        for d in dirs:
74
            p = os.path.join(root, d)
1530.1.21 by Robert Collins
Review feedback fixes.
75
            test.assertTransportMode(t, p, dir_mode)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
76
        for f in files:
77
            p = os.path.join(root, f)
1530.1.21 by Robert Collins
Review feedback fixes.
78
            test.assertTransportMode(t, p, file_mode)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
79
1532 by Robert Collins
Merge in John Meinels integration branch.
80
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
81
def assertEqualMode(test, mode, mode_test):
82
    test.assertEqual(mode, mode_test,
83
                     'mode mismatch %o != %o' % (mode, mode_test))
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
84
1532 by Robert Collins
Merge in John Meinels integration branch.
85
1534.4.28 by Robert Collins
first cut at merge from integration.
86
class TestPermissions(TestCaseWithTransport):
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
87
88
    def test_new_files(self):
89
        if sys.platform == 'win32':
90
            raise TestSkipped('chmod has no effect on win32')
91
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
92
        t = WorkingTree.create_standalone('.')
93
        b = t.branch
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
94
        open('a', 'wb').write('foo\n')
95
        t.add('a')
96
        t.commit('foo')
97
98
        # Delete them because we are modifying the filesystem underneath them
99
        del b, t 
100
        chmod_r('.bzr', 0644, 0755)
101
        check_mode_r(self, '.bzr', 0644, 0755)
102
103
        b = Branch.open('.')
104
        t = b.working_tree()
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
105
        assertEqualMode(self, 0755, b.control_files._dir_mode)
106
        assertEqualMode(self, 0644, b.control_files._file_mode)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
107
108
        # Modifying a file shouldn't break the permissions
109
        open('a', 'wb').write('foo2\n')
110
        t.commit('foo2')
111
        # The mode should be maintained after commit
112
        check_mode_r(self, '.bzr', 0644, 0755)
113
114
        # Adding a new file should maintain the permissions
115
        open('b', 'wb').write('new b\n')
116
        t.add('b')
117
        t.commit('new b')
118
        check_mode_r(self, '.bzr', 0644, 0755)
119
120
        del b, t
121
        # Recursively update the modes of all files
122
        chmod_r('.bzr', 0664, 0775)
123
        check_mode_r(self, '.bzr', 0664, 0775)
124
        b = Branch.open('.')
125
        t = b.working_tree()
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
126
        assertEqualMode(self, 0775, b.control_files._dir_mode)
127
        assertEqualMode(self, 0664, b.control_files._file_mode)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
128
129
        open('a', 'wb').write('foo3\n')
130
        t.commit('foo3')
131
        check_mode_r(self, '.bzr', 0664, 0775)
132
133
        open('c', 'wb').write('new c\n')
134
        t.add('c')
135
        t.commit('new c')
136
        check_mode_r(self, '.bzr', 0664, 0775)
137
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
138
        # Test the group sticky bit
139
        del b, t
140
        # Recursively update the modes of all files
141
        chmod_r('.bzr', 0664, 02775)
142
        check_mode_r(self, '.bzr', 0664, 02775)
143
        b = Branch.open('.')
144
        t = b.working_tree()
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
145
        assertEqualMode(self, 02775, b.control_files._dir_mode)
146
        assertEqualMode(self, 0664, b.control_files._file_mode)
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
147
148
        open('a', 'wb').write('foo4\n')
149
        t.commit('foo4')
150
        check_mode_r(self, '.bzr', 0664, 02775)
151
152
        open('d', 'wb').write('new d\n')
153
        t.add('d')
154
        t.commit('new d')
155
        check_mode_r(self, '.bzr', 0664, 02775)
156
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
157
    def test_disable_set_mode(self):
158
        # TODO: jam 20051215 Ultimately, this test should probably test that
159
        #                    extra chmod calls aren't being made
160
        try:
1534.4.28 by Robert Collins
first cut at merge from integration.
161
            transport = get_transport(self.get_url())
1185.65.23 by Robert Collins
update tests somewhat
162
            transport.put('my-lock', StringIO(''))
163
            lockable = LockableFiles(transport, 'my-lock')
164
            self.assertNotEqual(None, lockable._dir_mode)
165
            self.assertNotEqual(None, lockable._file_mode)
166
167
            LockableFiles._set_dir_mode = False
168
            transport = get_transport('.')
169
            lockable = LockableFiles(transport, 'my-lock')
170
            self.assertEqual(None, lockable._dir_mode)
171
            self.assertNotEqual(None, lockable._file_mode)
172
173
            LockableFiles._set_file_mode = False
174
            transport = get_transport('.')
175
            lockable = LockableFiles(transport, 'my-lock')
176
            self.assertEqual(None, lockable._dir_mode)
177
            self.assertEqual(None, lockable._file_mode)
178
179
            LockableFiles._set_dir_mode = True
180
            transport = get_transport('.')
181
            lockable = LockableFiles(transport, 'my-lock')
182
            self.assertNotEqual(None, lockable._dir_mode)
183
            self.assertEqual(None, lockable._file_mode)
184
185
            LockableFiles._set_file_mode = True
186
            transport = get_transport('.')
187
            lockable = LockableFiles(transport, 'my-lock')
188
            self.assertNotEqual(None, lockable._dir_mode)
189
            self.assertNotEqual(None, lockable._file_mode)
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
190
        finally:
1185.65.23 by Robert Collins
update tests somewhat
191
            LockableFiles._set_dir_mode = True
192
            LockableFiles._set_file_mode = True
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
193
194
    def test_new_branch(self):
195
        if sys.platform == 'win32':
196
            raise TestSkipped('chmod has no effect on win32')
1185.65.23 by Robert Collins
update tests somewhat
197
        #FIXME RBC 20060105 should test branch and repository 
198
        # permissions ? 
199
        # also, these are BzrBranch format specific things..
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
200
        os.mkdir('a')
201
        mode = stat.S_IMODE(os.stat('a').st_mode)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
202
        t = WorkingTree.create_standalone('.')
203
        b = t.branch
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
204
        assertEqualMode(self, mode, b.control_files._dir_mode)
205
        assertEqualMode(self, mode & ~07111, b.control_files._file_mode)
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
206
207
        os.mkdir('b')
208
        os.chmod('b', 02777)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
209
        b = Branch.create('b')
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
210
        assertEqualMode(self, 02777, b.control_files._dir_mode)
211
        assertEqualMode(self, 00666, b.control_files._file_mode)
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
212
        check_mode_r(self, 'b/.bzr', 00666, 02777)
213
214
        os.mkdir('c')
215
        os.chmod('c', 02750)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
216
        b = Branch.create('c')
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
217
        assertEqualMode(self, 02750, b.control_files._dir_mode)
218
        assertEqualMode(self, 00640, b.control_files._file_mode)
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
219
        check_mode_r(self, 'c/.bzr', 00640, 02750)
220
221
        os.mkdir('d')
222
        os.chmod('d', 0700)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
223
        b = Branch.create('d')
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
224
        assertEqualMode(self, 0700, b.control_files._dir_mode)
225
        assertEqualMode(self, 0600, b.control_files._file_mode)
1185.58.7 by John Arbash Meinel
Added the ability to disable setting permissions
226
        check_mode_r(self, 'd/.bzr', 00600, 0700)
227
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
228
229
class TestSftpPermissions(TestCaseWithSFTPServer):
230
231
    def test_new_files(self):
232
        if sys.platform == 'win32':
233
            raise TestSkipped('chmod has no effect on win32')
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
234
        # Though it would be nice to test that SFTP to a server
235
        # which does support chmod has the right effect
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
236
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
237
        from bzrlib.transport.sftp import SFTPTransport
238
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
239
        # We don't actually use it directly, we just want to
240
        # keep the connection open, since StubSFTPServer only
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
241
        # allows 1 connection
242
        _transport = SFTPTransport(self._sftp_url)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
243
244
        os.mkdir('local')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
245
        t_local = WorkingTree.create_standalone('local')
246
        b_local = t_local.branch
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
247
        open('local/a', 'wb').write('foo\n')
248
        t_local.add('a')
249
        t_local.commit('foo')
250
251
        # Delete them because we are modifying the filesystem underneath them
252
        del b_local, t_local 
253
        chmod_r('local/.bzr', 0644, 0755)
254
        check_mode_r(self, 'local/.bzr', 0644, 0755)
255
256
        b_local = Branch.open(u'local')
257
        t_local = b_local.working_tree()
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
258
        assertEqualMode(self, 0755, b_local.control_files._dir_mode)
259
        assertEqualMode(self, 0644, b_local.control_files._file_mode)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
260
261
        os.mkdir('sftp')
1530.1.7 by Robert Collins
merge integration.
262
        sftp_url = self.get_remote_url('sftp')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
263
        b_sftp = Branch.create(sftp_url)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
264
265
        b_sftp.pull(b_local)
266
        del b_sftp
267
        chmod_r('sftp/.bzr', 0644, 0755)
268
        check_mode_r(self, 'sftp/.bzr', 0644, 0755)
269
270
        b_sftp = Branch.open(sftp_url)
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
271
        assertEqualMode(self, 0755, b_sftp.control_files._dir_mode)
272
        assertEqualMode(self, 0644, b_sftp.control_files._file_mode)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
273
274
        open('local/a', 'wb').write('foo2\n')
275
        t_local.commit('foo2')
276
        b_sftp.pull(b_local)
277
        # The mode should be maintained after commit
278
        check_mode_r(self, 'sftp/.bzr', 0644, 0755)
279
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
280
        open('local/b', 'wb').write('new b\n')
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
281
        t_local.add('b')
282
        t_local.commit('new b')
283
        b_sftp.pull(b_local)
284
        check_mode_r(self, 'sftp/.bzr', 0644, 0755)
285
286
        del b_sftp
287
        # Recursively update the modes of all files
288
        chmod_r('sftp/.bzr', 0664, 0775)
289
        check_mode_r(self, 'sftp/.bzr', 0664, 0775)
290
291
        b_sftp = Branch.open(sftp_url)
1185.69.2 by John Arbash Meinel
Changed LockableFiles to take the root directory directly. Moved mode information into LockableFiles instead of Branch
292
        assertEqualMode(self, 0775, b_sftp.control_files._dir_mode)
293
        assertEqualMode(self, 0664, b_sftp.control_files._file_mode)
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
294
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
295
        open('local/a', 'wb').write('foo3\n')
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
296
        t_local.commit('foo3')
297
        b_sftp.pull(b_local)
298
        check_mode_r(self, 'sftp/.bzr', 0664, 0775)
299
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
300
        open('local/c', 'wb').write('new c\n')
1185.58.1 by John Arbash Meinel
Added new permissions test (currently don't pass)
301
        t_local.add('c')
302
        t_local.commit('new c')
303
        b_sftp.pull(b_local)
304
        check_mode_r(self, 'sftp/.bzr', 0664, 0775)
305
1185.58.10 by John Arbash Meinel
[patch] Robey Pointer to fix sftp server using umask for files (failing tests for directories)
306
    def test_sftp_server_modes(self):
307
        if sys.platform == 'win32':
308
            raise TestSkipped('chmod has no effect on win32')
309
310
        umask = 0022
311
        original_umask = os.umask(umask)
312
313
        try:
314
            from bzrlib.transport.sftp import SFTPTransport
315
            t = SFTPTransport(self._sftp_url)
316
            # Direct access should be masked by umask
317
            t._sftp_open_exclusive('a', mode=0666).write('foo\n')
1530.1.21 by Robert Collins
Review feedback fixes.
318
            self.assertTransportMode(t, 'a', 0666 &~umask)
1185.58.10 by John Arbash Meinel
[patch] Robey Pointer to fix sftp server using umask for files (failing tests for directories)
319
320
            # but Transport overrides umask
321
            t.put('b', 'txt', mode=0666)
1530.1.21 by Robert Collins
Review feedback fixes.
322
            self.assertTransportMode(t, 'b', 0666)
1185.58.10 by John Arbash Meinel
[patch] Robey Pointer to fix sftp server using umask for files (failing tests for directories)
323
324
            t._sftp.mkdir('c', mode=0777)
1530.1.21 by Robert Collins
Review feedback fixes.
325
            self.assertTransportMode(t, 'c', 0777 &~umask)
1185.58.10 by John Arbash Meinel
[patch] Robey Pointer to fix sftp server using umask for files (failing tests for directories)
326
327
            t.mkdir('d', mode=0777)
1530.1.21 by Robert Collins
Review feedback fixes.
328
            self.assertTransportMode(t, 'd', 0777)
1185.58.10 by John Arbash Meinel
[patch] Robey Pointer to fix sftp server using umask for files (failing tests for directories)
329
        finally:
330
            os.umask(original_umask)