Commit 71e4e155 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch '25301-git-2.11-force-push-bug-ee' into 'master'

EE: Accept environment variables from the `pre-receive` script

- EE version of gitlab-org/gitlab-ce!7967

See merge request !964
parents adc66360 4ba505ea
---
title: Accept environment variables from the `pre-receive` script
merge_request: 7967
author:
......@@ -59,6 +59,14 @@ module API
::Users::ActivityService.new(actor, 'Git SSH').execute if commands.include?(params[:action])
end
def parse_allowed_environment_variables
return if params[:env].blank?
JSON.parse(params[:env])
rescue JSON::ParserError
end
end
end
end
......@@ -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])
......
......@@ -4,11 +4,12 @@ module Gitlab
include PathLocksHelper
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
......@@ -69,7 +70,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?
......
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.present?
missed_ref, exit_status = Gitlab::Git::RevList.new(oldrev, newrev, project: project, env: env).execute
if exit_status == 0
missed_ref.present?
else
raise "Got a non-zero exit code while calling out to `git rev-list` in the force-push check."
end
end
end
end
......
module Gitlab
module Git
class RevList
attr_reader :project, :env
ALLOWED_VARIABLES = %w[GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES].freeze
def initialize(oldrev, newrev, project:, env: nil)
@project = project
@env = env.presence || {}
@args = [Gitlab.config.git.bin_path,
"--git-dir=#{project.repository.path_to_repo}",
"rev-list",
"--max-count=1",
oldrev,
"^#{newrev}"]
end
def execute
Gitlab::Popen.popen(@args, nil, parse_environment_variables)
end
def valid?
environment_variables.all? do |(name, value)|
value.start_with?(project.repository.path_to_repo)
end
end
private
def parse_environment_variables
return {} unless valid?
environment_variables
end
def environment_variables
@environment_variables ||= env.slice(*ALLOWED_VARIABLES)
end
end
end
end
......@@ -19,12 +19,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)
......@@ -138,7 +139,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?
......
require 'spec_helper'
describe Gitlab::Checks::ChangeAccess, lib: true do
let(:project) { create(:project) }
context "exit code checking" do
it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do
allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0])
expect { Gitlab::Checks::ForcePush.force_push?(project, 'oldrev', 'newrev') }.not_to raise_error
end
it "raises a runtime error if the `popen` call to git returns a non-zero exit code" do
allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1])
expect { Gitlab::Checks::ForcePush.force_push?(project, 'oldrev', 'newrev') }.to raise_error(RuntimeError)
end
end
end
require 'spec_helper'
describe Gitlab::Git::RevList, lib: true do
let(:project) { create(:project) }
context "validations" do
described_class::ALLOWED_VARIABLES.each do |var|
context var do
it "accepts values starting with the project repo path" do
env = { var => "#{project.repository.path_to_repo}/objects" }
rev_list = described_class.new('oldrev', 'newrev', project: project, env: env)
expect(rev_list).to be_valid
end
it "rejects values starting not with the project repo path" do
env = { var => "/some/other/path" }
rev_list = described_class.new('oldrev', 'newrev', project: project, env: env)
expect(rev_list).not_to be_valid
end
it "rejects values containing the project repo path but not starting with it" do
env = { var => "/some/other/path/#{project.repository.path_to_repo}" }
rev_list = described_class.new('oldrev', 'newrev', project: project, env: env)
expect(rev_list).not_to be_valid
end
end
end
end
context "#execute" do
let(:env) { { "GIT_OBJECT_DIRECTORY" => project.repository.path_to_repo } }
let(:rev_list) { Gitlab::Git::RevList.new('oldrev', 'newrev', project: project, env: env) }
it "calls out to `popen` without environment variables if the record is invalid" do
allow(rev_list).to receive(:valid?).and_return(false)
expect(Open3).to receive(:popen3).with(hash_excluding(env), any_args)
rev_list.execute
end
it "calls out to `popen` with environment variables if the record is valid" do
allow(rev_list).to receive(:valid?).and_return(true)
expect(Open3).to receive(:popen3).with(hash_including(env), any_args)
rev_list.execute
end
end
end
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