Basic access to a git
repository is fairly easy.
You specify --shared
when initializing your bare
repository, chgrp <your group>
to the repository directory and your done. Now everyone in <your group>
has read and write access to the repository with their account.
So what do I need?
- An easy way to tell which user can actually write or not
- A solution easy to integrate with my actual configuration manager - Here rudder/cfengine
Gitolite - to name the widely used tool for this kind of case - requires to install a bunch of script files, set a common git user, and store all its settings in a specific git
repository. Definitely not practical to integrate in a configuration management tool.
How to do it then?
It is actually very easy to achieve these requirements with only basic linux settings and git
hooks.
- Read access:
- ssh + user group
- Write access:
git
hook + acl file
Create your new git
repository:
git init --bare --shared <repo>
chgrp -R <your group> <repo>
chmod o-rx <repo>
ls -ld <repo>
drwxrws--- 7 root <your group> 10 Oct 21 09:40 <repo>
Replace <repo>/hooks/update
by the following python
script.
This script checks the type of command you're sending and validates if your username is listed in the git.acl
file and exits accordingly.
#!/bin/env python
import os, sys, subprocess, ConfigParser
refname = sys.argv[1]
oldrev = sys.argv[2]
newrev = sys.argv[3]
user = os.getenv('USER')
revtype = ['commit', 'delete', 'tag']
config = ConfigParser.RawConfigParser()
config.read('./git.acl')
users = config.get('users', 'write').split()
print refname
print "oldrev="+oldrev
print "newrev="+newrev
print user
cmd = 'git cat-file -t %s' % (newrev)
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=None, shell=True)
output = process.communicate()
thistype = output[0][:-1]
if ( thistype in revtype and not user in users):
print "!!! You're not authorized to push code to this repo"
sys.exit(1)
sys.exit(0)
Here is <repo>/hooks/git.acl
[users]
write = admin joe bob brad
The script could easily be extented to do more granular rights - allow pushing to branches but not to master, which branches a user could push to, etc... - while still being very easy to deploy using your favorite configuration management tool.