diff options
author | Gabriel Mazetto <gabriel@gitlab.com> | 2016-04-27 04:24:49 -0300 |
---|---|---|
committer | Gabriel Mazetto <gabriel@gitlab.com> | 2016-04-30 05:04:10 -0300 |
commit | 0cd5edf35cfaca74344dd389aadd65f0f179d395 (patch) | |
tree | d83d697f60126f5b10992dca550751e2182778d9 | |
parent | 40c38644a88b8f5e88e6fd3317421206d8ee851e (diff) | |
download | gitlab-ce-0cd5edf35cfaca74344dd389aadd65f0f179d395.tar.gz |
Backported minimal safewebhook implementation to GitLab CE
-rw-r--r-- | app/models/hooks/project_hook.rb | 1 | ||||
-rw-r--r-- | app/models/hooks/service_hook.rb | 1 | ||||
-rw-r--r-- | app/models/hooks/system_hook.rb | 1 | ||||
-rw-r--r-- | app/models/hooks/web_hook.rb | 24 | ||||
-rw-r--r-- | db/migrate/20160413115152_add_token_to_web_hooks.rb | 5 | ||||
-rw-r--r-- | db/schema.rb | 1 | ||||
-rw-r--r-- | spec/factories/project_hooks.rb | 4 | ||||
-rw-r--r-- | spec/models/hooks/web_hook_spec.rb | 46 |
8 files changed, 58 insertions, 25 deletions
diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb index bc6e0f98c3c..d149511b868 100644 --- a/app/models/hooks/project_hook.rb +++ b/app/models/hooks/project_hook.rb @@ -16,6 +16,7 @@ # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) # build_events :boolean default(FALSE), not null +# token :string # class ProjectHook < WebHook diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb index 80962264ba2..f45145eeb3a 100644 --- a/app/models/hooks/service_hook.rb +++ b/app/models/hooks/service_hook.rb @@ -16,6 +16,7 @@ # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) # build_events :boolean default(FALSE), not null +# token :string # class ServiceHook < WebHook diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb index 15dddcc2447..012cc8ec005 100644 --- a/app/models/hooks/system_hook.rb +++ b/app/models/hooks/system_hook.rb @@ -16,6 +16,7 @@ # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) # build_events :boolean default(FALSE), not null +# token :string # class SystemHook < WebHook diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index 3a2e4f546f7..1e3b4815596 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -16,6 +16,7 @@ # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) # build_events :boolean default(FALSE), not null +# token :string # class WebHook < ActiveRecord::Base @@ -43,23 +44,17 @@ class WebHook < ActiveRecord::Base if parsed_url.userinfo.blank? response = WebHook.post(url, body: data.to_json, - headers: { - "Content-Type" => "application/json", - "X-Gitlab-Event" => hook_name.singularize.titleize - }, + headers: build_headers(hook_name), verify: enable_ssl_verification) else - post_url = url.gsub("#{parsed_url.userinfo}@", "") + post_url = url.gsub("#{parsed_url.userinfo}@", '') auth = { username: CGI.unescape(parsed_url.user), password: CGI.unescape(parsed_url.password), } response = WebHook.post(post_url, body: data.to_json, - headers: { - "Content-Type" => "application/json", - "X-Gitlab-Event" => hook_name.singularize.titleize - }, + headers: build_headers(hook_name), verify: enable_ssl_verification, basic_auth: auth) end @@ -73,4 +68,15 @@ class WebHook < ActiveRecord::Base def async_execute(data, hook_name) Sidekiq::Client.enqueue(ProjectWebHookWorker, id, data, hook_name) end + + private + + def build_headers(hook_name) + headers = { + 'Content-Type' => 'application/json', + 'X-Gitlab-Event' => hook_name.singularize.titleize + } + headers['X-Gitlab-Token'] = token if token.present? + headers + end end diff --git a/db/migrate/20160413115152_add_token_to_web_hooks.rb b/db/migrate/20160413115152_add_token_to_web_hooks.rb new file mode 100644 index 00000000000..f04225068cd --- /dev/null +++ b/db/migrate/20160413115152_add_token_to_web_hooks.rb @@ -0,0 +1,5 @@ +class AddTokenToWebHooks < ActiveRecord::Migration + def change + add_column :web_hooks, :token, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 42457d92353..04aee737e4c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1025,6 +1025,7 @@ ActiveRecord::Schema.define(version: 20160421130527) do t.boolean "enable_ssl_verification", default: true t.boolean "build_events", default: false, null: false t.boolean "wiki_page_events", default: false, null: false + t.string "token" end add_index "web_hooks", ["created_at", "id"], name: "index_web_hooks_on_created_at_and_id", using: :btree diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb index 94dd935a039..3195fb3ddcc 100644 --- a/spec/factories/project_hooks.rb +++ b/spec/factories/project_hooks.rb @@ -1,5 +1,9 @@ FactoryGirl.define do factory :project_hook do url { FFaker::Internet.uri('http') } + + trait :token do + token { SecureRandom.hex(10) } + end end end diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index 04bc2dcfb16..37a27d73aab 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -43,51 +43,65 @@ describe WebHook, models: true do end describe "execute" do + let(:project) { create(:project) } + let(:project_hook) { create(:project_hook) } + before(:each) do - @project_hook = create(:project_hook) - @project = create(:project) - @project.hooks << [@project_hook] + project.hooks << [project_hook] @data = { before: 'oldrev', after: 'newrev', ref: 'ref' } - WebMock.stub_request(:post, @project_hook.url) + WebMock.stub_request(:post, project_hook.url) + end + + context 'when token is defined' do + let(:project_hook) { create(:project_hook, :token) } + + it 'POSTs to the webhook URL' do + project_hook.execute(@data, 'push_hooks') + expect(WebMock).to have_requested(:post, project_hook.url).with( + headers: { 'Content-Type' => 'application/json', + 'X-Gitlab-Event' => 'Push Hook', + 'X-Gitlab-Token' => project_hook.token } + ).once + end end it "POSTs to the webhook URL" do - @project_hook.execute(@data, 'push_hooks') - expect(WebMock).to have_requested(:post, @project_hook.url).with( - headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook' } + project_hook.execute(@data, 'push_hooks') + expect(WebMock).to have_requested(:post, project_hook.url).with( + headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'Push Hook' } ).once end it "POSTs the data as JSON" do - @project_hook.execute(@data, 'push_hooks') - expect(WebMock).to have_requested(:post, @project_hook.url).with( - headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook' } + project_hook.execute(@data, 'push_hooks') + expect(WebMock).to have_requested(:post, project_hook.url).with( + headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'Push Hook' } ).once end it "catches exceptions" do expect(WebHook).to receive(:post).and_raise("Some HTTP Post error") - expect { @project_hook.execute(@data, 'push_hooks') }.to raise_error(RuntimeError) + expect { project_hook.execute(@data, 'push_hooks') }.to raise_error(RuntimeError) end it "handles SSL exceptions" do expect(WebHook).to receive(:post).and_raise(OpenSSL::SSL::SSLError.new('SSL error')) - expect(@project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error']) + expect(project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error']) end it "handles 200 status code" do - WebMock.stub_request(:post, @project_hook.url).to_return(status: 200, body: "Success") + WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: "Success") - expect(@project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) + expect(project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) end it "handles 2xx status codes" do - WebMock.stub_request(:post, @project_hook.url).to_return(status: 201, body: "Success") + WebMock.stub_request(:post, project_hook.url).to_return(status: 201, body: "Success") - expect(@project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) + expect(project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) end end end |