Commit 18b4d39a authored by Alejandro Rodríguez's avatar Alejandro Rodríguez

Refactor repository paths handling to allow multiple git mount points

parent 5a6d71d1
v3.1.0
- Refactor repository paths handling to allow multiple git mount points
v3.0.1 v3.0.1
- Update PostReceive worker to provide enqueued_at time. - Update PostReceive worker to provide enqueued_at time.
......
...@@ -23,18 +23,15 @@ end ...@@ -23,18 +23,15 @@ end
puts "\nCheck directories and files: " puts "\nCheck directories and files: "
config = GitlabConfig.new config = GitlabConfig.new
dirs = [config.repos_path, config.auth_file]
dirs.each do |dir| abort("ERROR: missing option in config.yml") unless config.auth_file
abort("ERROR: missing option in config.yml") unless dir print "\t#{config.auth_file}: "
print "\t#{dir}: " if File.exists?(config.auth_file)
if File.exists?(dir) print 'OK'
print 'OK' else
else abort "FAILED"
abort "FAILED"
end
puts "\n"
end end
puts "\n"
print "Send ping to redis server: " print "Send ping to redis server: "
abort unless GitlabNet.new.redis_client.ping abort unless GitlabNet.new.redis_client.ping
...@@ -7,10 +7,14 @@ ...@@ -7,10 +7,14 @@
require_relative '../lib/gitlab_init' require_relative '../lib/gitlab_init'
require File.join(ROOT_PATH, 'lib', 'gitlab_projects') require File.join(ROOT_PATH, 'lib', 'gitlab_projects')
Dir["#{GitlabConfig.new.repos_path}/*/*.git"].each do |repo| repository_storage_paths = ARGV
begin
GitlabProjects.create_hooks(repo) repository_storage_paths.each do |repo_path|
rescue Errno::ENOENT Dir["#{repo_path.chomp('/')}/*/*.git"].each do |repo|
# The user must have deleted their repository. Ignore. begin
GitlabProjects.create_hooks(repo)
rescue Errno::ENOENT
# The user must have deleted their repository. Ignore.
end
end end
end end
...@@ -8,16 +8,20 @@ require_relative '../lib/gitlab_init' ...@@ -8,16 +8,20 @@ require_relative '../lib/gitlab_init'
config = GitlabConfig.new config = GitlabConfig.new
key_dir = File.dirname("#{config.auth_file}") key_dir = File.dirname("#{config.auth_file}")
repository_storage_paths = ARGV
commands = [ commands = [
%W(mkdir -p #{config.repos_path}),
%W(mkdir -p #{key_dir}), %W(mkdir -p #{key_dir}),
%W(chmod 700 #{key_dir}), %W(chmod 700 #{key_dir}),
%W(touch #{config.auth_file}), %W(touch #{config.auth_file}),
%W(chmod 600 #{config.auth_file}), %W(chmod 600 #{config.auth_file}),
%W(chmod ug+rwX,o-rwx #{config.repos_path}),
] ]
repository_storage_paths.each do |repository_storage_path|
commands << %W(mkdir -p #{repository_storage_path})
commands << %W(chmod ug+rwX,o-rwx #{repository_storage_path})
end
commands.each do |cmd| commands.each do |cmd|
print "#{cmd.join(' ')}: " print "#{cmd.join(' ')}: "
if system(*cmd) if system(*cmd)
......
...@@ -24,12 +24,6 @@ http_settings: ...@@ -24,12 +24,6 @@ http_settings:
# ca_path: /etc/pki/tls/certs # ca_path: /etc/pki/tls/certs
self_signed_cert: false self_signed_cert: false
# Repositories path
# Give the canonicalized absolute pathname,
# REPOS_PATH MUST NOT CONTAIN ANY SYMLINK!!!
# Check twice that none of the components is a symlink, including "/home".
repos_path: "/home/git/repositories"
# File used as authorized_keys for gitlab user # File used as authorized_keys for gitlab user
auth_file: "/home/git/.ssh/authorized_keys" auth_file: "/home/git/.ssh/authorized_keys"
......
...@@ -15,7 +15,7 @@ class GitlabAccess ...@@ -15,7 +15,7 @@ class GitlabAccess
@config = GitlabConfig.new @config = GitlabConfig.new
@repo_path = repo_path.strip @repo_path = repo_path.strip
@actor = actor @actor = actor
@repo_name = extract_repo_name(@repo_path.dup, config.repos_path.to_s) @repo_name = extract_repo_name(@repo_path.dup)
@changes = changes.lines @changes = changes.lines
end end
......
require 'json' require 'json'
class GitAccessStatus class GitAccessStatus
attr_reader :message attr_reader :message, :repository_path
def initialize(status, message) def initialize(status, message, repository_path)
@status = status @status = status
@message = message @message = message
@repository_path = repository_path
end end
def self.create_from_json(json) def self.create_from_json(json)
values = JSON.parse(json) values = JSON.parse(json)
self.new(values["status"], values["message"]) self.new(values["status"], values["message"], values["repository_path"])
end end
def allowed? def allowed?
......
...@@ -11,10 +11,6 @@ class GitlabConfig ...@@ -11,10 +11,6 @@ class GitlabConfig
ENV['HOME'] ENV['HOME']
end end
def repos_path
@config['repos_path'] ||= File.join(home, "repositories")
end
def auth_file def auth_file
@config['auth_file'] ||= File.join(home, ".ssh/authorized_keys") @config['auth_file'] ||= File.join(home, ".ssh/authorized_keys")
end end
......
...@@ -38,7 +38,7 @@ class GitlabNet ...@@ -38,7 +38,7 @@ class GitlabNet
if resp.code == '200' if resp.code == '200'
GitAccessStatus.create_from_json(resp.body) GitAccessStatus.create_from_json(resp.body)
else else
GitAccessStatus.new(false, 'API is not accessible') GitAccessStatus.new(false, 'API is not accessible', nil)
end end
end end
......
...@@ -43,8 +43,8 @@ class GitlabProjects ...@@ -43,8 +43,8 @@ class GitlabProjects
def initialize def initialize
@command = ARGV.shift @command = ARGV.shift
@repos_path = ARGV.shift
@project_name = ARGV.shift @project_name = ARGV.shift
@repos_path = GitlabConfig.new.repos_path
@full_path = File.join(@repos_path, @project_name) unless @project_name.nil? @full_path = File.join(@repos_path, @project_name) unless @project_name.nil?
end end
......
...@@ -9,12 +9,12 @@ class GitlabShell ...@@ -9,12 +9,12 @@ class GitlabShell
GIT_COMMANDS = %w(git-upload-pack git-receive-pack git-upload-archive git-annex-shell git-lfs-authenticate).freeze GIT_COMMANDS = %w(git-upload-pack git-receive-pack git-upload-archive git-annex-shell git-lfs-authenticate).freeze
attr_accessor :key_id, :repo_name, :git_cmd, :repos_path, :repo_name attr_accessor :key_id, :repo_name, :git_cmd
attr_reader :repo_path
def initialize(key_id) def initialize(key_id)
@key_id = key_id @key_id = key_id
@config = GitlabConfig.new @config = GitlabConfig.new
@repos_path = @config.repos_path
end end
# The origin_cmd variable contains UNTRUSTED input. If the user ran # The origin_cmd variable contains UNTRUSTED input. If the user ran
...@@ -66,13 +66,10 @@ class GitlabShell ...@@ -66,13 +66,10 @@ class GitlabShell
when 'git-annex-shell' when 'git-annex-shell'
raise DisallowedCommandError unless @config.git_annex_enabled? raise DisallowedCommandError unless @config.git_annex_enabled?
@repo_name = escape_path(args[2].sub(/\A\/~\//, '')) @repo_name = args[2].sub(/\A\/~\//, '')
# Make sure repository has git-annex enabled
init_git_annex(@repo_name) unless gcryptsetup?(args)
when 'git-lfs-authenticate' when 'git-lfs-authenticate'
raise DisallowedCommandError unless args.count >= 2 raise DisallowedCommandError unless args.count >= 2
@repo_name = escape_path(args[1]) @repo_name = args[1]
case args[2] case args[2]
when 'download' when 'download'
@git_access = 'git-upload-pack' @git_access = 'git-upload-pack'
...@@ -83,7 +80,7 @@ class GitlabShell ...@@ -83,7 +80,7 @@ class GitlabShell
end end
else else
raise DisallowedCommandError unless args.count == 2 raise DisallowedCommandError unless args.count == 2
@repo_name = escape_path(args.last) @repo_name = args.last
end end
end end
...@@ -91,19 +88,22 @@ class GitlabShell ...@@ -91,19 +88,22 @@ class GitlabShell
status = api.check_access(@git_access, @repo_name, @key_id, '_any') status = api.check_access(@git_access, @repo_name, @key_id, '_any')
raise AccessDeniedError, status.message unless status.allowed? raise AccessDeniedError, status.message unless status.allowed?
self.repo_path = status.repository_path
end end
def process_cmd(args) def process_cmd(args)
repo_full_path = File.join(repos_path, repo_name)
if @git_cmd == 'git-annex-shell' if @git_cmd == 'git-annex-shell'
raise DisallowedCommandError unless @config.git_annex_enabled? raise DisallowedCommandError unless @config.git_annex_enabled?
# Make sure repository has git-annex enabled
init_git_annex unless gcryptsetup?(args)
parsed_args = parsed_args =
args.map do |arg| args.map do |arg|
# use full repo path # use full repo path
if arg =~ /\A\/.*\.git\Z/ if arg =~ /\A\/.*\.git\Z/
repo_full_path repo_path
else else
arg arg
end end
...@@ -112,8 +112,8 @@ class GitlabShell ...@@ -112,8 +112,8 @@ class GitlabShell
$logger.info "gitlab-shell: executing git-annex command <#{parsed_args.join(' ')}> for #{log_username}." $logger.info "gitlab-shell: executing git-annex command <#{parsed_args.join(' ')}> for #{log_username}."
exec_cmd(*parsed_args) exec_cmd(*parsed_args)
else else
$logger.info "gitlab-shell: executing git command <#{@git_cmd} #{repo_full_path}> for #{log_username}." $logger.info "gitlab-shell: executing git command <#{@git_cmd} #{repo_path}> for #{log_username}."
exec_cmd(@git_cmd, repo_full_path) exec_cmd(@git_cmd, repo_path)
end end
end end
...@@ -164,23 +164,11 @@ class GitlabShell ...@@ -164,23 +164,11 @@ class GitlabShell
@config.audit_usernames ? username : "user with key #{@key_id}" @config.audit_usernames ? username : "user with key #{@key_id}"
end end
def escape_path(path) def init_git_annex
full_repo_path = File.join(repos_path, path) unless File.exists?(File.join(repo_path, 'annex'))
cmd = %W(git --git-dir=#{repo_path} annex init "GitLab")
if File.absolute_path(full_repo_path) == full_repo_path
path
else
raise InvalidRepositoryPathError
end
end
def init_git_annex(path)
full_repo_path = File.join(repos_path, path)
unless File.exists?(File.join(full_repo_path, 'annex'))
cmd = %W(git --git-dir=#{full_repo_path} annex init "GitLab")
system(*cmd, err: '/dev/null', out: '/dev/null') system(*cmd, err: '/dev/null', out: '/dev/null')
$logger.info "Enable git-annex for repository: #{path}." $logger.info "Enable git-annex for repository: #{repo_name}."
end end
end end
...@@ -188,4 +176,12 @@ class GitlabShell ...@@ -188,4 +176,12 @@ class GitlabShell
non_dashed = args.reject { |a| a.start_with?('-') } non_dashed = args.reject { |a| a.start_with?('-') }
non_dashed[0, 2] == %w{git-annex-shell gcryptsetup} non_dashed[0, 2] == %w{git-annex-shell gcryptsetup}
end end
private
def repo_path=(repo_path)
raise InvalidRepositoryPathError if File.absolute_path(repo_path) != repo_path
@repo_path = repo_path
end
end end
module NamesHelper module NamesHelper
def extract_repo_name(path, base) def extract_repo_name(path)
repo_name = path.strip repo_name = path.strip
repo_name.gsub!(base, "")
repo_name.gsub!(/\.git$/, "") repo_name.gsub!(/\.git$/, "")
repo_name.gsub!(/^\//, "") repo_name.gsub!(/^\//, "")
repo_name repo_name.split(File::SEPARATOR).last(2).join(File::SEPARATOR)
end end
def extract_ref_name(ref) def extract_ref_name(ref)
......
...@@ -7,7 +7,7 @@ describe GitlabAccess do ...@@ -7,7 +7,7 @@ describe GitlabAccess do
let(:repo_path) { File.join(repository_path, repo_name) + ".git" } let(:repo_path) { File.join(repository_path, repo_name) + ".git" }
let(:api) do let(:api) do
double(GitlabNet).tap do |api| double(GitlabNet).tap do |api|
api.stub(check_access: GitAccessStatus.new(true, 'ok')) api.stub(check_access: GitAccessStatus.new(true, 'ok', '/home/git/repositories'))
end end
end end
subject do subject do
...@@ -38,7 +38,7 @@ describe GitlabAccess do ...@@ -38,7 +38,7 @@ describe GitlabAccess do
context "access is denied" do context "access is denied" do
before do before do
api.stub(check_access: GitAccessStatus.new(false, 'denied')) api.stub(check_access: GitAccessStatus.new(false, 'denied', nil))
end end
it "returns false" do it "returns false" do
......
...@@ -59,21 +59,22 @@ describe GitlabProjects do ...@@ -59,21 +59,22 @@ describe GitlabProjects do
describe :initialize do describe :initialize do
before do before do
argv('add-project', repo_name) argv('add-project', tmp_repos_path, repo_name)
@gl_projects = GitlabProjects.new @gl_projects = GitlabProjects.new
end end
it { @gl_projects.project_name.should == repo_name } it { @gl_projects.project_name.should == repo_name }
it { @gl_projects.repos_path.should == tmp_repos_path }
it { @gl_projects.full_path.should == "#{tmp_repos_path}/gitlab-ci.git" }
it { @gl_projects.instance_variable_get(:@command).should == 'add-project' } it { @gl_projects.instance_variable_get(:@command).should == 'add-project' }
it { @gl_projects.instance_variable_get(:@full_path).should == "#{GitlabConfig.new.repos_path}/gitlab-ci.git" }
end end
describe :create_tag do describe :create_tag do
let(:gl_projects_create) { let(:gl_projects_create) {
build_gitlab_projects('import-project', repo_name, 'https://github.com/randx/six.git') build_gitlab_projects('import-project', tmp_repos_path, repo_name, 'https://github.com/randx/six.git')
} }
context "lightweight tag" do context "lightweight tag" do
let(:gl_projects) { build_gitlab_projects('create-tag', repo_name, 'test_tag', 'master') } let(:gl_projects) { build_gitlab_projects('create-tag', tmp_repos_path, repo_name, 'test_tag', 'master') }
it "should create a tag" do it "should create a tag" do
gl_projects_create.exec gl_projects_create.exec
...@@ -87,7 +88,7 @@ describe GitlabProjects do ...@@ -87,7 +88,7 @@ describe GitlabProjects do
msg = 'some message' msg = 'some message'
tag_name = 'test_annotated_tag' tag_name = 'test_annotated_tag'
let(:gl_projects) { build_gitlab_projects('create-tag', repo_name, tag_name, 'master', msg) } let(:gl_projects) { build_gitlab_projects('create-tag', tmp_repos_path, repo_name, tag_name, 'master', msg) }
it "should create an annotated tag" do it "should create an annotated tag" do
gl_projects_create.exec gl_projects_create.exec
...@@ -106,7 +107,7 @@ describe GitlabProjects do ...@@ -106,7 +107,7 @@ describe GitlabProjects do
end end
describe :add_project do describe :add_project do
let(:gl_projects) { build_gitlab_projects('add-project', repo_name) } let(:gl_projects) { build_gitlab_projects('add-project', tmp_repos_path, repo_name) }
it "should create a directory" do it "should create a directory" do
gl_projects.stub(system: true) gl_projects.stub(system: true)
...@@ -130,7 +131,7 @@ describe GitlabProjects do ...@@ -130,7 +131,7 @@ describe GitlabProjects do
describe :list_projects do describe :list_projects do
let(:gl_projects) do let(:gl_projects) do
build_gitlab_projects('add-project', "list_test/#{repo_name}") build_gitlab_projects('add-project', tmp_repos_path, "list_test/#{repo_name}")
end end
before do before do
...@@ -145,7 +146,7 @@ describe GitlabProjects do ...@@ -145,7 +146,7 @@ describe GitlabProjects do
end end
describe :mv_project do describe :mv_project do
let(:gl_projects) { build_gitlab_projects('mv-project', repo_name, 'repo.git') } let(:gl_projects) { build_gitlab_projects('mv-project', tmp_repos_path, repo_name, 'repo.git') }
let(:new_repo_path) { File.join(tmp_repos_path, 'repo.git') } let(:new_repo_path) { File.join(tmp_repos_path, 'repo.git') }
before do before do
...@@ -160,20 +161,20 @@ describe GitlabProjects do ...@@ -160,20 +161,20 @@ describe GitlabProjects do
end end
it "should fail if no destination path is provided" do it "should fail if no destination path is provided" do
incomplete = build_gitlab_projects('mv-project', repo_name) incomplete = build_gitlab_projects('mv-project', tmp_repos_path, repo_name)
$logger.should_receive(:error).with("mv-project failed: no destination path provided.") $logger.should_receive(:error).with("mv-project failed: no destination path provided.")
incomplete.exec.should be_false incomplete.exec.should be_false
end end
it "should fail if the source path doesn't exist" do it "should fail if the source path doesn't exist" do
bad_source = build_gitlab_projects('mv-project', 'bad-src.git', 'dest.git') bad_source = build_gitlab_projects('mv-project', tmp_repos_path, 'bad-src.git', 'dest.git')
$logger.should_receive(:error).with("mv-project failed: source path <#{tmp_repos_path}/bad-src.git> does not exist.") $logger.should_receive(:error).with("mv-project failed: source path <#{tmp_repos_path}/bad-src.git> does not exist.")
bad_source.exec.should be_false bad_source.exec.should be_false
end end
it "should fail if the destination path already exists" do it "should fail if the destination path already exists" do
FileUtils.mkdir_p(File.join(tmp_repos_path, 'already-exists.git')) FileUtils.mkdir_p(File.join(tmp_repos_path, 'already-exists.git'))
bad_dest = build_gitlab_projects('mv-project', repo_name, 'already-exists.git') bad_dest = build_gitlab_projects('mv-project', tmp_repos_path, repo_name, 'already-exists.git')
message = "mv-project failed: destination path <#{tmp_repos_path}/already-exists.git> already exists." message = "mv-project failed: destination path <#{tmp_repos_path}/already-exists.git> already exists."
$logger.should_receive(:error).with(message) $logger.should_receive(:error).with(message)
bad_dest.exec.should be_false bad_dest.exec.should be_false
...@@ -187,7 +188,7 @@ describe GitlabProjects do ...@@ -187,7 +188,7 @@ describe GitlabProjects do
end end
describe :rm_project do describe :rm_project do
let(:gl_projects) { build_gitlab_projects('rm-project', repo_name) } let(:gl_projects) { build_gitlab_projects('rm-project', tmp_repos_path, repo_name) }
before do before do
FileUtils.mkdir_p(tmp_repo_path) FileUtils.mkdir_p(tmp_repo_path)
...@@ -207,7 +208,7 @@ describe GitlabProjects do ...@@ -207,7 +208,7 @@ describe GitlabProjects do
describe :import_project do describe :import_project do
context 'success import' do context 'success import' do
let(:gl_projects) { build_gitlab_projects('import-project', repo_name, 'https://github.com/randx/six.git') } let(:gl_projects) { build_gitlab_projects('import-project', tmp_repos_path, repo_name, 'https://github.com/randx/six.git') }
it { gl_projects.exec.should be_true } it { gl_projects.exec.should be_true }
...@@ -224,7 +225,7 @@ describe GitlabProjects do ...@@ -224,7 +225,7 @@ describe GitlabProjects do
end end
context 'already exists' do context 'already exists' do
let(:gl_projects) { build_gitlab_projects('import-project', repo_name, 'https://github.com/randx/six.git') } let(:gl_projects) { build_gitlab_projects('import-project', tmp_repos_path, repo_name, 'https://github.com/randx/six.git') }
it 'should import only once' do it 'should import only once' do
gl_projects.exec.should be_true gl_projects.exec.should be_true
...@@ -233,7 +234,7 @@ describe GitlabProjects do ...@@ -233,7 +234,7 @@ describe GitlabProjects do
end end
context 'timeout' do context 'timeout' do
let(:gl_projects) { build_gitlab_projects('import-project', repo_name, 'https://github.com/gitlabhq/gitlabhq.git', '1') } let(:gl_projects) { build_gitlab_projects('import-project', tmp_repos_path, repo_name, 'https://github.com/gitlabhq/gitlabhq.git', '1') }
it { gl_projects.exec.should be_false } it { gl_projects.exec.should be_false }
...@@ -253,15 +254,15 @@ describe GitlabProjects do ...@@ -253,15 +254,15 @@ describe GitlabProjects do
describe :fork_project do describe :fork_project do
let(:source_repo_name) { File.join('source-namespace', repo_name) } let(:source_repo_name) { File.join('source-namespace', repo_name) }
let(:dest_repo) { File.join(tmp_repos_path, 'forked-to-namespace', repo_name) } let(:dest_repo) { File.join(tmp_repos_path, 'forked-to-namespace', repo_name) }
let(:gl_projects_fork) { build_gitlab_projects('fork-project', source_repo_name, 'forked-to-namespace') } let(:gl_projects_fork) { build_gitlab_projects('fork-project', tmp_repos_path, source_repo_name, 'forked-to-namespace') }
let(:gl_projects_import) { build_gitlab_projects('import-project', source_repo_name, 'https://github.com/randx/six.git') } let(:gl_projects_import) { build_gitlab_projects('import-project', tmp_repos_path, source_repo_name, 'https://github.com/randx/six.git') }
before do before do
gl_projects_import.exec gl_projects_import.exec
end end
it "should not fork without a destination namespace" do it "should not fork without a destination namespace" do
missing_arg = build_gitlab_projects('fork-project', source_repo_name) missing_arg = build_gitlab_projects('fork-project', tmp_repos_path, source_repo_name)
$logger.should_receive(:error).with("fork-project failed: no destination namespace provided.") $logger.should_receive(:error).with("fork-project failed: no destination namespace provided.")
missing_arg.exec.should be_false missing_arg.exec.should be_false
end end
...@@ -304,13 +305,13 @@ describe GitlabProjects do ...@@ -304,13 +305,13 @@ describe GitlabProjects do
describe :exec do describe :exec do
it 'should puts message if unknown command arg' do it 'should puts message if unknown command arg' do
gitlab_projects = build_gitlab_projects('edit-project', repo_name) gitlab_projects = build_gitlab_projects('edit-project', tmp_repos_path, repo_name)
gitlab_projects.should_receive(:puts).with('not allowed') gitlab_projects.should_receive(:puts).with('not allowed')
gitlab_projects.exec gitlab_projects.exec
end end
it 'should log a warning for unknown commands' do it 'should log a warning for unknown commands' do
gitlab_projects = build_gitlab_projects('hurf-durf', repo_name) gitlab_projects = build_gitlab_projects('hurf-durf', tmp_repos_path, repo_name)
$logger.should_receive(:warn).with('Attempt to execute invalid gitlab-projects command "hurf-durf".') $logger.should_receive(:warn).with('Attempt to execute invalid gitlab-projects command "hurf-durf".')
gitlab_projects.exec gitlab_projects.exec
end end
......
...@@ -22,7 +22,7 @@ describe GitlabShell do ...@@ -22,7 +22,7 @@ describe GitlabShell do
let(:api) do let(:api) do
double(GitlabNet).tap do |api| double(GitlabNet).tap do |api|
api.stub(discover: { 'name' => 'John Doe' }) api.stub(discover: { 'name' => 'John Doe' })
api.stub(check_access: GitAccessStatus.new(true, 'ok')) api.stub(check_access: GitAccessStatus.new(true, 'ok', repo_path))
end end
end end
...@@ -30,15 +30,17 @@ describe GitlabShell do ...@@ -30,15 +30,17 @@ describe GitlabShell do
let(:ssh_cmd) { nil } let(:ssh_cmd) { nil }
let(:tmp_repos_path) { File.join(ROOT_PATH, 'tmp', 'repositories') } let(:tmp_repos_path) { File.join(ROOT_PATH, 'tmp', 'repositories') }
let(:repo_name) { 'gitlab-ci.git' }
let(:repo_path) { File.join(tmp_repos_path, repo_name) }
before do before do
GitlabConfig.any_instance.stub(repos_path: tmp_repos_path, audit_usernames: false) GitlabConfig.any_instance.stub(audit_usernames: false)
end end
describe :initialize do describe :initialize do
let(:ssh_cmd) { 'git-receive-pack' } let(:ssh_cmd) { 'git-receive-pack' }
its(:key_id) { should == key_id } its(:key_id) { should == key_id }
its(:repos_path) { should == tmp_repos_path }
end end
describe :parse_cmd do describe :parse_cmd do
...@@ -55,6 +57,7 @@ describe GitlabShell do ...@@ -55,6 +57,7 @@ describe GitlabShell do
end end
context 'namespace' do context 'namespace' do
let(:repo_name) { 'dmitriy.zaporozhets/gitlab-ci.git' }
let(:ssh_args) { %W(git-upload-pack dmitriy.zaporozhets/gitlab-ci.git) } let(:ssh_args) { %W(git-upload-pack dmitriy.zaporozhets/gitlab-ci.git) }
before do before do
...@@ -75,50 +78,24 @@ describe GitlabShell do ...@@ -75,50 +78,24 @@ describe GitlabShell do
end end
describe 'git-annex' do describe 'git-annex' do
let(:repo_path) { File.join(tmp_repos_path, 'dzaporozhets/gitlab.git') } let(:repo_name) { 'dzaporozhets/gitlab.git' }
let(:ssh_args) { %W(git-annex-shell inannex /~/dzaporozhets/gitlab.git SHA256E) } let(:ssh_args) { %W(git-annex-shell inannex /~/dzaporozhets/gitlab.git SHA256E) }
before do before do
GitlabConfig.any_instance.stub(git_annex_enabled?: true) GitlabConfig.any_instance.stub(git_annex_enabled?: true)
# Create existing project
FileUtils.mkdir_p(repo_path)
cmd = %W(git --git-dir=#{repo_path} init --bare)
system(*cmd)
subject.send :parse_cmd, ssh_args subject.send :parse_cmd, ssh_args
end end
its(:repo_name) { should == 'dzaporozhets/gitlab.git' } its(:repo_name) { should == 'dzaporozhets/gitlab.git' }
its(:git_cmd) { should == 'git-annex-shell' } its(:git_cmd) { should == 'git-annex-shell' }
it 'should init git-annex' do
File.exists?(File.join(tmp_repos_path, 'dzaporozhets/gitlab.git/annex')).should be_true
end
context 'with git-annex-shell gcryptsetup' do
let(:ssh_args) { %W(git-annex-shell gcryptsetup /~/dzaporozhets/gitlab.git) }
it 'should not init git-annex' do
File.exists?(File.join(tmp_repos_path, 'dzaporozhets/gitlab.git/annex')).should be_false
end
end
context 'with git-annex and relative path without ~/' do
# Using a SSH URL on a custom port will generate /dzaporozhets/gitlab.git
let(:ssh_args) { %W(git-annex-shell inannex /dzaporozhets/gitlab.git SHA256E) }
it 'should init git-annex' do
File.exists?(File.join(tmp_repos_path, 'dzaporozhets/gitlab.git/annex')).should be_true
end
end
end end
end end
describe :exec do describe :exec do
context 'git-upload-pack' do context 'git-upload-pack' do
let(:ssh_cmd) { 'git-upload-pack gitlab-ci.git' } let(:ssh_cmd) { "git-upload-pack gitlab-ci.git" }
after { subject.exec(ssh_cmd) } after { subject.exec(ssh_cmd) }
it "should process the command" do it "should process the command" do
...@@ -126,12 +103,12 @@ describe GitlabShell do ...@@ -126,12 +103,12 @@ describe GitlabShell do
end end
it "should execute the command" do it "should execute the command" do
subject.should_receive(:exec_cmd).with("git-upload-pack", File.join(tmp_repos_path, 'gitlab-ci.git')) subject.should_receive(:exec_cmd).with("git-upload-pack", repo_path)
end end
it "should log the command execution" do it "should log the command execution" do
message = "gitlab-shell: executing git command " message = "gitlab-shell: executing git command "
message << "<git-upload-pack #{File.join(tmp_repos_path, 'gitlab-ci.git')}> " message << "<git-upload-pack #{repo_path}> "
message << "for user with key #{key_id}." message << "for user with key #{key_id}."
$logger.should_receive(:info).with(message) $logger.should_receive(:info).with(message)
end end
...@@ -143,7 +120,7 @@ describe GitlabShell do ...@@ -143,7 +120,7 @@ describe GitlabShell do
end end
context 'git-receive-pack' do context 'git-receive-pack' do
let(:ssh_cmd) { 'git-receive-pack gitlab-ci.git' } let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" }
after { subject.exec(ssh_cmd) } after { subject.exec(ssh_cmd) }
it "should process the command" do it "should process the command" do
...@@ -151,12 +128,12 @@ describe GitlabShell do ...@@ -151,12 +128,12 @@ describe GitlabShell do
end end
it "should execute the command" do it "should execute the command" do
subject.should_receive(:exec_cmd).with("git-receive-pack", File.join(tmp_repos_path, 'gitlab-ci.git')) subject.should_receive(:exec_cmd).with("git-receive-pack", repo_path)
end end
it "should log the command execution" do it "should log the command execution" do
message = "gitlab-shell: executing git command " message = "gitlab-shell: executing git command "
message << "<git-receive-pack #{File.join(tmp_repos_path, 'gitlab-ci.git')}> " message << "<git-receive-pack #{repo_path}> "
message << "for user with key #{key_id}." message << "for user with key #{key_id}."
$logger.should_receive(:info).with(message) $logger.should_receive(:info).with(message)
end end
...@@ -206,34 +183,93 @@ describe GitlabShell do ...@@ -206,34 +183,93 @@ describe GitlabShell do
end end
describe 'git-annex' do describe 'git-annex' do
let(:ssh_cmd) { 'git-annex-shell commit /~/gitlab-ci.git SHA256' } let(:repo_name) { 'dzaporozhets/gitlab.git' }
before do before do
GitlabConfig.any_instance.stub(git_annex_enabled?: true) GitlabConfig.any_instance.stub(git_annex_enabled?: true)
end end
after { subject.exec(ssh_cmd) } context 'initialization' do
let(:ssh_cmd) { "git-annex-shell inannex /~/gitlab-ci.git SHA256E" }
it "should execute the command" do before do
subject.should_receive(:exec_cmd).with("git-annex-shell", "commit", File.join(tmp_repos_path, 'gitlab-ci.git'), "SHA256") # Create existing project
FileUtils.mkdir_p(repo_path)
cmd = %W(git --git-dir=#{repo_path} init --bare)
system(*cmd)
subject.exec(ssh_cmd)
end
it 'should init git-annex' do
File.exists?(repo_path).should be_true
end
context 'with git-annex-shell gcryptsetup' do
let(:ssh_cmd) { "git-annex-shell gcryptsetup /~/dzaporozhets/gitlab.git" }
it 'should not init git-annex' do
File.exists?(File.join(tmp_repos_path, 'dzaporozhets/gitlab.git/annex')).should be_false
end
end
context 'with git-annex and relative path without ~/' do
# Using a SSH URL on a custom port will generate /dzaporozhets/gitlab.git
let(:ssh_cmd) { "git-annex-shell inannex dzaporozhets/gitlab.git SHA256E" }
it 'should init git-annex' do
File.exists?(File.join(tmp_repos_path, "dzaporozhets/gitlab.git/annex")).should be_true
end
end
end
context 'execution' do
let(:ssh_cmd) { "git-annex-shell commit /~/gitlab-ci.git SHA256" }
after { subject.exec(ssh_cmd) }
it "should execute the command" do
subject.should_receive(:exec_cmd).with("git-annex-shell", "commit", repo_path, "SHA256")
end
end end
end end
end end
describe :validate_access do describe :validate_access do
let(:ssh_cmd) { 'git-upload-pack gitlab-ci.git' } let(:ssh_cmd) { "git-upload-pack gitlab-ci.git" }
after { subject.exec(ssh_cmd) }
describe 'check access with api' do
after { subject.exec(ssh_cmd) }
it "should call api.check_access" do it "should call api.check_access" do
api.should_receive(:check_access). api.should_receive(:check_access).with('git-upload-pack', 'gitlab-ci.git', key_id, '_any')
with('git-upload-pack', 'gitlab-ci.git', key_id, '_any') end
it "should disallow access and log the attempt if check_access returns false status" do
api.stub(check_access: GitAccessStatus.new(false, 'denied', nil))
message = "gitlab-shell: Access denied for git command <git-upload-pack gitlab-ci.git> "
message << "by user with key #{key_id}."
$logger.should_receive(:warn).with(message)
end
end end
it "should disallow access and log the attempt if check_access returns false status" do describe 'set the repository path' do
api.stub(check_access: GitAccessStatus.new(false, 'denied')) context 'with a correct path' do
message = "gitlab-shell: Access denied for git command <git-upload-pack gitlab-ci.git> " before { subject.exec(ssh_cmd) }
message << "by user with key #{key_id}."
$logger.should_receive(:warn).with(message) its(:repo_path) { should == repo_path }
end
context "with a path that doesn't match an absolute path" do
before do
File.stub(:absolute_path) { 'y/gitlab-ci.git' }
end
it "refuses to assign the path" do
$stderr.should_receive(:puts).with("GitLab: Invalid repository path")
expect(subject.exec(ssh_cmd)).to be_false
end
end
end end
end end
...@@ -262,12 +298,4 @@ describe GitlabShell do ...@@ -262,12 +298,4 @@ describe GitlabShell do
it { should be_a(GitlabNet) } it { should be_a(GitlabNet) }
end end
describe :escape_path do
let(:shell) { GitlabShell.new(key_id) }
before { File.stub(:absolute_path) { 'y' } }
subject { -> { shell.send(:escape_path, 'z') } }
it { should raise_error(GitlabShell::InvalidRepositoryPathError) }
end
end end
...@@ -5,8 +5,8 @@ describe NamesHelper do ...@@ -5,8 +5,8 @@ describe NamesHelper do
include NamesHelper include NamesHelper
describe :extract_repo_name do describe :extract_repo_name do
it { extract_repo_name(' /opt/repos/randx/gitlab.git', '/opt/repos').should == 'randx/gitlab' } it { extract_repo_name(' /opt/repos/randx/gitlab.git').should == 'randx/gitlab' }
it { extract_repo_name("/opt/repos/randx/gitlab.git\r\n", '/opt/repos/').should == 'randx/gitlab' } it { extract_repo_name("/opt/repos/randx/gitlab.git\r\n").should == 'randx/gitlab' }
end end
describe :extract_ref_name do describe :extract_ref_name do
...@@ -15,4 +15,3 @@ describe NamesHelper do ...@@ -15,4 +15,3 @@ describe NamesHelper do
it { extract_ref_name('refs/tags/releases/v2.2.1').should == 'releases/v2.2.1' } it { extract_ref_name('refs/tags/releases/v2.2.1').should == 'releases/v2.2.1' }
end 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