Commit 76f7f349 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'hooks-refactoring' into 'master'

Hooks refactoring

* replace update hook with pre-receive & post-receive hooks
* use pre-receive hook for authorisation
* use post-receive hook to create background job for GitLab worker

Related to https://dev.gitlab.org/gitlab/gitlabhq/issues/1516

See merge request !38
parents 99fa0c6e a71c8072
v1.9.8
v2.0.0
- Works with GitLab v7.3+
- Replace raise with abort when checking path to prevent path exposure
- Handle invalid number of arguments on remote commands
- Replace update hook with pre-receive and post-receive hooks.
v1.9.7
- Increased test coverage
......
#!/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!
changes = ARGF.read
key_id = ENV['GL_ID']
repo_path = Dir.pwd
require_relative '../lib/gitlab_post_receive'
if GitlabPostReceive.new(repo_path, key_id, changes).exec
exit 0
else
exit 1
end
......@@ -4,10 +4,14 @@
# will be processed properly.
# You can add your own hooks to this file, but be careful when updating gitlab-shell!
refname = ARGV[0]
refs = ARGF.read
key_id = ENV['GL_ID']
repo_path = Dir.pwd
require_relative '../lib/gitlab_update'
require_relative '../lib/gitlab_access'
GitlabUpdate.new(repo_path, key_id, refname).exec
if GitlabAccess.new(repo_path, key_id, refs).exec
exit 0
else
exit 1
end
require_relative 'gitlab_init'
require_relative 'gitlab_net'
require_relative 'names_helper'
require 'json'
class GitlabAccess
include NamesHelper
attr_reader :config, :repo_path, :repo_name, :changes
def initialize(repo_path, actor, changes)
@config = GitlabConfig.new
@repo_path, @actor = repo_path.strip, actor
@repo_name = extract_repo_name(@repo_path.dup, config.repos_path.to_s)
@changes = changes.lines
end
def exec
if api.allowed?('git-receive-pack', @repo_name, @actor, @changes)
exit 0
else
# reset GL_ID env since we stop git push here
ENV['GL_ID'] = nil
puts "GitLab: You are not allowed to access #{@ref_name}!"
exit 1
end
end
protected
def api
GitlabNet.new
end
end
......@@ -6,21 +6,17 @@ require_relative 'gitlab_config'
require_relative 'gitlab_logger'
class GitlabNet
def allowed?(cmd, repo, actor, ref, oldrev = nil, newrev = nil, forced_push = false)
def allowed?(cmd, repo, actor, changes)
project_name = repo.gsub("'", "")
project_name = project_name.gsub(/\.git\Z/, "")
project_name = project_name.gsub(/\A\//, "")
params = {
action: cmd,
ref: ref,
changes: changes,
project: project_name,
forced_push: forced_push,
}
params.merge!(oldrev: oldrev) if oldrev
params.merge!(newrev: newrev) if newrev
if actor =~ /\Akey\-\d+\Z/
params.merge!(key_id: actor.gsub("key-", ""))
elsif actor =~ /\Auser\-\d+\Z/
......@@ -86,7 +82,7 @@ class GitlabNet
end
def cert_store
@cert_store ||= OpenSSL::X509::Store.new.tap { |store|
@cert_store ||= OpenSSL::X509::Store.new.tap do |store|
store.set_default_paths
if ca_file = config.http_settings['ca_file']
......@@ -96,6 +92,6 @@ class GitlabNet
if ca_path = config.http_settings['ca_path']
store.add_path(ca_path)
end
}
end
end
end
require_relative 'gitlab_init'
require_relative 'gitlab_net'
require_relative 'names_helper'
require 'json'
class GitlabUpdate
include NamesHelper
class GitlabPostReceive
attr_reader :config, :repo_path, :changes
attr_reader :config, :repo_path, :repo_name,
:ref, :ref_name, :oldrev, :newrev
def initialize(repo_path, actor, ref)
def initialize(repo_path, actor, changes)
@config = GitlabConfig.new
@repo_path, @actor, @ref = repo_path.strip, actor, ref
@repo_name = extract_repo_name(@repo_path.dup, config.repos_path.to_s)
@ref_name = extract_ref_name(ref)
@oldrev = ARGV[1]
@newrev = ARGV[2]
end
def forced_push?
if @oldrev !~ /00000000/ && @newrev !~ /00000000/
missed_refs = IO.popen(%W(git rev-list #{@oldrev} ^#{@newrev})).read
missed_refs.split("\n").size > 0
else
false
end
@repo_path, @actor = repo_path.strip, actor
@changes = changes.lines
end
def exec
......@@ -32,24 +15,14 @@ class GitlabUpdate
# get value from it
ENV['GL_ID'] = nil
if api.allowed?('git-receive-pack', @repo_name, @actor, @ref_name, @oldrev, @newrev, forced_push?)
update_redis
exit 0
else
puts "GitLab: You are not allowed to access #{@ref_name}!"
exit 1
end
end
protected
def api
GitlabNet.new
end
def update_redis
queue = "#{config.redis_namespace}:queue:post_receive"
msg = JSON.dump({'class' => 'PostReceive', 'args' => [@repo_path, @oldrev, @newrev, @ref, @actor]})
msg = JSON.dump({'class' => 'PostReceive', 'args' => [@repo_path, @actor, @changes]})
unless system(*config.redis_command, 'rpush', queue, msg, err: '/dev/null', out: '/dev/null')
puts "GitLab: An unexpected error occurred (redis-cli returned #{$?.exitstatus})."
exit 1
......
......@@ -18,9 +18,11 @@ class GitlabProjects
attr_reader :full_path
def self.create_hooks(path)
hook = File.join(path, 'hooks', 'update')
%w(pre-receive post-receive).each do |hook_name|
hook = File.join(path, 'hooks', hook_name)
File.delete(hook) if File.exists?(hook)
File.symlink(File.join(ROOT_PATH, 'hooks', 'update'), hook)
File.symlink(File.join(ROOT_PATH, 'hooks', hook_name), hook)
end
end
def initialize
......
require 'spec_helper'
require 'gitlab_update'
require 'gitlab_access'
describe GitlabUpdate do
describe GitlabAccess do
let(:repository_path) { "/home/git/repositories" }
let(:repo_name) { 'dzaporozhets/gitlab-ci' }
let(:repo_path) { File.join(repository_path, repo_name) + ".git" }
let(:ref) { 'refs/heads/awesome-feature' }
let(:gitlab_update) { GitlabUpdate.new(repo_path, 'key-123', ref) }
let(:gitlab_access) { GitlabAccess.new(repo_path, 'key-123', 'wow') }
before do
ARGV[1] = 'd1e3ca3b25'
ARGV[2] = 'c2b3653b25'
GitlabConfig.any_instance.stub(repos_path: repository_path)
end
describe :initialize do
it { gitlab_update.repo_name.should == repo_name }
it { gitlab_update.repo_path.should == repo_path }
it { gitlab_update.ref.should == ref }
it { gitlab_update.ref_name.should == 'awesome-feature' }
it { gitlab_update.oldrev.should == 'd1e3ca3b25' }
it { gitlab_update.newrev.should == 'c2b3653b25' }
it { gitlab_access.repo_name.should == repo_name }
it { gitlab_access.repo_path.should == repo_path }
it { gitlab_access.changes.should == ['wow'] }
end
end
......@@ -4,6 +4,7 @@ require_relative '../lib/gitlab_net'
describe GitlabNet, vcr: true do
let(:gitlab_net) { GitlabNet.new }
let(:changes) { ['0000000000000000000000000000000000000000 92d0970eefd7acb6d548878925ce2208cfe2d2ec refs/heads/branch4'] }
before do
gitlab_net.stub!(:host).and_return('https://dev.gitlab.org/api/v3/internal')
......@@ -31,14 +32,14 @@ describe GitlabNet, vcr: true do
context 'ssh key with access to project' do
it 'should allow pull access for dev.gitlab.org' do
VCR.use_cassette("allowed-pull") do
access = gitlab_net.allowed?('git-receive-pack', 'gitlab/gitlabhq.git', 'key-126', 'master')
access = gitlab_net.allowed?('git-receive-pack', 'gitlab/gitlabhq.git', 'key-126', changes)
access.should be_true
end
end
it 'should allow push access for dev.gitlab.org' do
VCR.use_cassette("allowed-push") do
access = gitlab_net.allowed?('git-upload-pack', 'gitlab/gitlabhq.git', 'key-126', 'master')
access = gitlab_net.allowed?('git-upload-pack', 'gitlab/gitlabhq.git', 'key-126', changes)
access.should be_true
end
end
......@@ -47,21 +48,21 @@ describe GitlabNet, vcr: true do
context 'ssh key without access to project' do
it 'should deny pull access for dev.gitlab.org' do
VCR.use_cassette("denied-pull") do
access = gitlab_net.allowed?('git-receive-pack', 'gitlab/gitlabhq.git', 'key-2', 'master')
access = gitlab_net.allowed?('git-receive-pack', 'gitlab/gitlabhq.git', 'key-2', changes)
access.should be_false
end
end
it 'should deny push access for dev.gitlab.org' do
VCR.use_cassette("denied-push") do
access = gitlab_net.allowed?('git-upload-pack', 'gitlab/gitlabhq.git', 'key-2', 'master')
access = gitlab_net.allowed?('git-upload-pack', 'gitlab/gitlabhq.git', 'key-2', changes)
access.should be_false
end
end
it 'should deny push access for dev.gitlab.org (with user)' do
VCR.use_cassette("denied-push-with-user") do
access = gitlab_net.allowed?('git-upload-pack', 'gitlab/gitlabhq.git', 'user-1', 'master')
access = gitlab_net.allowed?('git-upload-pack', 'gitlab/gitlabhq.git', 'user-1', changes)
access.should be_false
end
end
......
require 'spec_helper'
require 'gitlab_post_receive'
describe GitlabPostReceive do
let(:repository_path) { "/home/git/repositories" }
let(:repo_name) { 'dzaporozhets/gitlab-ci' }
let(:repo_path) { File.join(repository_path, repo_name) + ".git" }
let(:gitlab_post_receive) { GitlabPostReceive.new(repo_path, 'key-123', 'wow') }
before do
GitlabConfig.any_instance.stub(repos_path: repository_path)
end
describe :initialize do
it { gitlab_post_receive.repo_path.should == repo_path }
it { gitlab_post_receive.changes.should == ['wow'] }
end
end
......@@ -295,7 +295,8 @@ describe GitlabProjects do
FileUtils.mkdir_p(File.join(tmp_repos_path, 'forked-to-namespace'))
gl_projects_fork.exec.should be_true
File.exists?(dest_repo).should be_true
File.exists?(File.join(dest_repo, '/hooks/update')).should be_true
File.exists?(File.join(dest_repo, '/hooks/pre-receive')).should be_true
File.exists?(File.join(dest_repo, '/hooks/post-receive')).should be_true
end
it "should not fork if a project of the same name already exists" do
......
require 'spec_helper'
require 'gitlab_update'
require 'names_helper'
describe NamesHelper do
include NamesHelper
......
......@@ -2,7 +2,7 @@
http_interactions:
- request:
method: get
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-receive-pack&forced_push=false&key_id=126&project=gitlab/gitlabhq&ref=master
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-receive-pack&changes=0000000000000000000000000000000000000000%2092d0970eefd7acb6d548878925ce2208cfe2d2ec%20refs/heads/branch4&key_id=126&project=gitlab/gitlabhq
body:
encoding: US-ASCII
string: ''
......@@ -21,7 +21,7 @@ http_interactions:
Server:
- nginx/1.1.19
Date:
- Mon, 14 Apr 2014 18:25:53 GMT
- Mon, 01 Sep 2014 16:23:50 GMT
Content-Type:
- application/json
Content-Length:
......@@ -35,12 +35,12 @@ http_interactions:
Cache-Control:
- max-age=0, private, must-revalidate
X-Request-Id:
- b049c014-05c4-4ec7-a591-1b0661257e33
- 677dee49-79ab-452b-a56c-bb656949dab1
X-Runtime:
- '0.055486'
- '0.079772'
body:
encoding: UTF-8
string: 'true'
http_version:
recorded_at: Mon, 14 Apr 2014 18:25:53 GMT
recorded_at: Mon, 01 Sep 2014 16:23:50 GMT
recorded_with: VCR 2.4.0
......@@ -2,7 +2,7 @@
http_interactions:
- request:
method: get
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-upload-pack&forced_push=false&key_id=126&project=gitlab/gitlabhq&ref=master
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-upload-pack&changes=0000000000000000000000000000000000000000%2092d0970eefd7acb6d548878925ce2208cfe2d2ec%20refs/heads/branch4&key_id=126&project=gitlab/gitlabhq
body:
encoding: US-ASCII
string: ''
......@@ -21,7 +21,7 @@ http_interactions:
Server:
- nginx/1.1.19
Date:
- Mon, 14 Apr 2014 18:25:54 GMT
- Mon, 01 Sep 2014 16:23:51 GMT
Content-Type:
- application/json
Content-Length:
......@@ -35,12 +35,12 @@ http_interactions:
Cache-Control:
- max-age=0, private, must-revalidate
X-Request-Id:
- 7f92ebb7-4f92-4236-a35a-5f15c59b81f8
- 598daf73-57a1-4861-b159-fdfa2cbb3cfc
X-Runtime:
- '0.060724'
- '0.033789'
body:
encoding: UTF-8
string: 'true'
http_version:
recorded_at: Mon, 14 Apr 2014 18:25:54 GMT
recorded_at: Mon, 01 Sep 2014 16:23:51 GMT
recorded_with: VCR 2.4.0
......@@ -21,7 +21,7 @@ http_interactions:
Server:
- nginx/1.1.19
Date:
- Mon, 14 Apr 2014 18:25:52 GMT
- Mon, 01 Sep 2014 16:23:48 GMT
Content-Type:
- application/json
Content-Length:
......@@ -31,16 +31,16 @@ http_interactions:
Status:
- 200 OK
Etag:
- '"263db4ad138ffbada1f94332a1a2e1e8"'
- '"4deef8ced16c13af425359a8f45f42e1"'
Cache-Control:
- max-age=0, private, must-revalidate
X-Request-Id:
- 17b6ff1c-e1a5-4443-b053-74cfced03184
- 041c17df-8c96-4633-9063-d309583fe0fa
X-Runtime:
- '0.004863'
- '0.012408'
body:
encoding: UTF-8
string: '{"api_version":"v3","gitlab_version":"6.8.0.pre","gitlab_rev":"352bb97"}'
string: '{"api_version":"v3","gitlab_version":"7.3.0.pre","gitlab_rev":"174c00c"}'
http_version:
recorded_at: Mon, 14 Apr 2014 18:25:52 GMT
recorded_at: Mon, 01 Sep 2014 16:23:48 GMT
recorded_with: VCR 2.4.0
......@@ -2,7 +2,7 @@
http_interactions:
- request:
method: get
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-receive-pack&forced_push=false&key_id=2&project=gitlab/gitlabhq&ref=master
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-receive-pack&changes=0000000000000000000000000000000000000000%2092d0970eefd7acb6d548878925ce2208cfe2d2ec%20refs/heads/branch4&key_id=2&project=gitlab/gitlabhq
body:
encoding: US-ASCII
string: ''
......@@ -21,7 +21,7 @@ http_interactions:
Server:
- nginx/1.1.19
Date:
- Mon, 14 Apr 2014 18:25:54 GMT
- Mon, 01 Sep 2014 16:23:52 GMT
Content-Type:
- application/json
Content-Length:
......@@ -33,12 +33,12 @@ http_interactions:
Cache-Control:
- no-cache
X-Request-Id:
- 7eb4f49d-66a6-4cca-84dd-9dfcd431210a
- 1721b961-9792-4af4-b3d2-fff0f7aa33b7
X-Runtime:
- '0.010216'
- '0.034322'
body:
encoding: UTF-8
string: '{"message":"404 Not found"}'
http_version:
recorded_at: Mon, 14 Apr 2014 18:25:54 GMT
recorded_at: Mon, 01 Sep 2014 16:23:52 GMT
recorded_with: VCR 2.4.0
......@@ -2,7 +2,7 @@
http_interactions:
- request:
method: get
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-upload-pack&forced_push=false&project=gitlab/gitlabhq&ref=master&user_id=1
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-upload-pack&changes=0000000000000000000000000000000000000000%2092d0970eefd7acb6d548878925ce2208cfe2d2ec%20refs/heads/branch4&project=gitlab/gitlabhq&user_id=1
body:
encoding: US-ASCII
string: ''
......@@ -15,30 +15,32 @@ http_interactions:
- Ruby
response:
status:
code: 404
message: Not Found
code: 200
message: OK
headers:
Server:
- nginx/1.1.19
Date:
- Mon, 14 Apr 2014 18:25:54 GMT
- Mon, 01 Sep 2014 16:23:52 GMT
Content-Type:
- application/json
Content-Length:
- '27'
- '4'
Connection:
- keep-alive
Status:
- 404 Not Found
- 200 OK
Etag:
- '"b326b5062b2f0e69046810717534cb09"'
Cache-Control:
- no-cache
- max-age=0, private, must-revalidate
X-Request-Id:
- 2a2a3ef9-aaf1-4ffb-8b18-475d52ec5e09
- 1222ecfc-c1af-4246-b63f-f3f2865c4813
X-Runtime:
- '0.013223'
- '0.031859'
body:
encoding: UTF-8
string: '{"message":"404 Not found"}'
string: 'false'
http_version:
recorded_at: Mon, 14 Apr 2014 18:25:54 GMT
recorded_at: Mon, 01 Sep 2014 16:23:52 GMT
recorded_with: VCR 2.4.0
......@@ -2,7 +2,7 @@
http_interactions:
- request:
method: get
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-upload-pack&forced_push=false&key_id=2&project=gitlab/gitlabhq&ref=master
uri: https://dev.gitlab.org/api/v3/internal/allowed?action=git-upload-pack&changes=0000000000000000000000000000000000000000%2092d0970eefd7acb6d548878925ce2208cfe2d2ec%20refs/heads/branch4&key_id=2&project=gitlab/gitlabhq
body:
encoding: US-ASCII
string: ''
......@@ -21,7 +21,7 @@ http_interactions:
Server:
- nginx/1.1.19
Date:
- Mon, 14 Apr 2014 18:25:54 GMT
- Mon, 01 Sep 2014 16:23:52 GMT
Content-Type:
- application/json
Content-Length:
......@@ -33,12 +33,12 @@ http_interactions:
Cache-Control:
- no-cache
X-Request-Id:
- 2a2a3ef9-aaf1-4ffb-8b18-475d52ec5e09
- fbaed080-e60e-4893-afe3-4f0c331b1983
X-Runtime:
- '0.013223'
- '0.013659'
body:
encoding: UTF-8
string: '{"message":"404 Not found"}'
http_version:
recorded_at: Mon, 14 Apr 2014 18:25:54 GMT
recorded_at: Mon, 01 Sep 2014 16:23:52 GMT
recorded_with: VCR 2.4.0
......@@ -21,7 +21,7 @@ http_interactions:
Server:
- nginx/1.1.19
Date:
- Mon, 14 Apr 2014 18:25:53 GMT
- Mon, 01 Sep 2014 16:23:49 GMT
Content-Type:
- application/json
Content-Length:
......@@ -35,12 +35,12 @@ http_interactions:
Cache-Control:
- max-age=0, private, must-revalidate
X-Request-Id:
- c3d44ccc-7599-4cc1-879e-281894f9cb39
- f0ec702f-ff68-4597-a386-b7ff4bae5650
X-Runtime:
- '0.010799'
- '0.935522'
body:
encoding: UTF-8
string: '{"name":"Dmitriy Zaporozhets","username":"dzaporozhets"}'
http_version:
recorded_at: Mon, 14 Apr 2014 18:25:53 GMT
recorded_at: Mon, 01 Sep 2014 16:23:49 GMT
recorded_with: VCR 2.4.0
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment