Manage git-daemon-export-ok flags from gitosis config.

This commit is contained in:
Tommi Virtanen 2007-11-17 16:27:21 +02:00
parent 2487c658ba
commit 13c89cdb7d
5 changed files with 253 additions and 5 deletions

View file

@ -6,7 +6,8 @@
- gitosis-lint: check that the user account (e.g. ``git``) looks valid
- git-daemon-export-ok
- create git-daemon-export-ok, description, projects.list etc when
autocreating repositorites?
- guard against *.pub files named -foo.pub or foo;bar.pub

View file

@ -13,8 +13,7 @@ gitweb = no
## Allow git-daemon to publish all known repositories. As with gitweb,
## this can be done globally or per-repository.
## NOT YET IMPLEMENTED.
# daemon-ok = no
daemon = no
## Logging level, one of DEBUG, INFO, WARNING, ERROR, CRITICAL
loglevel = DEBUG
@ -41,8 +40,7 @@ gitweb = yes
owner = John Doe
## Allow git-daemon to publish this repository.
## NOT YET IMPLEMENTED.
# daemon-ok = no
daemon = yes
[gitweb]
## Where to make gitweb link to as it's "home location".

90
gitosis/gitdaemon.py Normal file
View file

@ -0,0 +1,90 @@
import errno
import logging
import os
from ConfigParser import NoSectionError, NoOptionError
log = logging.getLogger('gitosis.gitdaemon')
from gitosis import util
def export_ok_path(repopath):
p = os.path.join(repopath, 'git-daemon-export-ok')
return p
def allow_export(repopath):
p = export_ok_path(repopath)
file(p, 'a').close()
def deny_export(repopath):
p = export_ok_path(repopath)
try:
os.unlink(p)
except OSError, e:
if e.errno == errno.ENOENT:
pass
else:
raise
def _extract_reldir(topdir, dirpath):
if topdir == dirpath:
return '.'
prefix = topdir + '/'
assert dirpath.startswith(prefix)
reldir = dirpath[len(prefix):]
return reldir
def set_export_ok(config):
repositories = util.getRepositoryDir(config)
try:
global_enable = config.getboolean('gitosis', 'daemon')
except (NoSectionError, NoOptionError):
global_enable = False
log.debug(
'Global default is %r',
{True: 'allow', False: 'deny'}.get(global_enable),
)
def _error(e):
if e.errno == errno.ENOENT:
pass
else:
raise e
for (dirpath, dirnames, filenames) \
in os.walk(repositories, onerror=_error):
# oh how many times i have wished for os.walk to report
# topdir and reldir separately, instead of dirpath
reldir = _extract_reldir(
topdir=repositories,
dirpath=dirpath,
)
log.debug('Walking %r, seeing %r', reldir, dirnames)
to_recurse = []
repos = []
for dirname in dirnames:
if dirname.endswith('.git'):
repos.append(dirname)
else:
to_recurse.append(dirname)
dirnames[:] = to_recurse
for repo in repos:
name, ext = os.path.splitext(repo)
if reldir != '.':
name = os.path.join(reldir, name)
assert ext == '.git'
try:
enable = config.getboolean('repo %s' % name, 'daemon')
except (NoSectionError, NoOptionError):
enable = global_enable
if enable:
log.debug('Allow %r', name)
allow_export(os.path.join(dirpath, repo))
else:
log.debug('Deny %r', name)
deny_export(os.path.join(dirpath, repo))

View file

@ -11,6 +11,7 @@ import shutil
from gitosis import repository
from gitosis import ssh
from gitosis import gitweb
from gitosis import gitdaemon
from gitosis import app
def post_update(cfg, git_dir):
@ -31,6 +32,9 @@ def post_update(cfg, git_dir):
config=cfg,
path=os.path.join(git_dir, 'projects.list'),
)
gitdaemon.set_export_ok(
config=cfg,
)
ssh.writeAuthorizedKeys(
path=os.path.expanduser('~/.ssh/authorized_keys'),
keydir=os.path.join(export, 'keydir'),

View file

@ -0,0 +1,155 @@
from nose.tools import eq_ as eq
import os
from ConfigParser import RawConfigParser
from gitosis import gitdaemon
from gitosis.test.util import maketemp, writeFile
def exported(path):
assert os.path.isdir(path)
p = gitdaemon.export_ok_path(path)
return os.path.exists(p)
def test_git_daemon_export_ok_repo_missing():
# configured but not created yet; before first push
tmp = maketemp()
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
cfg.add_section('repo foo')
cfg.set('repo foo', 'daemon', 'yes')
gitdaemon.set_export_ok(config=cfg)
assert not os.path.exists(os.path.join(tmp, 'foo'))
assert not os.path.exists(os.path.join(tmp, 'foo.git'))
def test_git_daemon_export_ok_repo_missing_parent():
# configured but not created yet; before first push
tmp = maketemp()
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
cfg.add_section('repo foo/bar')
cfg.set('repo foo/bar', 'daemon', 'yes')
gitdaemon.set_export_ok(config=cfg)
assert not os.path.exists(os.path.join(tmp, 'foo'))
def test_git_daemon_export_ok_allowed():
tmp = maketemp()
path = os.path.join(tmp, 'foo.git')
os.mkdir(path)
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
cfg.add_section('repo foo')
cfg.set('repo foo', 'daemon', 'yes')
gitdaemon.set_export_ok(config=cfg)
eq(exported(path), True)
def test_git_daemon_export_ok_allowed_already():
tmp = maketemp()
path = os.path.join(tmp, 'foo.git')
os.mkdir(path)
writeFile(gitdaemon.export_ok_path(path), '')
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
cfg.add_section('repo foo')
cfg.set('repo foo', 'daemon', 'yes')
gitdaemon.set_export_ok(config=cfg)
eq(exported(path), True)
def test_git_daemon_export_ok_denied():
tmp = maketemp()
path = os.path.join(tmp, 'foo.git')
os.mkdir(path)
writeFile(gitdaemon.export_ok_path(path), '')
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
cfg.add_section('repo foo')
cfg.set('repo foo', 'daemon', 'no')
gitdaemon.set_export_ok(config=cfg)
eq(exported(path), False)
def test_git_daemon_export_ok_denied_already():
tmp = maketemp()
path = os.path.join(tmp, 'foo.git')
os.mkdir(path)
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
cfg.add_section('repo foo')
cfg.set('repo foo', 'daemon', 'no')
gitdaemon.set_export_ok(config=cfg)
eq(exported(path), False)
def test_git_daemon_export_ok_subdirs():
tmp = maketemp()
foo = os.path.join(tmp, 'foo')
os.mkdir(foo)
path = os.path.join(foo, 'bar.git')
os.mkdir(path)
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
cfg.add_section('repo foo/bar')
cfg.set('repo foo/bar', 'daemon', 'yes')
gitdaemon.set_export_ok(config=cfg)
eq(exported(path), True)
def test_git_daemon_export_ok_denied_default():
tmp = maketemp()
path = os.path.join(tmp, 'foo.git')
os.mkdir(path)
writeFile(gitdaemon.export_ok_path(path), '')
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
cfg.add_section('repo foo')
gitdaemon.set_export_ok(config=cfg)
eq(exported(path), False)
def test_git_daemon_export_ok_denied_even_not_configured():
# repositories not mentioned in config also get touched; this is
# to avoid security trouble, otherwise we might expose (or
# continue to expose) old repositories removed from config
tmp = maketemp()
path = os.path.join(tmp, 'foo.git')
os.mkdir(path)
writeFile(gitdaemon.export_ok_path(path), '')
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
gitdaemon.set_export_ok(config=cfg)
eq(exported(path), False)
def test_git_daemon_export_ok_allowed_global():
tmp = maketemp()
for repo in [
'foo.git',
'quux.git',
'thud.git',
]:
path = os.path.join(tmp, repo)
os.mkdir(path)
# try to provoke an invalid allow
writeFile(gitdaemon.export_ok_path(os.path.join(tmp, 'thud.git')), '')
cfg = RawConfigParser()
cfg.add_section('gitosis')
cfg.set('gitosis', 'repositories', tmp)
cfg.set('gitosis', 'daemon', 'yes')
cfg.add_section('repo foo')
cfg.add_section('repo quux')
# same as default, no effect
cfg.set('repo quux', 'daemon', 'yes')
cfg.add_section('repo thud')
# this is still hidden
cfg.set('repo thud', 'daemon', 'no')
gitdaemon.set_export_ok(config=cfg)
eq(exported(os.path.join(tmp, 'foo.git')), True)
eq(exported(os.path.join(tmp, 'quux.git')), True)
eq(exported(os.path.join(tmp, 'thud.git')), False)