diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb index eb223c1101db27c0d914a552cc4f5ed0fc880249..e8975eb57e0f05e98d2b611cd118fd9c1732802f 100644 --- a/lib/api/helpers/internal_helpers.rb +++ b/lib/api/helpers/internal_helpers.rb @@ -52,6 +52,14 @@ module API :push_code ] end + + def parse_allowed_environment_variables + return if params[:env].blank? + + JSON.parse(params[:env]) + + rescue JSON::ParserError + end end end end diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 7087ce114014f325dfa23c66897fa096c80942d7..db2d18f935d0423282aa7233622b89cefdfef3ea 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -32,7 +32,11 @@ module API if wiki? Gitlab::GitAccessWiki.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities) else - Gitlab::GitAccess.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities) + Gitlab::GitAccess.new(actor, + project, + protocol, + authentication_abilities: ssh_authentication_abilities, + env: parse_allowed_environment_variables) end access_status = access.check(params[:action], params[:changes]) diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb index cb1065223d4d65b9de3602a5dbc8df63a977137f..3d203017d9f4a1311c600fd7d0a5e3a726e45c59 100644 --- a/lib/gitlab/checks/change_access.rb +++ b/lib/gitlab/checks/change_access.rb @@ -3,11 +3,12 @@ module Gitlab class ChangeAccess attr_reader :user_access, :project - def initialize(change, user_access:, project:) + def initialize(change, user_access:, project:, env: {}) @oldrev, @newrev, @ref = change.values_at(:oldrev, :newrev, :ref) @branch_name = Gitlab::Git.branch_name(@ref) @user_access = user_access @project = project + @env = env end def exec @@ -68,7 +69,7 @@ module Gitlab end def forced_push? - Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev) + Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev, env: @env) end def matching_merge_request? diff --git a/lib/gitlab/checks/force_push.rb b/lib/gitlab/checks/force_push.rb index 5fe86553bd014486944dc6fa936457e490e93628..589525e40ade1d26f68c96c39e59493a98eea542 100644 --- a/lib/gitlab/checks/force_push.rb +++ b/lib/gitlab/checks/force_push.rb @@ -1,14 +1,14 @@ module Gitlab module Checks class ForcePush - def self.force_push?(project, oldrev, newrev) + def self.force_push?(project, oldrev, newrev, env: {}) return false if project.empty_repo? # Created or deleted branch if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev) false else - missed_ref, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list --max-count=1 #{oldrev} ^#{newrev})) + missed_ref, _ = Gitlab::Git::RevList.new(oldrev, newrev, project: project, env: env).execute missed_ref.present? end end diff --git a/lib/gitlab/git/rev_list.rb b/lib/gitlab/git/rev_list.rb new file mode 100644 index 0000000000000000000000000000000000000000..ecdb7f07744fb553028cbf50ef8da1e66cb71ee2 --- /dev/null +++ b/lib/gitlab/git/rev_list.rb @@ -0,0 +1,28 @@ +# Call out to the `git rev-list` command + +module Gitlab + module Git + class RevList + def initialize(oldrev, newrev, project:, env: nil) + @args = [Gitlab.config.git.bin_path, + "--git-dir=#{project.repository.path_to_repo}", + "rev-list", + "--max-count=1", + oldrev, + "^#{newrev}"] + + @env = env.slice(*allowed_environment_variables) + end + + def execute + Gitlab::Popen.popen(@args, nil, @env.slice(*allowed_environment_variables)) + end + + private + + def allowed_environment_variables + %w(GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_OBJECT_DIRECTORY) + end + end + end +end diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index db07b7c5fcc5756dd160e44f7b3cee02c41a96ab..c6b6efda360cb9a752e8128e2a6cb6c942977050 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -17,12 +17,13 @@ module Gitlab attr_reader :actor, :project, :protocol, :user_access, :authentication_abilities - def initialize(actor, project, protocol, authentication_abilities:) + def initialize(actor, project, protocol, authentication_abilities:, env: {}) @actor = actor @project = project @protocol = protocol @authentication_abilities = authentication_abilities @user_access = UserAccess.new(user, project: project) + @env = env end def check(cmd, changes) @@ -103,7 +104,7 @@ module Gitlab end def change_access_check(change) - Checks::ChangeAccess.new(change, user_access: user_access, project: project).exec + Checks::ChangeAccess.new(change, user_access: user_access, project: project, env: @env).exec end def protocol_allowed? diff --git a/lib/gitlab/popen.rb b/lib/gitlab/popen.rb index cc74bb29087c7fd56cc0d7d07b3f57131fd5af53..4bc5cda8cb587ee32ab9f3fd1e88a66ef5925367 100644 --- a/lib/gitlab/popen.rb +++ b/lib/gitlab/popen.rb @@ -5,13 +5,13 @@ module Gitlab module Popen extend self - def popen(cmd, path = nil) + def popen(cmd, path = nil, vars = {}) unless cmd.is_a?(Array) raise "System commands must be given as an array of strings" end path ||= Dir.pwd - vars = { "PWD" => path } + vars['PWD'] = path options = { chdir: path } unless File.directory?(path)