Talk:Gitosis

Do not edit your own .ssh/authorized_keys
Just to note gitosis generates it's own  file. So if you edit this when you first create the SSH account things will fail. Suki 13:08, 30 March 2009 (UTC)

Allowing http based repository access
Suki 10:09, 31 March 2009 (UTC)

Because it is not allowed to run git-daemon on a shared Dreamhost I still wanted a way for public repositories to be available to clone publicly. Gitosis offers great access control for the read write operations via SSH.

This is what I did to get http repository support for the Gitosis install described here. I had to patch the Gitosis code to allow public repositories access. But first let me describe to you my directory setup.

As per the default install Gitosis creates a  directory in your $HOME folder. By default all git repositories that are created here have the directory permissions of 750 (or Owner read,write,execute; Group read,write ; Other nothing) what this means is that if you attempt to symlink to this directory the webserver (and thus a git clone opperation) will fail with access denied.

So first mission is to set all public repositories permissions to 755 allowing the Other group read access to the public repositories. The patch mentioned will do this automatically for all repositories that have  set (or all if globally set)

The second hurtle is that the repositories directory sits outside the website document root. Meaning that you have to access these public repositories via symlinks.


 * Why not place the repositories directory inside the web document root? Because this would expose private repositories including gitosis-admin!

The patch mentioned will automatically add a symlink to the proper public directory within the document root.

So this is how it works. Apply the patch at the bottom of this page. (You can upload this via ftp or use copy / paste to a running editor via ssh.) cd cd src/gitosis patch -p1 < $HOME/0001-patched-for-dreamhost-custom-config.patch Now continue the instructions to install gitosis python setup.py install --prefix=$HOME

Next make the appropriate public directory. For me I created a sub-domain for this user using dreamhost's web panel (For this I will use example.com) cd cd git.example.com mkdir repos Once complete follow the instructions to edit your gitosis-admin and add the following to the  section. public_html_path = /home/gituser/git.example.com/repos

In your gitweb.conf be sure to put in @git_base_url_list = ('http://git.example.com/repos');

0001-Added-Apache-htaccess-patch-for-public-http-access.patch
From 6ad425d93f2be765105d56af03e273cf84969d4c Mon Sep 17 00:00:00 2001 From: Devin Weaver  Date: Fri, 12 Jun 2009 00:59:11 -0400 Subject: [PATCH] Added Apache htaccess patch for public http access.

Dreamhost and some other hosting services do not allow public access to a git repository via git-daemon. This is a patch that will enable a set of Apache htaccess files that disallow access to non public repositories while allowing public anonymous access via the http protocal. The repositories directory must be within the DocumentRoot. Use ``public_http = YES`` in a repo section to enable this feature. This also includes the following patch:

Fixed permissions problem.

It seems that when the setup.py script builds the package it does not honor the executable permissions for the admin/hooks/post-update. This means that when the gitosis-admin.git is updated the changes are not realized until someone attepts gitosis-serve or a second commit is done. Added a hack to set the permissions when the initial gitosis-admin.git repository is created. --- gitosis/gitweb.py    |  104 +++++++++++++++++++++++++++++++++++++++++++++++++ gitosis/init.py      |    3 + gitosis/repository.py |   3 +- gitosis/run_hook.py  |    1 + gitosis/serve.py     |    4 +- 5 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/gitosis/gitweb.py b/gitosis/gitweb.py index b4b538b..63e5b5d 100644 --- a/gitosis/gitweb.py +++ b/gitosis/gitweb.py @@ -163,3 +163,107 @@ def set_descriptions(config): finally: f.close os.rename(tmp, path) + + +def generate_public_htaccess(config): +   """ +    Generate Apache htaccess files that will allow only ``public_http`` +    enabled repos access via http. + +    :param config: configuration to read projects from +    :type config: RawConfigParser +    """ +   log = logging.getLogger('gitosis.gitweb.generate_public_htaccess') + +   log.info('Generating public http htaccess files if needed.') +   path = os.path.join(util.getGeneratedFilesDir(config), 'htaccess') +   tmp_file = '%s.%d.tmp' % (path, os.getpid) + +   repositories = util.getRepositoryDir(config) + +   is_htaccess_used = False + +   try: +       global_enable = config.getboolean('gitosis', 'public_http') +   except (NoSectionError, NoOptionError): +       global_enable = False + +   for section in config.sections: +       l = section.split(None, 1) +       type_ = l.pop(0) +       if type_ != 'repo': +           continue +       if not l: +            continue + +       try: +           enable = config.getboolean(section, 'public_http') +       except (NoSectionError, NoOptionError): +           enable = global_enable + +       name, = l + +       if enable: +           is_htaccess_used = True + +       if not os.path.exists(os.path.join(repositories, name)): +           namedotgit = '%s.git' % name +           if os.path.exists(os.path.join(repositories, namedotgit)): +               name = namedotgit +           else: +               log.warning( +                    'Cannot find %(name)r in %(repositories)r' +                    % dict(name=name, repositories=repositories)) +               continue + +       if not enable: +           disabled_htaccess = os.path.join(repositories, name, '.htaccess') +           if os.path.exists(disabled_htaccess): +               log.debug('Removing .htaccess from repository %s' % name) +               os.unlink(disabled_htaccess) +           continue + +# Create .htaccess file for public repo. +       log.debug('Generating .htaccess for repository %s' % name) +       fp = file(tmp_file, 'w') +       try: +           print >>fp, "# This is a generated document by gitosis." +           print >>fp, "# DO NOT EDIT. Changes will be lost." +           print >>fp, "Order Allow,Deny" +           print >>fp, "Allow from all" +       finally: +           fp.close +       os.rename(tmp_file, os.path.join(repositories, name, '.htaccess')) + +# Create post-update hook for public repo. +       log.debug('Generating post-update hook for repository %s' % name) +       fp = file(tmp_file, 'w') +       try: +           print >>fp, "#!/bin/sh" +           print >>fp, "# This is a generated document by gitosis." +           print >>fp, "# DO NOT EDIT. Changes will be lost." +           print >>fp +           print >>fp, "exec git-update-server-info" +       finally: +           fp.close +       hook = os.path.join(repositories, name, 'hooks', 'post-update') +       os.chmod(tmp_file, 0755) +       os.rename(tmp_file, hook) + +# Force Apache to refuse all connections in the repository. Public access is +# overridden by the existance of the above htaccess per repository. +   log.debug('Generating .htaccess for main repository directory') +   repo_htaccess = os.path.join(util.getRepositoryDir(config), '.htaccess') +   if is_htaccess_used: +       fp = file(tmp_file, 'w') +       try: +           print >>fp, "# This is a generated document by gitosis." +           print >>fp, "# DO NOT EDIT. Changes will be lost." +           print >>fp, "Order Deny,Allow" +           print >>fp, "Deny from all" +       finally: +           fp.close +       os.rename(tmp_file, repo_htaccess) +   elif os.path.exists(repo_htaccess): +       log.debug('Removing .htaccess for main repository directory') +       os.unlink(repo_htaccess) diff --git a/gitosis/init.py b/gitosis/init.py index 87ad9a7..c77a130 100644 --- a/gitosis/init.py +++ b/gitosis/init.py @@ -77,6 +77,9 @@ def init_admin_repository(    repository.init( path=git_dir, ) +   # The setup.py does not appear to honor the execute permissions of the +    # template files when packaged. Force executable here. +    os.chmod(os.path.join(git_dir, 'hooks', 'post-update'), 0755)     if not repository.has_initial_commit(git_dir):         log.info('Making initial commit...')         # ConfigParser does not guarantee order, so jump through hoops diff --git a/gitosis/repository.py b/gitosis/repository.py index 092e41d..7b8d8c0 100644 --- a/gitosis/repository.py +++ b/gitosis/repository.py @@ -36,7 +36,8 @@ def init( if _git is None: _git = 'git' -   util.mkdir(path, 0750) +   #util.mkdir(path, 0750) +   util.mkdir(path, 0755) # Needed for HTTP access. Less secure. args = [ _git, '--git-dir=.', diff --git a/gitosis/run_hook.py b/gitosis/run_hook.py index e535e6a..4379d09 100644 --- a/gitosis/run_hook.py +++ b/gitosis/run_hook.py @@ -39,6 +39,7 @@ def post_update(cfg, git_dir): config=cfg, path=os.path.join(generated, 'projects.list'), ) +   gitweb.generate_public_htaccess(config=cfg)     gitdaemon.set_export_ok( config=cfg, ) diff --git a/gitosis/serve.py b/gitosis/serve.py index 867249e..2cfc756 100644 --- a/gitosis/serve.py +++ b/gitosis/serve.py @@ -140,7 +140,8 @@ def serve( p = topdir for segment in repopath.split(os.sep)[:-1]: p = os.path.join(p, segment) -           util.mkdir(p, 0750) +           #util.mkdir(p, 0750) +           util.mkdir(p, 0755) # Needed for HTTP access. Less secure. repository.init(path=fullpath) gitweb.set_descriptions( @@ -151,6 +152,7 @@ def serve( config=cfg, path=os.path.join(generated, 'projects.list'), ) +       gitweb.generate_public_htaccess(config=cfg)         gitdaemon.set_export_ok( config=cfg, ) -- 1.6.3.1

Sample gitosis.conf
[gitosis] loglevel = ERROR daemon = no gitweb = no public_http = no

[group gitosis-admin] writable = gitosis-admin members = gituser@remote.host

[group wwwdocs] writable = wwwdocs members = @gitosis-admin

[repo testrepo] gitweb = yes public_http = yes owner = gituser description = A test repository

[group testrepo] writable = testrepo members = @gitosis-admin

Where to copy the public key
The instructions suggested that you should copy the SSH public key to ~/tmp using scp. This won't work because most users don't have a ~/tmp directory. Also there was a typo in the command so that the key would be copied to /tmp instead. I have now changed the instructions so that the key is copied to the home directory (~/) and deleted after use. --Marzol3 03:21, 4 June 2011 (PDT)