Commit 3f05c22f authored by Douwe Maan's avatar Douwe Maan

Merge branch 'rs-git-bin-path' into 'master'

Replace all usages of `git` command with configurable binary path

Closes #3311

See merge request !1742
parents 82aa5419 d09d62b6
...@@ -89,7 +89,7 @@ class Repository ...@@ -89,7 +89,7 @@ class Repository
def find_commits_by_message(query) def find_commits_by_message(query)
# Limited to 1000 commits for now, could be parameterized? # Limited to 1000 commits for now, could be parameterized?
args = %W(git log --pretty=%H --max-count 1000 --grep=#{query}) args = %W(#{Gitlab.config.git.bin_path} log --pretty=%H --max-count 1000 --grep=#{query})
git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp) git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp)
commits = git_log_results.map { |c| commit(c) } commits = git_log_results.map { |c| commit(c) }
...@@ -296,7 +296,7 @@ class Repository ...@@ -296,7 +296,7 @@ class Repository
end end
def last_commit_for_path(sha, path) def last_commit_for_path(sha, path)
args = %W(git rev-list --max-count=1 #{sha} -- #{path}) args = %W(#{Gitlab.config.git.bin_path} rev-list --max-count=1 #{sha} -- #{path})
sha = Gitlab::Popen.popen(args, path_to_repo).first.strip sha = Gitlab::Popen.popen(args, path_to_repo).first.strip
commit(sha) commit(sha)
end end
...@@ -347,7 +347,7 @@ class Repository ...@@ -347,7 +347,7 @@ class Repository
end end
def branch_names_contains(sha) def branch_names_contains(sha)
args = %W(git branch --contains #{sha}) args = %W(#{Gitlab.config.git.bin_path} branch --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split) if names.respond_to?(:split)
...@@ -364,7 +364,7 @@ class Repository ...@@ -364,7 +364,7 @@ class Repository
end end
def tag_names_contains(sha) def tag_names_contains(sha)
args = %W(git tag --contains #{sha}) args = %W(#{Gitlab.config.git.bin_path} tag --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split) if names.respond_to?(:split)
...@@ -505,7 +505,7 @@ class Repository ...@@ -505,7 +505,7 @@ class Repository
def search_files(query, ref) def search_files(query, ref)
offset = 2 offset = 2
args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref}) args = %W(#{Gitlab.config.git.bin_path} grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref})
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/) Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end end
...@@ -537,7 +537,7 @@ class Repository ...@@ -537,7 +537,7 @@ class Repository
end end
def fetch_ref(source_path, source_ref, target_ref) def fetch_ref(source_path, source_ref, target_ref)
args = %W(git fetch -f #{source_path} #{source_ref}:#{target_ref}) args = %W(#{Gitlab.config.git.bin_path} fetch -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo) Gitlab::Popen.popen(args, path_to_repo)
end end
......
module Gitlab module Gitlab
VERSION = File.read(Rails.root.join("VERSION")).strip
REVISION = Gitlab::Popen.popen(%W(git log --pretty=format:%h -n 1)).first.chomp
def self.config def self.config
Settings Settings
end end
VERSION = File.read(Rails.root.join("VERSION")).strip
REVISION = Gitlab::Popen.popen(%W(#{config.git.bin_path} log --pretty=format:%h -n 1)).first.chomp
end end
...@@ -35,6 +35,16 @@ Gitlab::Popen.popen(%W(find /some/path -not -path /some/path -mmin +120 -delete) ...@@ -35,6 +35,16 @@ Gitlab::Popen.popen(%W(find /some/path -not -path /some/path -mmin +120 -delete)
This coding style could have prevented CVE-2013-4490. This coding style could have prevented CVE-2013-4490.
## Always use the configurable git binary path for git commands
```ruby
# Wrong
system(*%W(git branch -d -- #{branch_name}))
# Correct
system(*%W(#{Gitlab.config.git.bin_path} branch -d -- #{branch_name}))
```
## Bypass the shell by splitting commands into separate tokens ## Bypass the shell by splitting commands into separate tokens
When we pass shell commands as a single string to Ruby, Ruby will let `/bin/sh` evaluate the entire string. Essentially, we are asking the shell to evaluate a one-line script. This creates a risk for shell injection attacks. It is better to split the shell command into tokens ourselves. Sometimes we use the scripting capabilities of the shell to change the working directory or set environment variables. All of this can also be achieved securely straight from Ruby When we pass shell commands as a single string to Ruby, Ruby will let `/bin/sh` evaluate the entire string. Essentially, we are asking the shell to evaluate a one-line script. This creates a risk for shell injection attacks. It is better to split the shell command into tokens ourselves. Sometimes we use the scripting capabilities of the shell to change the working directory or set environment variables. All of this can also be achieved securely straight from Ruby
...@@ -81,9 +91,9 @@ In the GitLab codebase, we avoid the option/argument ambiguity by _always_ using ...@@ -81,9 +91,9 @@ In the GitLab codebase, we avoid the option/argument ambiguity by _always_ using
```ruby ```ruby
# Wrong # Wrong
system(*%W(git branch -d #{branch_name})) system(*%W(#{Gitlab.config.git.bin_path} branch -d #{branch_name}))
# Correct # Correct
system(*%W(git branch -d -- #{branch_name})) system(*%W(#{Gitlab.config.git.bin_path} branch -d -- #{branch_name}))
``` ```
This coding style could have prevented CVE-2013-4582. This coding style could have prevented CVE-2013-4582.
...@@ -94,9 +104,9 @@ Capturing the output of shell commands with backticks reads nicely, but you are ...@@ -94,9 +104,9 @@ Capturing the output of shell commands with backticks reads nicely, but you are
```ruby ```ruby
# Wrong # Wrong
logs = `cd #{repo_dir} && git log` logs = `cd #{repo_dir} && #{Gitlab.config.git.bin_path} log`
# Correct # Correct
logs, exit_status = Gitlab::Popen.popen(%W(git log), repo_dir) logs, exit_status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} log), repo_dir)
# Wrong # Wrong
user = `whoami` user = `whoami`
...@@ -108,7 +118,7 @@ In other repositories, such as gitlab-shell you can also use `IO.popen`. ...@@ -108,7 +118,7 @@ In other repositories, such as gitlab-shell you can also use `IO.popen`.
```ruby ```ruby
# Safe IO.popen example # Safe IO.popen example
logs = IO.popen(%W(git log), chdir: repo_dir) { |p| p.read } logs = IO.popen(%W(#{Gitlab.config.git.bin_path} log), chdir: repo_dir) { |p| p.read }
``` ```
Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error. Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error.
......
...@@ -35,7 +35,7 @@ module Backup ...@@ -35,7 +35,7 @@ module Backup
if wiki.repository.empty? if wiki.repository.empty?
$progress.puts " [SKIPPED]".cyan $progress.puts " [SKIPPED]".cyan
else else
cmd = %W(git --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all) cmd = %W(#{Gitlab.config.git.bin_path} --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all)
output, status = Gitlab::Popen.popen(cmd) output, status = Gitlab::Popen.popen(cmd)
if status.zero? if status.zero?
$progress.puts " [DONE]".green $progress.puts " [DONE]".green
...@@ -67,7 +67,7 @@ module Backup ...@@ -67,7 +67,7 @@ module Backup
FileUtils.mkdir_p(path_to_repo(project)) FileUtils.mkdir_p(path_to_repo(project))
cmd = %W(tar -xf #{path_to_bundle(project)} -C #{path_to_repo(project)}) cmd = %W(tar -xf #{path_to_bundle(project)} -C #{path_to_repo(project)})
else else
cmd = %W(git init --bare #{path_to_repo(project)}) cmd = %W(#{Gitlab.config.git.bin_path} init --bare #{path_to_repo(project)})
end end
if system(*cmd, silent) if system(*cmd, silent)
...@@ -87,7 +87,7 @@ module Backup ...@@ -87,7 +87,7 @@ module Backup
# that was initialized with ProjectWiki.new() and then # that was initialized with ProjectWiki.new() and then
# try to restore with 'git clone --bare'. # try to restore with 'git clone --bare'.
FileUtils.rm_rf(path_to_repo(wiki)) FileUtils.rm_rf(path_to_repo(wiki))
cmd = %W(git clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)}) cmd = %W(#{Gitlab.config.git.bin_path} clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)})
if system(*cmd, silent) if system(*cmd, silent)
$progress.puts " [DONE]".green $progress.puts " [DONE]".green
......
...@@ -7,7 +7,7 @@ module Gitlab ...@@ -7,7 +7,7 @@ module Gitlab
if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev) if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev)
false false
else else
missed_refs, _ = Gitlab::Popen.popen(%W(git --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})) missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev}))
missed_refs.split("\n").size > 0 missed_refs.split("\n").size > 0
end end
end end
......
...@@ -6,7 +6,7 @@ module Gitlab ...@@ -6,7 +6,7 @@ module Gitlab
# Returns true for a valid reference name, false otherwise # Returns true for a valid reference name, false otherwise
def validate(ref_name) def validate(ref_name)
Gitlab::Utils.system_silent( Gitlab::Utils.system_silent(
%W(git check-ref-format refs/#{ref_name})) %W(#{Gitlab.config.git.bin_path} check-ref-format refs/#{ref_name}))
end end
end end
end end
...@@ -50,15 +50,15 @@ module Gitlab ...@@ -50,15 +50,15 @@ module Gitlab
end end
def fetch_git_tags def fetch_git_tags
remote_tags, _ = Gitlab::Popen.popen(%W(git ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git)) remote_tags, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git))
remote_tags.split("\n").grep(/tags\/v#{current_version.major}/) remote_tags.split("\n").grep(/tags\/v#{current_version.major}/)
end end
def update_commands def update_commands
{ {
"Stash changed files" => %W(git stash), "Stash changed files" => %W(#{Gitlab.config.git.bin_path} stash),
"Get latest code" => %W(git fetch), "Get latest code" => %W(#{Gitlab.config.git.bin_path} fetch),
"Switch to new version" => %W(git checkout v#{latest_version}), "Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}),
"Install gems" => %W(bundle), "Install gems" => %W(bundle),
"Migrate DB" => %W(bundle exec rake db:migrate), "Migrate DB" => %W(bundle exec rake db:migrate),
"Recompile assets" => %W(bundle exec rake assets:clean assets:precompile), "Recompile assets" => %W(bundle exec rake assets:clean assets:precompile),
......
...@@ -824,7 +824,7 @@ namespace :gitlab do ...@@ -824,7 +824,7 @@ namespace :gitlab do
repo_dirs = Dir.glob(File.join(namespace_dir, '*')) repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
repo_dirs.each do |dir| repo_dirs.each do |dir|
puts "\nChecking repo at #{dir}" puts "\nChecking repo at #{dir}"
system(*%w(git fsck), chdir: dir) system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: dir)
end end
end end
end end
......
...@@ -17,7 +17,7 @@ namespace :gitlab do ...@@ -17,7 +17,7 @@ namespace :gitlab do
# Clone if needed # Clone if needed
unless File.directory?(target_dir) unless File.directory?(target_dir)
system(*%W(git clone -- #{args.repo} #{target_dir})) system(*%W(#{Gitlab.config.git.bin_path} clone -- #{args.repo} #{target_dir}))
end end
# Make sure we're on the right tag # Make sure we're on the right tag
...@@ -27,7 +27,7 @@ namespace :gitlab do ...@@ -27,7 +27,7 @@ namespace :gitlab do
reseted = reset_to_commit(args) reseted = reset_to_commit(args)
unless reseted unless reseted
system(*%W(git fetch origin)) system(*%W(#{Gitlab.config.git.bin_path} fetch origin))
reset_to_commit(args) reset_to_commit(args)
end end
...@@ -128,14 +128,14 @@ namespace :gitlab do ...@@ -128,14 +128,14 @@ namespace :gitlab do
end end
def reset_to_commit(args) def reset_to_commit(args)
tag, status = Gitlab::Popen.popen(%W(git describe -- #{args.tag})) tag, status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} describe -- #{args.tag}))
unless status.zero? unless status.zero?
tag, status = Gitlab::Popen.popen(%W(git describe -- origin/#{args.tag})) tag, status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} describe -- origin/#{args.tag}))
end end
tag = tag.strip tag = tag.strip
system(*%W(git reset --hard #{tag})) system(*%W(#{Gitlab.config.git.bin_path} reset --hard #{tag}))
end end
end end
...@@ -223,7 +223,7 @@ describe ProjectWiki do ...@@ -223,7 +223,7 @@ describe ProjectWiki do
def create_temp_repo(path) def create_temp_repo(path)
FileUtils.mkdir_p path FileUtils.mkdir_p path
system(*%W(git init --quiet --bare -- #{path})) system(*%W(#{Gitlab.config.git.bin_path} init --quiet --bare -- #{path}))
end end
def remove_temp_repo(path) def remove_temp_repo(path)
......
...@@ -36,8 +36,8 @@ describe API::API, api: true do ...@@ -36,8 +36,8 @@ describe API::API, api: true do
it 'should create a new annotated tag' do it 'should create a new annotated tag' do
# Identity must be set in .gitconfig to create annotated tag. # Identity must be set in .gitconfig to create annotated tag.
repo_path = project.repository.path_to_repo repo_path = project.repository.path_to_repo
system(*%W(git --git-dir=#{repo_path} config user.name #{user.name})) system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.name #{user.name}))
system(*%W(git --git-dir=#{repo_path} config user.email #{user.email})) system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.email #{user.email}))
post api("/projects/#{project.id}/repository/tags", user), post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v7.1.0', tag_name: 'v7.1.0',
......
...@@ -96,15 +96,15 @@ module TestEnv ...@@ -96,15 +96,15 @@ module TestEnv
clone_url = "https://gitlab.com/gitlab-org/#{repo_name}.git" clone_url = "https://gitlab.com/gitlab-org/#{repo_name}.git"
unless File.directory?(repo_path) unless File.directory?(repo_path)
system(*%W(git clone -q #{clone_url} #{repo_path})) system(*%W(#{Gitlab.config.git.bin_path} clone -q #{clone_url} #{repo_path}))
end end
Dir.chdir(repo_path) do Dir.chdir(repo_path) do
branch_sha.each do |branch, sha| branch_sha.each do |branch, sha|
# Try to reset without fetching to avoid using the network. # Try to reset without fetching to avoid using the network.
reset = %W(git update-ref refs/heads/#{branch} #{sha}) reset = %W(#{Gitlab.config.git.bin_path} update-ref refs/heads/#{branch} #{sha})
unless system(*reset) unless system(*reset)
if system(*%w(git fetch origin)) if system(*%W(#{Gitlab.config.git.bin_path} fetch origin))
unless system(*reset) unless system(*reset)
raise 'The fetched test seed '\ raise 'The fetched test seed '\
'does not contain the required revision.' 'does not contain the required revision.'
...@@ -117,7 +117,7 @@ module TestEnv ...@@ -117,7 +117,7 @@ module TestEnv
end end
# We must copy bare repositories because we will push to them. # We must copy bare repositories because we will push to them.
system(git_env, *%W(git clone -q --bare #{repo_path} #{repo_path_bare})) system(git_env, *%W(#{Gitlab.config.git.bin_path} clone -q --bare #{repo_path} #{repo_path_bare}))
end end
def copy_repo(project) def copy_repo(project)
......
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