Tuesday, September 09, 2014

gitlab hooks and disabling forced push

For people who do not know much about gitlab, it is a "github" equivalent with the possibility of deployment in a local network. Which means, that if your organization is not comfortable of pushing code to an external website like github, you can get all the features that github provides in your local environment.

The installation of gitlab is not an easy process. If you have an ubuntu-type system, you can get a .deb file and simply install it. Else installation is a very tedius task.

After installation and deployment, the first task that you would think about doing is to write some hooks for putting some restrictions and sanitizing the code moving into the different git repos. The trick to enable hooks in gitlab is to modify the "gitlab-shell/hooks/update" file.

On an ubuntu installation, the file can be found in the following folder

/opt/gitlab/embedded/service/gitlab-shell/hooks

But, if you have followed the installation notes - https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md as in the documents, the update file is found in

/home/git/gitlab-shell/hooks

The "update" file is written in ruby. In order to abort a push, we need to exit with a "1" status. Let us create a very simple hook to disable all deletes. Add the following lines to the "update" after the line "require_relative"

require_relative '../lib/gitlab_update'

oldhash = ARGV[1]
newhash = ARGV[2]

cmd = "git cat-file -t #{newhash}"
action = IO.popen(cmd).read

if action == "delete"
    puts "deletes are not allowed"
    exit 1
end

For each push, gitlab's update script receives the old commit hash and the new commit hash. using the "git cat-file" command we are getting the action / method performed. And then we are comparing it with the "delete" string to identify if it is a delete. We are exiting with a "1" to disable a push.

We can also write another hook to disable forced push. But it is easier to modify the "gitlab-shell/lib/gitlab_update.rb" to disable forced push. There is a function here which identifies if this is a forced push. To check forced push simply call this function inside the "exec" function. Here is the code that i added to the "exec" function to disable forced push.

 def exec
    # reset GL_ID env since we already
    # get value from it
    ENV['GL_ID'] = nil

    if forced_push?
      puts "Forced push now allowed!"
      exit 1
    end
......
end