1 from nose.tools import eq_ as eq
2 from gitosis.test.util import assert_raises
6 from cStringIO import StringIO
7 from ConfigParser import RawConfigParser
9 from gitosis import serve
10 from gitosis import repository
12 from gitosis.test import util
14 def test_bad_newLine():
15 cfg = RawConfigParser()
17 serve.CommandMayNotContainNewlineError,
23 eq(str(e), 'Command may not contain newline')
24 assert isinstance(e, serve.ServingError)
26 def test_bad_nospace():
27 cfg = RawConfigParser()
29 serve.UnknownCommandError,
33 command='git-upload-pack',
35 eq(str(e), 'Unknown command denied')
36 assert isinstance(e, serve.ServingError)
38 def test_bad_command():
39 cfg = RawConfigParser()
41 serve.UnknownCommandError,
47 eq(str(e), 'Unknown command denied')
48 assert isinstance(e, serve.ServingError)
50 def test_bad_unsafeArguments_notQuoted():
51 cfg = RawConfigParser()
53 serve.UnsafeArgumentsError,
57 command="git-upload-pack foo",
59 eq(str(e), 'Arguments to command look dangerous')
60 assert isinstance(e, serve.ServingError)
62 def test_bad_unsafeArguments_badCharacters():
63 cfg = RawConfigParser()
65 serve.UnsafeArgumentsError,
69 command="git-upload-pack 'ev!l'",
71 eq(str(e), 'Arguments to command look dangerous')
72 assert isinstance(e, serve.ServingError)
74 def test_bad_unsafeArguments_dotdot():
75 cfg = RawConfigParser()
77 serve.UnsafeArgumentsError,
81 command="git-upload-pack 'something/../evil'",
83 eq(str(e), 'Arguments to command look dangerous')
84 assert isinstance(e, serve.ServingError)
86 def test_bad_forbiddenCommand_read():
87 cfg = RawConfigParser()
89 serve.ReadAccessDenied,
93 command="git-upload-pack 'foo'",
95 eq(str(e), 'Repository read access denied')
96 assert isinstance(e, serve.AccessDenied)
97 assert isinstance(e, serve.ServingError)
99 def test_bad_forbiddenCommand_write_noAccess():
100 cfg = RawConfigParser()
102 serve.ReadAccessDenied,
106 command="git-receive-pack 'foo'",
108 # error message talks about read in an effort to make it more
109 # obvious that jdoe doesn't have *even* read access
110 eq(str(e), 'Repository read access denied')
111 assert isinstance(e, serve.AccessDenied)
112 assert isinstance(e, serve.ServingError)
114 def test_bad_forbiddenCommand_write_readAccess():
115 cfg = RawConfigParser()
116 cfg.add_section('group foo')
117 cfg.set('group foo', 'members', 'jdoe')
118 cfg.set('group foo', 'readonly', 'foo')
120 serve.WriteAccessDenied,
124 command="git-receive-pack 'foo'",
126 eq(str(e), 'Repository write access denied')
127 assert isinstance(e, serve.AccessDenied)
128 assert isinstance(e, serve.ServingError)
130 def test_simple_read():
131 tmp = util.maketemp()
132 repository.init(os.path.join(tmp, 'foo.git'))
133 cfg = RawConfigParser()
134 cfg.add_section('gitosis')
135 cfg.set('gitosis', 'repositories', tmp)
136 cfg.add_section('group foo')
137 cfg.set('group foo', 'members', 'jdoe')
138 cfg.set('group foo', 'readonly', 'foo')
142 command="git-upload-pack 'foo'",
144 eq(got, "git-upload-pack '%s/foo.git'" % tmp)
146 def test_simple_write():
147 tmp = util.maketemp()
148 repository.init(os.path.join(tmp, 'foo.git'))
149 cfg = RawConfigParser()
150 cfg.add_section('gitosis')
151 cfg.set('gitosis', 'repositories', tmp)
152 cfg.add_section('group foo')
153 cfg.set('group foo', 'members', 'jdoe')
154 cfg.set('group foo', 'writable', 'foo')
158 command="git-receive-pack 'foo'",
160 eq(got, "git-receive-pack '%s/foo.git'" % tmp)
162 def test_push_inits_if_needed():
163 # a push to a non-existent repository (but where config authorizes
164 # you to do that) will create the repository on the fly
165 tmp = util.maketemp()
166 cfg = RawConfigParser()
167 cfg.add_section('gitosis')
168 repositories = os.path.join(tmp, 'repositories')
169 os.mkdir(repositories)
170 cfg.set('gitosis', 'repositories', repositories)
171 generated = os.path.join(tmp, 'generated')
173 cfg.set('gitosis', 'generate-files-in', generated)
174 cfg.add_section('group foo')
175 cfg.set('group foo', 'members', 'jdoe')
176 cfg.set('group foo', 'writable', 'foo')
180 command="git-receive-pack 'foo'",
182 eq(os.listdir(repositories), ['foo.git'])
183 assert os.path.isfile(os.path.join(repositories, 'foo.git', 'HEAD'))
185 def test_push_inits_if_needed_haveExtension():
186 # a push to a non-existent repository (but where config authorizes
187 # you to do that) will create the repository on the fly
188 tmp = util.maketemp()
189 cfg = RawConfigParser()
190 cfg.add_section('gitosis')
191 repositories = os.path.join(tmp, 'repositories')
192 os.mkdir(repositories)
193 cfg.set('gitosis', 'repositories', repositories)
194 generated = os.path.join(tmp, 'generated')
196 cfg.set('gitosis', 'generate-files-in', generated)
197 cfg.add_section('group foo')
198 cfg.set('group foo', 'members', 'jdoe')
199 cfg.set('group foo', 'writable', 'foo')
203 command="git-receive-pack 'foo.git'",
205 eq(os.listdir(repositories), ['foo.git'])
206 assert os.path.isfile(os.path.join(repositories, 'foo.git', 'HEAD'))
208 def test_push_inits_subdir_parent_missing():
209 tmp = util.maketemp()
210 cfg = RawConfigParser()
211 cfg.add_section('gitosis')
212 repositories = os.path.join(tmp, 'repositories')
213 os.mkdir(repositories)
214 cfg.set('gitosis', 'repositories', repositories)
215 generated = os.path.join(tmp, 'generated')
217 cfg.set('gitosis', 'generate-files-in', generated)
218 cfg.add_section('group foo')
219 cfg.set('group foo', 'members', 'jdoe')
220 cfg.set('group foo', 'writable', 'foo/bar')
224 command="git-receive-pack 'foo/bar.git'",
226 eq(os.listdir(repositories), ['foo'])
227 foo = os.path.join(repositories, 'foo')
228 util.check_mode(foo, 0750, is_dir=True)
229 eq(os.listdir(foo), ['bar.git'])
230 assert os.path.isfile(os.path.join(repositories, 'foo', 'bar.git', 'HEAD'))
232 def test_push_inits_subdir_parent_exists():
233 tmp = util.maketemp()
234 cfg = RawConfigParser()
235 cfg.add_section('gitosis')
236 repositories = os.path.join(tmp, 'repositories')
237 os.mkdir(repositories)
238 foo = os.path.join(repositories, 'foo')
239 # silly mode on purpose; not to be touched
241 cfg.set('gitosis', 'repositories', repositories)
242 generated = os.path.join(tmp, 'generated')
244 cfg.set('gitosis', 'generate-files-in', generated)
245 cfg.add_section('group foo')
246 cfg.set('group foo', 'members', 'jdoe')
247 cfg.set('group foo', 'writable', 'foo/bar')
251 command="git-receive-pack 'foo/bar.git'",
253 eq(os.listdir(repositories), ['foo'])
254 util.check_mode(foo, 0751, is_dir=True)
255 eq(os.listdir(foo), ['bar.git'])
256 assert os.path.isfile(os.path.join(repositories, 'foo', 'bar.git', 'HEAD'))
258 def test_push_inits_if_needed_existsWithExtension():
259 tmp = util.maketemp()
260 cfg = RawConfigParser()
261 cfg.add_section('gitosis')
262 repositories = os.path.join(tmp, 'repositories')
263 os.mkdir(repositories)
264 cfg.set('gitosis', 'repositories', repositories)
265 cfg.add_section('group foo')
266 cfg.set('group foo', 'members', 'jdoe')
267 cfg.set('group foo', 'writable', 'foo')
268 os.mkdir(os.path.join(repositories, 'foo.git'))
272 command="git-receive-pack 'foo'",
274 eq(os.listdir(repositories), ['foo.git'])
275 # it should *not* have HEAD here as we just mkdirred it and didn't
276 # create it properly, and the mock repo didn't have anything in
277 # it.. having HEAD implies serve ran git init, which is supposed
278 # to be unnecessary here
279 eq(os.listdir(os.path.join(repositories, 'foo.git')), [])
281 def test_push_inits_no_stdout_spam():
282 # git init has a tendency to spew to stdout, and that confuses
284 tmp = util.maketemp()
285 cfg = RawConfigParser()
286 cfg.add_section('gitosis')
287 repositories = os.path.join(tmp, 'repositories')
288 os.mkdir(repositories)
289 cfg.set('gitosis', 'repositories', repositories)
290 generated = os.path.join(tmp, 'generated')
292 cfg.set('gitosis', 'generate-files-in', generated)
293 cfg.add_section('group foo')
294 cfg.set('group foo', 'members', 'jdoe')
295 cfg.set('group foo', 'writable', 'foo')
296 old_stdout = os.dup(1)
298 new_stdout = os.tmpfile()
299 os.dup2(new_stdout.fileno(), 1)
303 command="git-receive-pack 'foo'",
306 os.dup2(old_stdout, 1)
309 got = new_stdout.read()
312 eq(os.listdir(repositories), ['foo.git'])
313 assert os.path.isfile(os.path.join(repositories, 'foo.git', 'HEAD'))
315 def test_push_inits_sets_description():
316 tmp = util.maketemp()
317 cfg = RawConfigParser()
318 cfg.add_section('gitosis')
319 repositories = os.path.join(tmp, 'repositories')
320 os.mkdir(repositories)
321 cfg.set('gitosis', 'repositories', repositories)
322 generated = os.path.join(tmp, 'generated')
324 cfg.set('gitosis', 'generate-files-in', generated)
325 cfg.add_section('group foo')
326 cfg.set('group foo', 'members', 'jdoe')
327 cfg.set('group foo', 'writable', 'foo')
328 cfg.add_section('repo foo')
329 cfg.set('repo foo', 'description', 'foodesc')
333 command="git-receive-pack 'foo'",
335 eq(os.listdir(repositories), ['foo.git'])
336 path = os.path.join(repositories, 'foo.git', 'description')
337 assert os.path.exists(path)
338 got = util.readFile(path)
341 def test_push_inits_updates_projects_list():
342 tmp = util.maketemp()
343 cfg = RawConfigParser()
344 cfg.add_section('gitosis')
345 repositories = os.path.join(tmp, 'repositories')
346 os.mkdir(repositories)
347 cfg.set('gitosis', 'repositories', repositories)
348 generated = os.path.join(tmp, 'generated')
350 cfg.set('gitosis', 'generate-files-in', generated)
351 cfg.add_section('group foo')
352 cfg.set('group foo', 'members', 'jdoe')
353 cfg.set('group foo', 'writable', 'foo')
354 cfg.add_section('repo foo')
355 cfg.set('repo foo', 'gitweb', 'yes')
356 os.mkdir(os.path.join(repositories, 'gitosis-admin.git'))
360 command="git-receive-pack 'foo'",
363 sorted(os.listdir(repositories)),
364 sorted(['foo.git', 'gitosis-admin.git']),
366 path = os.path.join(generated, 'projects.list')
367 assert os.path.exists(path)
368 got = util.readFile(path)
371 def test_push_inits_sets_export_ok():
372 tmp = util.maketemp()
373 cfg = RawConfigParser()
374 cfg.add_section('gitosis')
375 repositories = os.path.join(tmp, 'repositories')
376 os.mkdir(repositories)
377 cfg.set('gitosis', 'repositories', repositories)
378 generated = os.path.join(tmp, 'generated')
380 cfg.set('gitosis', 'generate-files-in', generated)
381 cfg.add_section('group foo')
382 cfg.set('group foo', 'members', 'jdoe')
383 cfg.set('group foo', 'writable', 'foo')
384 cfg.add_section('repo foo')
385 cfg.set('repo foo', 'daemon', 'yes')
389 command="git-receive-pack 'foo'",
391 eq(os.listdir(repositories), ['foo.git'])
392 path = os.path.join(repositories, 'foo.git', 'git-daemon-export-ok')
393 assert os.path.exists(path)
396 # as the only convenient way to use non-standard SSH ports with
397 # git is via the ssh://user@host:port/path syntax, and that syntax
398 # forces absolute urls, just force convert absolute paths to
399 # relative paths; you'll never really want absolute paths via
401 tmp = util.maketemp()
402 repository.init(os.path.join(tmp, 'foo.git'))
403 cfg = RawConfigParser()
404 cfg.add_section('gitosis')
405 cfg.set('gitosis', 'repositories', tmp)
406 cfg.add_section('group foo')
407 cfg.set('group foo', 'members', 'jdoe')
408 cfg.set('group foo', 'readonly', 'foo')
412 command="git-upload-pack '/foo'",
414 eq(got, "git-upload-pack '%s/foo.git'" % tmp)
416 def test_typo_writeable():
417 tmp = util.maketemp()
418 repository.init(os.path.join(tmp, 'foo.git'))
419 cfg = RawConfigParser()
420 cfg.add_section('gitosis')
421 cfg.set('gitosis', 'repositories', tmp)
422 cfg.add_section('group foo')
423 cfg.set('group foo', 'members', 'jdoe')
424 cfg.set('group foo', 'writeable', 'foo')
425 log = logging.getLogger('gitosis.serve')
427 handler = logging.StreamHandler(buf)
428 log.addHandler(handler)
433 command="git-receive-pack 'foo'",
436 log.removeHandler(handler)
437 eq(got, "git-receive-pack '%s/foo.git'" % tmp)
441 "Repository 'foo' config has typo \"writeable\", shou"
442 +"ld be \"writable\"\n",