diff options
author | Douwe Maan <douwe@gitlab.com> | 2018-10-26 18:06:25 +0000 |
---|---|---|
committer | Douwe Maan <douwe@gitlab.com> | 2018-10-26 18:06:25 +0000 |
commit | e997b22df50a46759cac9936a6557993310f8888 (patch) | |
tree | 7477ee5da963ef699652ccc84fc4fee8726babad | |
parent | f2e9148d18c049bb699e60ed31d3804f9ae4b592 (diff) | |
parent | 679d9b21b7aac55796ef59d5694b7d2e0fb40b35 (diff) | |
download | gitlab-ce-e997b22df50a46759cac9936a6557993310f8888.tar.gz |
Merge branch '51335-fail-early-when-user-cannot-be-identified' into 'master'
User not defined in PostReceive#process_project_changes
Closes #51335
See merge request gitlab-org/gitlab-ce!22519
-rw-r--r-- | app/workers/post_receive.rb | 13 | ||||
-rw-r--r-- | changelogs/unreleased/51335-fail-early-when-user-cannot-be-identified.yml | 5 | ||||
-rw-r--r-- | lib/gitlab/git_post_receive.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/identifier.rb | 21 | ||||
-rw-r--r-- | spec/lib/gitlab/identifier_spec.rb | 49 | ||||
-rw-r--r-- | spec/workers/post_receive_spec.rb | 133 |
6 files changed, 98 insertions, 127 deletions
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 09a594cdb4e..72a1733a2a8 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -29,15 +29,14 @@ class PostReceive def process_project_changes(post_received) changes = [] refs = Set.new + @user = post_received.identify - post_received.changes_refs do |oldrev, newrev, ref| - @user ||= post_received.identify(newrev) - - unless @user - log("Triggered hook for non-existing user \"#{post_received.identifier}\"") - return false # rubocop:disable Cop/AvoidReturnFromBlocks - end + unless @user + log("Triggered hook for non-existing user \"#{post_received.identifier}\"") + return false + end + post_received.changes_refs do |oldrev, newrev, ref| if Gitlab::Git.tag_ref?(ref) GitTagPushService.new(post_received.project, @user, oldrev: oldrev, newrev: newrev, ref: ref).execute elsif Gitlab::Git.branch_ref?(ref) diff --git a/changelogs/unreleased/51335-fail-early-when-user-cannot-be-identified.yml b/changelogs/unreleased/51335-fail-early-when-user-cannot-be-identified.yml new file mode 100644 index 00000000000..a042debc28f --- /dev/null +++ b/changelogs/unreleased/51335-fail-early-when-user-cannot-be-identified.yml @@ -0,0 +1,5 @@ +--- +title: If user was not found, service hooks won't run on post receive background job +merge_request: 22519 +author: +type: fixed diff --git a/lib/gitlab/git_post_receive.rb b/lib/gitlab/git_post_receive.rb index e731e654f3c..cf2329e489d 100644 --- a/lib/gitlab/git_post_receive.rb +++ b/lib/gitlab/git_post_receive.rb @@ -11,8 +11,8 @@ module Gitlab @changes = deserialize_changes(changes) end - def identify(revision) - super(identifier, project, revision) + def identify + super(identifier) end def changes_refs diff --git a/lib/gitlab/identifier.rb b/lib/gitlab/identifier.rb index 28a9fe29465..d5f94ad04f1 100644 --- a/lib/gitlab/identifier.rb +++ b/lib/gitlab/identifier.rb @@ -1,13 +1,11 @@ # frozen_string_literal: true # Detect user based on identifier like -# key-13 or user-36 or last commit +# key-13 or user-36 module Gitlab module Identifier - def identify(identifier, project = nil, newrev = nil) - if identifier.blank? - identify_using_commit(project, newrev) - elsif identifier =~ /\Auser-\d+\Z/ + def identify(identifier) + if identifier =~ /\Auser-\d+\Z/ # git push over http identify_using_user(identifier) elsif identifier =~ /\Akey-\d+\Z/ @@ -16,19 +14,6 @@ module Gitlab end end - # Tries to identify a user based on a commit SHA. - def identify_using_commit(project, ref) - return if project.nil? && ref.nil? - - commit = project.commit(ref) - - return if !commit || !commit.author_email - - identify_with_cache(:email, commit.author_email) do - commit.author - end - end - # Tries to identify a user based on a user identifier (e.g. "user-123"). # rubocop: disable CodeReuse/ActiveRecord def identify_using_user(identifier) diff --git a/spec/lib/gitlab/identifier_spec.rb b/spec/lib/gitlab/identifier_spec.rb index 0385dd762c2..1e583f4cee2 100644 --- a/spec/lib/gitlab/identifier_spec.rb +++ b/spec/lib/gitlab/identifier_spec.rb @@ -11,11 +11,8 @@ describe Gitlab::Identifier do describe '#identify' do context 'without an identifier' do - it 'identifies the user using a commit' do - expect(identifier).to receive(:identify_using_commit) - .with(project, '123') - - identifier.identify('', project, '123') + it 'returns nil' do + expect(identifier.identify('')).to be nil end end @@ -24,7 +21,7 @@ describe Gitlab::Identifier do expect(identifier).to receive(:identify_using_user) .with("user-#{user.id}") - identifier.identify("user-#{user.id}", project, '123') + identifier.identify("user-#{user.id}") end end @@ -33,49 +30,11 @@ describe Gitlab::Identifier do expect(identifier).to receive(:identify_using_ssh_key) .with("key-#{key.id}") - identifier.identify("key-#{key.id}", project, '123') + identifier.identify("key-#{key.id}") end end end - describe '#identify_using_commit' do - it "returns the User for an existing commit author's Email address" do - commit = double(:commit, author: user, author_email: user.email) - - expect(project).to receive(:commit).with('123').and_return(commit) - - expect(identifier.identify_using_commit(project, '123')).to eq(user) - end - - it 'returns nil when no user could be found' do - allow(project).to receive(:commit).with('123').and_return(nil) - - expect(identifier.identify_using_commit(project, '123')).to be_nil - end - - it 'returns nil when the commit does not have an author Email' do - commit = double(:commit, author_email: nil) - - expect(project).to receive(:commit).with('123').and_return(commit) - - expect(identifier.identify_using_commit(project, '123')).to be_nil - end - - it 'caches the found users per Email' do - commit = double(:commit, author: user, author_email: user.email) - - expect(project).to receive(:commit).with('123').twice.and_return(commit) - - 2.times do - expect(identifier.identify_using_commit(project, '123')).to eq(user) - end - end - - it 'returns nil if the project & ref are not present' do - expect(identifier.identify_using_commit(nil, nil)).to be_nil - end - end - describe '#identify_using_user' do it 'returns the User for an existing ID in the identifier' do found = identifier.identify_using_user("user-#{user.id}") diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index cd6661f09a1..9176eb12b12 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -6,7 +6,7 @@ describe PostReceive do let(:base64_changes) { Base64.encode64(wrongly_encoded_changes) } let(:gl_repository) { "project-#{project.id}" } let(:key) { create(:key, user: project.owner) } - let(:key_id) { key.shell_id } + let!(:key_id) { key.shell_id } let(:project) do create(:project, :repository, auto_cancel_pending_pipelines: 'disabled') @@ -31,85 +31,108 @@ describe PostReceive do end describe "#process_project_changes" do - before do - allow_any_instance_of(Gitlab::GitPostReceive).to receive(:identify).and_return(project.owner) + context 'empty changes' do + it "does not call any PushService but runs after project hooks" do + expect(GitPushService).not_to receive(:new) + expect(GitTagPushService).not_to receive(:new) + expect_next_instance_of(SystemHooksService) { |service| expect(service).to receive(:execute_hooks) } + + described_class.new.perform(gl_repository, key_id, "") + end end - context "branches" do - let(:changes) { "123456 789012 refs/heads/tést" } + context 'unidentified user' do + let!(:key_id) { "" } - it "calls GitTagPushService" do - expect_any_instance_of(GitPushService).to receive(:execute).and_return(true) - expect_any_instance_of(GitTagPushService).not_to receive(:execute) - described_class.new.perform(gl_repository, key_id, base64_changes) + it 'returns false' do + expect(GitPushService).not_to receive(:new) + expect(GitTagPushService).not_to receive(:new) + + expect(described_class.new.perform(gl_repository, key_id, base64_changes)).to be false end end - context "tags" do - let(:changes) { "123456 789012 refs/tags/tag" } + context 'with changes' do + before do + allow_any_instance_of(Gitlab::GitPostReceive).to receive(:identify).and_return(project.owner) + end + + context "branches" do + let(:changes) { "123456 789012 refs/heads/tést" } - it "calls GitTagPushService" do - expect_any_instance_of(GitPushService).not_to receive(:execute) - expect_any_instance_of(GitTagPushService).to receive(:execute).and_return(true) - described_class.new.perform(gl_repository, key_id, base64_changes) + it "calls GitPushService" do + expect_any_instance_of(GitPushService).to receive(:execute).and_return(true) + expect_any_instance_of(GitTagPushService).not_to receive(:execute) + described_class.new.perform(gl_repository, key_id, base64_changes) + end end - end - context "merge-requests" do - let(:changes) { "123456 789012 refs/merge-requests/123" } + context "tags" do + let(:changes) { "123456 789012 refs/tags/tag" } - it "does not call any of the services" do - expect_any_instance_of(GitPushService).not_to receive(:execute) - expect_any_instance_of(GitTagPushService).not_to receive(:execute) - described_class.new.perform(gl_repository, key_id, base64_changes) + it "calls GitTagPushService" do + expect_any_instance_of(GitPushService).not_to receive(:execute) + expect_any_instance_of(GitTagPushService).to receive(:execute).and_return(true) + described_class.new.perform(gl_repository, key_id, base64_changes) + end end - end - context "gitlab-ci.yml" do - let(:changes) { "123456 789012 refs/heads/feature\n654321 210987 refs/tags/tag" } + context "merge-requests" do + let(:changes) { "123456 789012 refs/merge-requests/123" } - subject { described_class.new.perform(gl_repository, key_id, base64_changes) } + it "does not call any of the services" do + expect_any_instance_of(GitPushService).not_to receive(:execute) + expect_any_instance_of(GitTagPushService).not_to receive(:execute) + described_class.new.perform(gl_repository, key_id, base64_changes) + end + end - context "creates a Ci::Pipeline for every change" do - before do - stub_ci_pipeline_to_return_yaml_file + context "gitlab-ci.yml" do + let(:changes) { "123456 789012 refs/heads/feature\n654321 210987 refs/tags/tag" } - allow_any_instance_of(Project) - .to receive(:commit) - .and_return(project.commit) + subject { described_class.new.perform(gl_repository, key_id, base64_changes) } - allow_any_instance_of(Repository) - .to receive(:branch_exists?) - .and_return(true) - end + context "creates a Ci::Pipeline for every change" do + before do + stub_ci_pipeline_to_return_yaml_file - it { expect { subject }.to change { Ci::Pipeline.count }.by(2) } - end + allow_any_instance_of(Project) + .to receive(:commit) + .and_return(project.commit) - context "does not create a Ci::Pipeline" do - before do - stub_ci_pipeline_yaml_file(nil) + allow_any_instance_of(Repository) + .to receive(:branch_exists?) + .and_return(true) + end + + it { expect { subject }.to change { Ci::Pipeline.count }.by(2) } end - it { expect { subject }.not_to change { Ci::Pipeline.count } } + context "does not create a Ci::Pipeline" do + before do + stub_ci_pipeline_yaml_file(nil) + end + + it { expect { subject }.not_to change { Ci::Pipeline.count } } + end end - end - context 'after project changes hooks' do - let(:changes) { '123456 789012 refs/heads/tést' } - let(:fake_hook_data) { Hash.new(event_name: 'repository_update') } + context 'after project changes hooks' do + let(:changes) { '123456 789012 refs/heads/tést' } + let(:fake_hook_data) { Hash.new(event_name: 'repository_update') } - before do - allow_any_instance_of(Gitlab::DataBuilder::Repository).to receive(:update).and_return(fake_hook_data) - # silence hooks so we can isolate - allow_any_instance_of(Key).to receive(:post_create_hook).and_return(true) - allow_any_instance_of(GitPushService).to receive(:execute).and_return(true) - end + before do + allow_any_instance_of(Gitlab::DataBuilder::Repository).to receive(:update).and_return(fake_hook_data) + # silence hooks so we can isolate + allow_any_instance_of(Key).to receive(:post_create_hook).and_return(true) + allow_any_instance_of(GitPushService).to receive(:execute).and_return(true) + end - it 'calls SystemHooksService' do - expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(fake_hook_data, :repository_update_hooks).and_return(true) + it 'calls SystemHooksService' do + expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(fake_hook_data, :repository_update_hooks).and_return(true) - described_class.new.perform(gl_repository, key_id, base64_changes) + described_class.new.perform(gl_repository, key_id, base64_changes) + end end end end |