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 - 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 - 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, ## Allow git-daemon to publish all known repositories. As with gitweb,
## this can be done globally or per-repository. ## this can be done globally or per-repository.
## NOT YET IMPLEMENTED. daemon = no
# daemon-ok = no
## Logging level, one of DEBUG, INFO, WARNING, ERROR, CRITICAL ## Logging level, one of DEBUG, INFO, WARNING, ERROR, CRITICAL
loglevel = DEBUG loglevel = DEBUG
@ -41,8 +40,7 @@ gitweb = yes
owner = John Doe owner = John Doe
## Allow git-daemon to publish this repository. ## Allow git-daemon to publish this repository.
## NOT YET IMPLEMENTED. daemon = yes
# daemon-ok = no
[gitweb] [gitweb]
## Where to make gitweb link to as it's "home location". ## 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 repository
from gitosis import ssh from gitosis import ssh
from gitosis import gitweb from gitosis import gitweb
from gitosis import gitdaemon
from gitosis import app from gitosis import app
def post_update(cfg, git_dir): def post_update(cfg, git_dir):
@ -31,6 +32,9 @@ def post_update(cfg, git_dir):
config=cfg, config=cfg,
path=os.path.join(git_dir, 'projects.list'), path=os.path.join(git_dir, 'projects.list'),
) )
gitdaemon.set_export_ok(
config=cfg,
)
ssh.writeAuthorizedKeys( ssh.writeAuthorizedKeys(
path=os.path.expanduser('~/.ssh/authorized_keys'), path=os.path.expanduser('~/.ssh/authorized_keys'),
keydir=os.path.join(export, 'keydir'), 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)