Example #1
0
def post_update(cfg, git_dir):
    export = os.path.join(git_dir, 'gitosis-export')
    try:
        shutil.rmtree(export)
    except OSError as e:
        if e.errno == errno.ENOENT:
            pass
        else:
            raise
    repository.export(git_dir=git_dir, path=export)
    os.rename(
        os.path.join(export, 'gitosis.conf'),
        os.path.join(export, '..', 'gitosis.conf'),
    )
    # re-read config to get up-to-date settings
    cfg.read(os.path.join(export, '..', 'gitosis.conf'))
    gitweb.set_descriptions(config=cfg, )
    generated = util.getGeneratedFilesDir(config=cfg)
    gitweb.generate_project_list(
        config=cfg,
        path=os.path.join(generated, 'projects.list'),
    )
    gitdaemon.set_export_ok(config=cfg, )
    authorized_keys = util.getSSHAuthorizedKeysPath(config=cfg)
    ssh.writeAuthorizedKeys(
        path=authorized_keys,
        keydir=os.path.join(export, 'keydir'),
    )
Example #2
0
def test_git_daemon_export_ok_allowed_all():
    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-if-all", "yes")
    cfg.add_section("group all")
    cfg.set("group all", "readonly", "foo")
    cfg.add_section("group boo")
    cfg.set("group boo", "members", "@all")
    cfg.set("group boo", "readonly", "quux thud")
    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)
Example #3
0
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)
Example #4
0
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)
Example #5
0
def test_git_daemon_export_ok_allowed_all():
    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-if-all', 'yes')
    cfg.add_section('group all')
    cfg.set('group all', 'readonly', 'foo')
    cfg.add_section('group boo')
    cfg.set('group boo', 'members', '@all')
    cfg.set('group boo', 'readonly', 'quux thud')
    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)
Example #6
0
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"))
Example #7
0
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'))
Example #8
0
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)
Example #9
0
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)
Example #10
0
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)
Example #11
0
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)
Example #12
0
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)
Example #13
0
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)
Example #14
0
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)
Example #15
0
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)
Example #16
0
    repository.export(git_dir=git_dir, path=export)

    os.rename(
        os.path.join(export, 'gitosis.conf'),
        os.path.join(export, '..', 'gitosis.conf'),
        )

    cfg.read(os.path.join(export, '..', 'gitosis.conf'))

    gitweb.set_descriptions(
        config=cfg,
        )
    generated = util.getGeneratedFilesDir(config=cfg)
    gitweb.write_project_list(cfg,
        os.path.join(generated, 'projects.list'))
    gitdaemon.set_export_ok(cfg)
    authorized_keys = util.getSSHAuthorizedKeysPath(config=cfg)
    ssh.writeAuthorizedKeys(authorized_keys, os.path.join(export, 'keydir'))

class Main(app.App):
    def create_parser(self):
        parser = super(Main, self).create_parser()
        parser.set_usage('%prog [OPTS] HOOK')
        parser.set_description(
            'Perform gitosis actions for a git hook')
        return parser

    def handle_args(self, parser, cfg, options, args):
        try:
            (hook,) = args
        except ValueError:
Example #17
0
def serve(
    cfg,
    user,
    command,
    ):
    if '\n' in command:
        raise CommandMayNotContainNewlineError()

    try:
        verb, args = command.split(None, 1)
    except ValueError:
        # all known "git-foo" commands take one argument; improve
        # if/when needed
        raise UnknownCommandError()

    if verb == 'git':
        try:
            subverb, args = args.split(None, 1)
        except ValueError:
            # all known "git foo" commands take one argument; improve
            # if/when needed
            raise UnknownCommandError()
        verb = '%s %s' % (verb, subverb)

    if (verb not in COMMANDS_WRITE
        and verb not in COMMANDS_READONLY):
        raise UnknownCommandError()

    match = ALLOW_RE.match(args)
    if match is None:
        raise UnsafeArgumentsError()

    path = match.group('path')

    # write access is always sufficient
    newpath = access.haveAccess(
        config=cfg,
        user=user,
        mode='writable',
        path=path)

    if newpath is None:
        # didn't have write access; try once more with the popular
        # misspelling
        newpath = access.haveAccess(
            config=cfg,
            user=user,
            mode='writeable',
            path=path)
        if newpath is not None:
            log.warning(
                'Repository %r config has typo "writeable", '
                +'should be "writable"',
                path,
                )

    if newpath is None:
        # didn't have write access

        newpath = access.haveAccess(
            config=cfg,
            user=user,
            mode='readonly',
            path=path)

        if newpath is None:
            raise ReadAccessDenied()

        if verb in COMMANDS_WRITE:
            # didn't have write access and tried to write
            raise WriteAccessDenied()

    (topdir, relpath) = newpath
    assert not relpath.endswith('.git'), \
           'git extension should have been stripped: %r' % relpath
    repopath = '%s.git' % relpath
    fullpath = os.path.join(topdir, repopath)
    if (not os.path.exists(fullpath)
        and verb in COMMANDS_WRITE):
        # it doesn't exist on the filesystem, but the configuration
        # refers to it, we're serving a write request, and the user is
        # authorized to do that: create the repository on the fly

        # create leading directories
        p = topdir
        for segment in repopath.split(os.sep)[:-1]:
            p = os.path.join(p, segment)
            util.mkdir(p, 0755)

        repository.init(path=fullpath)
        gitweb.set_descriptions(
            config=cfg,
            )
        generated = util.getGeneratedFilesDir(config=cfg)
        gitweb.generate_project_list(
            config=cfg,
            path=os.path.join(generated, 'projects.list'),
            )
        gitdaemon.set_export_ok(
            config=cfg,
            )

    # put the verb back together with the new path
    newcmd = "%(verb)s '%(path)s'" % dict(
        verb=verb,
        path=fullpath,
        )
    return newcmd
Example #18
0
        os.path.join(export, 'gitosis.conf'),
        os.path.join(export, '..', 'gitosis.conf'),
        )
    # re-read config to get up-to-date settings
    cfg.read(os.path.join(export, '..', 'gitosis.conf'))
    autoinit_repos(config=cfg)
    gitweb.set_descriptions(
        config=cfg,
        )
    generated = util.getGeneratedFilesDir(config=cfg)
    gitweb.generate_project_list(
        config=cfg,
        path=os.path.join(generated, 'projects.list'),
        )
    gitdaemon.set_export_ok(
        config=cfg,
        )
    if htaccess.gen_htaccess_if_enabled(config=cfg):
        group.generate_group_list(
            config=cfg,
            path=os.path.join(generated, 'groups'),
            )
    authorized_keys = util.getSSHAuthorizedKeysPath(config=cfg)
    ssh.writeAuthorizedKeys(
        path=authorized_keys,
        keydir=os.path.join(export, 'keydir'),
        )

def update_mirrors(cfg, git_dir):
    mirror.push_mirrors(cfg, git_dir)
Example #19
0
    os.rename(
        os.path.join(export, 'gitosis.conf'),
        os.path.join(export, '..', 'gitosis.conf'),
        )
    # re-read config to get up-to-date settings
    cfg.read(os.path.join(export, '..', 'gitosis.conf'))
    gitweb.set_descriptions(
        config=cfg,
        )
    generated = util.getGeneratedFilesDir(config=cfg)
    gitweb.generate_project_list(
        config=cfg,
        path=os.path.join(generated, 'projects.list'),
        )
    gitdaemon.set_export_ok(
        config=cfg,
        )
    authorized_keys = util.getSSHAuthorizedKeysPath(config=cfg)
    ssh.writeAuthorizedKeys(
        path=authorized_keys,
        keydir=os.path.join(export, 'keydir'),
        )

class Main(app.App):
    def create_parser(self):
        parser = super(Main, self).create_parser()
        parser.set_usage('%prog [OPTS] HOOK')
        parser.set_description(
            'Perform gitosis actions for a git hook')
        return parser
Example #20
0
def serve(
    cfg,
    user,
    command,
    ):
    if '\n' in command:
        raise CommandMayNotContainNewlineError()
    
    try:
        verb, args = command.split(None, 1)
    except ValueError:
        # all known "git-foo" commands take one argument; improve
        # if/when needed
        raise UnknownCommandError()

    if verb == 'git':
        try:
            subverb, args = args.split(None, 1)
        except ValueError:
            # all known "git foo" commands take one argument; improve
            # if/when needed
            raise UnknownCommandError()
        verb = '%s %s' % (verb, subverb)

    if (verb not in COMMANDS_WRITE
        and verb not in COMMANDS_READONLY):
        raise UnknownCommandError()

    match = ALLOW_RE.match(args)
    if match is None:
        raise UnsafeArgumentsError()

    path = match.group('path')

    # write access is always sufficient
    newpath = access.haveAccess(
        config=cfg,
        user=user,
        mode='writable',
        path=path)

    if newpath is None:
        # didn't have write access; try once more with the popular
        # misspelling
        newpath = access.haveAccess(
            config=cfg,
            user=user,
            mode='writeable',
            path=path)
        if newpath is not None:
            log.warning(
                'Repository %r config has typo "writeable", '
                +'should be "writable"',
                path,
                )

    if newpath is None:
        # didn't have write access

        newpath = access.haveAccess(
            config=cfg,
            user=user,
            mode='readonly',
            path=path)

        if newpath is None:
            raise ReadAccessDenied()

        if verb in COMMANDS_WRITE:
            # didn't have write access and tried to write
            raise WriteAccessDenied()

    (topdir, relpath) = newpath
    assert not relpath.endswith('.git'), \
           'git extension should have been stripped: %r' % relpath
    repopath = '%s.git' % relpath
    fullpath = os.path.join(topdir, repopath)
    if not os.path.exists(fullpath):
        # it doesn't exist on the filesystem, but the configuration
        # refers to it, we're serving a write request, and the user is
        # authorized to do that: create the repository on the fly

        # create leading directories
        p = topdir
        for segment in repopath.split(os.sep)[:-1]:
            p = os.path.join(p, segment)
            util.mkdir(p, 0750)

        repository.init(path=fullpath)
        gitweb.set_descriptions(
            config=cfg,
            )
        generated = util.getGeneratedFilesDir(config=cfg)
        gitweb.generate_project_list(
            config=cfg,
            path=os.path.join(generated, 'projects.list'),
            )
        gitdaemon.set_export_ok(
            config=cfg,
            )

    # put the verb back together with the new path
    newcmd = "%(verb)s '%(path)s'" % dict(
        verb=verb,
        path=fullpath,
        )
    return newcmd
Example #21
0
def serve(
    cfg,
    user,
    command,
    ):
    if '\n' in command:
        raise CommandMayNotContainNewlineError()

    try:
        verb, args = command.split(None, 1)
    except ValueError:
        # all known "git-foo" commands take one argument; improve
        # if/when needed
        raise UnknownCommandError()

    if verb == 'git':
        try:
            subverb, args = args.split(None, 1)
        except ValueError:
            # all known "git foo" commands take one argument; improve
            # if/when needed
            raise UnknownCommandError()
        verb = '%s %s' % (verb, subverb)
    elif verb == 'cvs':
        try:
            args, server = args.split(None, 1)
        except:
            raise UnknownCommandError()
        if server != 'server':
            raise UnknownCommandError()

        path = path_from_args(args)

        newpath = path_for_write(cfg=cfg, user=user, path=path)
        if newpath is None:
            raise WriteAccessDenied()

        (topdir, repopath) = construct_path(newpath)

        # Put the repository and base path in the environment
        repos_dir = util.getRepositoryDir(cfg)
        fullpath = os.path.join(repos_dir, repopath)
        os.environ['GIT_CVSSERVER_BASE_PATH'] = repos_dir
        os.environ['GIT_CVSSERVER_ROOTS'] = fullpath

        # Put the user's information in the environment
        try:
            section = 'user %s' % user
            name = cfg.get(section, 'name')
            email = cfg.get(section, 'email')
        except:
            log.error('Missing name or email for user "%s"' % user)
            raise WriteAccessDenied()
        os.environ['GIT_AUTHOR_NAME'] = name
        os.environ['GIT_AUTHOR_EMAIL'] = email

        return 'cvs server'

    if (verb not in COMMANDS_WRITE
        and verb not in COMMANDS_READONLY):
        raise UnknownCommandError()

    path = path_from_args(args)

    # write access is always sufficient
    newpath = path_for_write(
        cfg=cfg,
        user=user,
        path=path)

    if newpath is None:
        # didn't have write access

        newpath = access.haveAccess(
            config=cfg,
            user=user,
            mode='readonly',
            path=path)

        if newpath is None:
            raise ReadAccessDenied()

        if verb in COMMANDS_WRITE:
            # didn't have write access and tried to write
            raise WriteAccessDenied()

    (topdir, repopath) = construct_path(newpath)
    fullpath = os.path.join(topdir, repopath)
    if not os.path.exists(fullpath):
        # it doesn't exist on the filesystem, but the configuration
        # refers to it, we're serving a write request, and the user is
        # authorized to do that: create the repository on the fly
        auto_init_repo(cfg,topdir,repopath)
        gitweb.set_descriptions(
            config=cfg,
            )
        generated = util.getGeneratedFilesDir(config=cfg)
        gitweb.generate_project_list(
            config=cfg,
            path=os.path.join(generated, 'projects.list'),
            )
        gitdaemon.set_export_ok(
            config=cfg,
            )
        htaccess.gen_htaccess_if_enabled(
            config=cfg,
            )

    # put the verb back together with the new path
    newcmd = "%(verb)s '%(path)s'" % dict(
        verb=verb,
        path=fullpath,
        )
    return newcmd