4

I am running a gitlab git server.

Most of my users are running 1 of 3 versions of git.

git 1.7.1 (centos users)
git 1.7.9 (everyone else)
git 1.8.4 (mac users)

Some users have accidentally been committing and pushing code as the root user. I need to block commits from those users.

My pre-commit hook looks like this:

#!/bin/bash

if [[ $GIT_AUTHOR_NAME == 'root' ]]
then
    echo "If you commit as root, you're gonna have a bad time";
    echo "Set 'git config user.name' and try again";
    exit 1;
fi

This works as a pre-commit hook on 1.7.9 and 1.8.x but not 1.7.1

According to this blog, pre receive and post receive hooks do not have any of the environment variables that I am looking for ( GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, GIT_COMMITTER_DATE, EMAIL ).

Is there any way to modify this pre-commit hook to block root users on older versions of git?

http://longair.net/blog/2011/04/09/missing-git-hooks-documentation/

spuder
  • 17,437
  • 19
  • 87
  • 153

3 Answers3

1

Why don't you put the check in a pre-receive hook i.e., do the authetication on the server side when the code is about to be committed to the central git repository/server.

#Extract commiter names here.
commiters=$(git log --pretty=format:"%cn" $revs) #This should work in all git versions

printf "$commiters\n" | while read name; do
     if [[ $name == "root" ]]; then
      echo "You are commiting as root user which I don't like. Reveal your identity!"
      exit 1
     fi
done
Mayur Nagekar
  • 813
  • 5
  • 13
  • This is great. It has two minor problems: 1. It is case sensitive 2. If a commit has *ever* happened from root, then the script will exit with 1. – spuder Mar 19 '14 at 16:26
  • You can make it case insensitive. That shouldn't be a hard thing to do. Regarding your point #2, didn't you want to block any commit from root ? Hence, exit when you find any commit from root. – Mayur Nagekar Mar 19 '14 at 21:49
  • Yes, however some commits from root already exist in the history. I need to just block root going forward. – spuder Mar 20 '14 at 17:32
  • You got two options in that case. First, change the committer name from root to whatever you deem appropriate. Second, Let the commits from root be pushed into the central repository and then put this hook onto the git server so that further commits with root as the commiter are thrown out. – Mayur Nagekar Mar 20 '14 at 21:51
0

Set up e.g. gitolite (there should be packages for your server's system), and configure it so that only approved users can push. If they switch to root the credentials won't match, and the push will be refused. It gives you detailed control over the branches each one has access to.

vonbrand
  • 11,412
  • 8
  • 32
  • 52
0

You can encourage your users to use the pre-commit hook on their side as a mitigation, but ultimately your will have to reject the pushes on the server side to have the policy fully enforced.

One thing that you can do is to employ an update hook that will reject pushes of commits that have been made by the root author. Add this to your .git/hooks/update:

git log --format="%h %an" ${2}..${3} | while read COMMIT_HASH COMMIT_AUTHOR; do
    if [ "$COMMIT_AUTHOR" = "root" ]; then
        echo "Updating ${1} by root is not allowed, offending commit: $COMMIT_HASH"
        exit 1
    fi
done

The snippet will parse all the commits between the old revisions and the new revision being pushed and will reject the push if any of these commits has root as the author. Also, make sure that the hook is executable!

mockinterface
  • 14,452
  • 5
  • 28
  • 49
  • What does ${2}..${3} do? When I include those parameters, I get the error "fatal: ..: '..' is outside repository" – spuder Mar 19 '14 at 18:11
  • The update hooks gets command line arguments from git. The $1 argument is the ref updated, $2 is the old revision and $3 is the new revision. So `$2..$3` is the set of commits pushed to your server, reachable from the new revision (typically the new tip of branch). If you started a new repo to experiment you may want to print/echo the arguments to debug, and maybe check for emptyness. – mockinterface Mar 19 '14 at 20:05
  • @spuder Additionally, refer to the `update.sample` hook in the `.git/hooks` directory - you'll find that it's a very good example. – mockinterface Mar 19 '14 at 20:15
  • @mockinterface there isn't anything looking like this in my .git/hooks/update.sample. I have git 1.8.3.1 on centos 7. –  Dec 03 '15 at 16:43