5

I am looking to write a pre-receive githook in Python. It is my understanding that no arguments are passed into pre-receive scripts but rather each reference is passed in using standard input on separate lines. I have been able to read the reference changes via:

!/usr/bin/env python

import sys
import fileinput

for line in fileinput.input():
    print "pre-receive: Trying to push ref: %s" % line

However, for this hook, I am mainly concerned with making sure that the user pushing code has the correct privileges to push to the branch of which they are trying to. Through my research, I have been unable to find a way to seek the committer's user credentials. It was my goal to compare their creds against a whitelist in order to grant access.

How can I change my pre-receive code to authenticate the committing user and verify that they are whitelisted to push to their attempted branch? And what, if any, changes do I have to make on the git repository to make the code function?

Dylan Wheeler
  • 6,928
  • 14
  • 56
  • 80
  • This won't help with the Python part, but Gitolite (mostly Perl) relies on ssh: you force users to ssh in as `git@host.dom.ain` and use the AuthorizedKeys settings to run a proxy command. See sshd documentation and `SSH_ORIGINAL_COMMAND`, and http://gitolite.com/gitolite/how.html (note that the user name is passed as an argument here). – torek Jun 24 '16 at 23:12

2 Answers2

8

From the stdin, we can get <old-value> SP <new-value> SP <ref-name> LF. Use git cat-file -p $new-value or git cat-file -p $ref-name in the hook, we can get info like this

tree d06734b17feff2faf22bcd7c0fac1587876e601d
parent 524bd5e2fa72e6358a22f28582e094de936c3768
author Xyz <mm@nn.com> 1466782764 +0800
committer Abc <ss@tt.com> 1466782764 +0800

Or in a more straightforward way, we can use git log -1 --pretty=%an $ref-name to get the author, and git log -1 --pretty=%cn $ref-name to get the committer.

So a part of the hook in bash could be like:

#!/bin/bash

read old new ref
author=$(git log -1 $ref --pretty=%an)
committer=$(git log -1 $ref --pretty=%cn)
echo author:$author
echo committer:$committer

The left part is to check if the author or committer has the right to do something.

My version to implement your hook in python would be

#!/usr/bin/env python

import sys
import fileinput
import commands

for line in fileinput.input():
    print "pre-receive: Trying to push ref: %s" % line
    values = line.split()
    old = values[0]
    new = values[1]
    ref = values[2]
    author = ''
    committer = ''
    status,output = commands.getstatusoutput('git log -1 --pretty=%an {0}'.format(ref))
    if status == 0:
        author = output
    status,output = commands.getstatusoutput('git log -1 --pretty=%cn {0}'.format(ref))
    if status == 0:
        committer = output
ElpieKay
  • 27,194
  • 6
  • 32
  • 53
2

If you are using git over ssh (or git in the local file system) the committing user will be available to the hook in the environment variable USER, so in python you can check against os.environ['USER']

It is possible to set up an environment (using git-daemon; there are other ways as well) where your git server receives a pack and there is no authenticating information at all attached; in that case you are out of luck.

antlersoft
  • 14,636
  • 4
  • 35
  • 55
  • Following up: what other environment variables does git provide? I am fairly new on a development team right now, and I am not sure if we are using SSH (I would assume so but not sure). How can I check to make sure this is the case? What do I use if this is not the case? – Dylan Wheeler Jun 24 '16 at 14:27
  • @Configure - I don't think git itself is guaranteed to provide --any-- environment variables; they are set (if they are set) by the transfer protocol. ssh will set the USER environment variable; you are using ssh if your git URL's (with which you set up your remotes) start with ssh:. – antlersoft Jun 24 '16 at 14:37
  • You can easily check your environment variables with `import os; print os.environ`. No guarantee they'll always be there, though. – Wayne Werner Jun 24 '16 at 14:37