Reject unknown/dummy user commits

192 views
Skip to first unread message

tombert

unread,
Sep 22, 2014, 10:26:45 AM9/22/14
to gitl...@googlegroups.com
Hi,

before using GitLab I had a receive hook rejecting the push when the last commit was from an unknown user.
So it was mandatory that they had user.name correctly configured - avoiding commits from "dummy" users.

I would like to have the same hook in GitLab.
One idea would be directly accessing the database and read the users list.

Does someone know a similar implementation I can make use of? Is this something that could be worth as a feature request?

thx

Sytse Sijbrandij

unread,
Sep 22, 2014, 1:45:37 PM9/22/14
to gitl...@googlegroups.com
You can consider adding a feature request to feedback.gitlab.com

It seems most obvious to implement this as a git hook, right now these
are only available in GitLab EE

Best regards,
Sytse Sijbrandij
CEO GitLab B.V.
> --
> You received this message because you are subscribed to the Google Groups
> "GitLab" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to gitlabhq+u...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/gitlabhq/17372f21-914b-484f-9ad9-39274559780d%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

tombert

unread,
Sep 23, 2014, 9:18:26 AM9/23/14
to gitl...@googlegroups.com
Below the update ruby script from /opt/gitlab/embedded/service/gitlab-shell/hooks/update
which does the trick. Note that I put a .pgpass file into the GitLab home folder /var/opt/gitlab/

-----------------
#!/opt/gitlab/embedded/bin/ruby
# Fix the PATH so that gitlab-shell can find git-upload-pack and friends.
ENV['PATH'] = '/opt/gitlab/bin:/opt/gitlab/embedded/bin:' + ENV['PATH']

#!/usr/bin/env ruby

# This file was placed here by GitLab. It makes sure that your pushed commits
# will be processed properly.
# You can add your own hooks to this file, but be careful when updating gitlab-shell!

refname = ARGV[0]
key_id = ENV['GL_ID']
repo_path = Dir.pwd
shanew = ARGV[2]
shaold = ARGV[1]

require_relative '../lib/gitlab_update'

## cn = committers name
## ce = committers e-mail
## gln = GitLab usernames
## gle = GitLab user e-mails
cn = `git log #{shanew} --pretty=format:%cn --max-count=1`
ce = `git log #{shanew} --pretty=format:%ce --max-count=1`
gln = `psql -h localhost -At -d gitlab -c "select username from users;"`
gln = gln.split("\n")
gle = `psql -h localhost -At -d gitlab -c "select email from users;"`
gle = gle.split("\n")

## loop all GitLab usernames and compare with committers name
found = 0
for username in gln
  if username == cn
    found = 1
  end
end

## reject push
if found == 0
  puts "Rejected push because of unknown committer '#{cn}'"
  exit 1
end

## do original GitLab code
GitlabUpdate.new(repo_path, key_id, refname).exec

tombert

unread,
Oct 31, 2014, 4:23:49 PM10/31/14
to gitl...@googlegroups.com
Because the "update" hook has been removed in GitLab version 7.4 here a new and better reject hook replacing the pre-receive:

#!/opt/gitlab/embedded/bin/ruby
# @backup
# Fix the PATH so that gitlab-shell can find git-upload-pack and friends.
ENV['PATH'] = '/opt/gitlab/bin:/opt/gitlab/embedded/bin:' + ENV['PATH']

#!/usr/bin/env ruby

# This file was placed here by GitLab. It makes sure that your pushed commits
# will be processed properly.
# You can add your own hooks to this file, but be careful when updating gitlab-shell!

refs = ARGF.read
key_id  = ENV['GL_ID']
repo_path = Dir.pwd
# get sha references
temp = refs.split(" ")
shaold = temp[0]
shanew = temp[1]

require '/opt/gitlab/embedded/service/gitlab-shell/lib/gitlab_access'

# read the remote user which is pushing
# distinguish between key-id (ssh access) and user-id (http access)
user = {}
if key_id =~ /\Akey\-\d+\Z/
  # discover the user though its ssh key using GitLab shell function
  require '/opt/gitlab/embedded/service/gitlab-shell/lib/gitlab_net'
  api = GitlabNet.new
  user = api.discover(key_id)
elsif key_id =~ /\Auser\-\d+\Z/
  # read user data directly from database table
  dbid = key_id.gsub("user-", "")
  temp = `psql -h localhost -At -d gitlab -c "select name from users where id=#{dbid};"`
  temp = temp.encode('UTF-8', :invalid => :replace).strip
  user["name"] = temp
  temp = `psql -h localhost -At -d gitlab -c "select username from users where id=#{dbid};"`
  temp = temp.encode('UTF-8', :invalid => :replace).strip
  user["username"] = temp
else
  puts "Unknown GL_ID response: " + key_id
  exit 1
end

## cn = committers name from SHA reference
cn = `git log #{shanew} --pretty=format:%cn --max-count=1`

puts "Remote account is " + user['name'] + " (" + user['username'] + ")"
if (user["username"] != cn) && (user["name"] != cn)
  puts "Rejected push because the committers name '#{cn}' does not match the remote account"
  puts "Use 'git config user.name <your-account-name>' to set things right"
  exit 1
end  

if GitlabAccess.new(repo_path, key_id, refs).exec
  exit 0
else
  exit 1
end

tombert

unread,
Nov 17, 2014, 3:17:58 AM11/17/14
to gitl...@googlegroups.com
Update: encoding to UTF8 from database. Be less restrictive in checking (reactivate code from first initial version)

------------------------------- file pre-receive -------------------------------
## glu = GitLab usernames
glu = `psql -h localhost -At -d gitlab -c "select username from users;"`
glu = glu.encode('UTF-8', :invalid => :replace).strip
glu = glu.split("\n")
## gln = GitLab names
gln = `psql -h localhost -At -d gitlab -c "select name from users;"`
gln = gln.encode('UTF-8', :invalid => :replace).strip
gln = gln.split("\n")

puts "Remote account is " + user['name'] + " (" + user['username'] + ")"

## reject if pushers name does not match the last comitters name
## (maybe too restrictive)
#if (user["username"] != cn) && (user["name"] != cn)
#  puts "Rejected push because the committers name '#{cn}' does not match the remote account"
#  puts "Use 'git config user.name <your-account-name>' to set things right"
#  exit 1
#end  

## loop all GitLab usernames and compare with committers name
found = 0
for username in glu
  if username == cn
    found = 1
  end
end
## loop all GitLab names ...
for name in gln
  if name == cn
    found = 1
  end
end

## reject push
if found == 0
  puts "Rejected push because of unknown committer '#{cn}'"

tombert

unread,
Mar 26, 2015, 10:22:11 AM3/26/15
to gitl...@googlegroups.com
Update. Also check for valid e-mail strings:
----------------------------------

#!/opt/gitlab/embedded/bin/ruby
# @backup
# Fix the PATH so that gitlab-shell can find git-upload-pack and friends.
ENV['PATH'] = '/opt/gitlab/bin:/opt/gitlab/embedded/bin:' + ENV['PATH']

#!/usr/bin/env ruby

refs = ARGF.read
key_id  = ENV['GL_ID']
repo_path = Dir.pwd
# get sha references
temp = refs.split(" ")
shaold = temp[0]
shanew = temp[1]

require '/opt/gitlab/embedded/service/gitlab-shell/lib/gitlab_access'
require '/opt/gitlab/embedded/service/gitlab-shell/lib/gitlab_custom_hook'

# read the remote user which is pushing
# distinguish between key-id (ssh access) and user-id (http access)
user = {}
if key_id =~ /\Akey\-\d+\Z/
  # discover the user though its ssh key using GitLab shell function
  require '/opt/gitlab/embedded/service/gitlab-shell/lib/gitlab_net'
  api = GitlabNet.new
  user = api.discover(key_id)
  temp = `psql -h localhost -At -d gitlab -c "select email from users where username='#{user['username']}';"`
  temp = temp.encode('UTF-8', :invalid => :replace).strip
  user["email"] = temp
elsif key_id =~ /\Auser\-\d+\Z/
  # read user data directly from database table
  dbid = key_id.gsub("user-", "")
  temp = `psql -h localhost -At -d gitlab -c "select name from users where id=#{dbid};"`
  temp = temp.encode('UTF-8', :invalid => :replace).strip
  user["name"] = temp
  temp = `psql -h localhost -At -d gitlab -c "select username from users where id=#{dbid};"`
  temp = temp.encode('UTF-8', :invalid => :replace).strip
  user["username"] = temp
  temp = `psql -h localhost -At -d gitlab -c "select email from users where id=#{dbid};"`
  temp = temp.encode('UTF-8', :invalid => :replace).strip
  user["email"] = temp
else
  puts "Unknown GL_ID response: " + key_id
  exit 1
end

## cn = committers name from SHA reference
cn = `git log #{shanew} --pretty=format:%cn --max-count=1`
## ce = committers email from SHA reference
ce = `git log #{shanew} --pretty=format:%ce --max-count=1`

## glu = GitLab usernames
glu = `psql -h localhost -At -d gitlab -c "select username from users order by id;"`
glu = glu.encode('UTF-8', :invalid => :replace).strip
glu = glu.split("\n")
## gln = GitLab names
gln = `psql -h localhost -At -d gitlab -c "select name from users order by id;"`
gln = gln.encode('UTF-8', :invalid => :replace).strip
gln = gln.split("\n")
## gln = GitLab emails
glm = `psql -h localhost -At -d gitlab -c "select email from users order by id;"`
glm = glm.encode('UTF-8', :invalid => :replace).strip
glm = glm.split("\n")

## Provide some info to pusher
puts "Remote account is " + user['name'] + " (" + user['username'] + ", " + user['email'] + ")"

## reject push if email is invalid format
pattern = /^[A-Za-z0-9]+[A-Za-z0-9._]*+@[A-Za-z0-9]+\.[A-Za-z]{2,4}$/
unless pattern.match(ce)
  puts ""
  puts "Rejecting push because of malformed e-mail '#{ce}'"
  puts "Use \"git config user.email <email>\" to set things right"
  puts "Note that you must perform a fresh commit do make the changes active"
  puts ""
  exit 1
end

## loop all GitLab usernames and compare with committers name
found = 0
for index in 0..glu.length do
  if (cn == glu[index]) or (cn == gln[index])
    if (ce != glm[index])
      ## the main e-mail does not match, check for other configure e-mails
      glmo = `psql -h localhost -At -d gitlab -c "select emails.email from users,emails where users.username='#{user['username']}' and users.id=emails.user_id;"`
      glmo = glmo.encode('UTF-8', :invalid => :replace).strip
      glmo = glmo.split("\n")
      if !glmo.include?(ce)
        puts ""
        puts "Committers e-mail '#{ce}' does not match GitLab account"
        puts "Use \"git config user.email <email>\" to set things right"
        puts "Note that you must perform a fresh commit do make the changes active"
        puts "Or you could configure additional e-mails in your GitLab account"
        puts ""
        exit 1
      end
    end
    found = 1
    break
  end
end

## reject push if last committer is unknown
if found == 0
  puts ""
  puts "Rejecting push because of unknown committer '#{cn}'"
  puts "Use \"git config user.name <account>\" to set things right"
  puts "Note that you must perform a fresh commit do make the changes active"
  puts ""
  exit 1
end

## the original GitLab code
if GitlabAccess.new(repo_path, key_id, refs).exec &&
    GitlabCustomHook.new.pre_receive(refs, repo_path)
Reply all
Reply to author
Forward
0 new messages