Commit edcc488b authored by Alexis Reigel's avatar Alexis Reigel

use mutex for keychain interaction

setting of the gpg home directory is not thread safe, as the directoy
gets stored on the class.

if multiple threads change the directory at the same time, one of the
threads will be working in the wrong directory.
parent 6cd9888f
...@@ -2,6 +2,8 @@ module Gitlab ...@@ -2,6 +2,8 @@ module Gitlab
module Gpg module Gpg
extend self extend self
MUTEX = Mutex.new
module CurrentKeyChain module CurrentKeyChain
extend self extend self
...@@ -42,7 +44,30 @@ module Gitlab ...@@ -42,7 +44,30 @@ module Gitlab
end end
end end
def using_tmp_keychain # Allows thread safe switching of temporary keychain files
#
# 1. The current thread may use nesting of temporary keychain
# 2. Another thread needs to wait for the lock to be released
def using_tmp_keychain(&block)
if MUTEX.locked? && MUTEX.owned?
optimistic_using_tmp_keychain(&block)
else
MUTEX.synchronize do
optimistic_using_tmp_keychain(&block)
end
end
end
# 1. Returns the custom home directory if one has been set by calling
# `GPGME::Engine.home_dir=`
# 2. Returns the default home directory otherwise
def current_home_dir
GPGME::Engine.info.first.home_dir || GPGME::Engine.dirinfo('homedir')
end
private
def optimistic_using_tmp_keychain
Dir.mktmpdir do |dir| Dir.mktmpdir do |dir|
previous_dir = current_home_dir previous_dir = current_home_dir
...@@ -55,12 +80,5 @@ module Gitlab ...@@ -55,12 +80,5 @@ module Gitlab
return_value return_value
end end
end end
# 1. Returns the custom home directory if one has been set by calling
# `GPGME::Engine.home_dir=`
# 2. Returns the default home directory otherwise
def current_home_dir
GPGME::Engine.info.first.home_dir || GPGME::Engine.dirinfo('homedir')
end
end end
end end
...@@ -65,6 +65,36 @@ describe Gitlab::Gpg do ...@@ -65,6 +65,36 @@ describe Gitlab::Gpg do
expect(described_class.current_home_dir).to eq default_home_dir expect(described_class.current_home_dir).to eq default_home_dir
end end
end end
describe '.using_tmp_keychain' do
it "the second thread does not change the first thread's directory" do
thread1 = Thread.new do
described_class.using_tmp_keychain do
dir = described_class.current_home_dir
sleep 0.1
expect(described_class.current_home_dir).to eq dir
end
end
thread2 = Thread.new do
described_class.using_tmp_keychain do
sleep 0.2
end
end
thread1.join
thread2.join
end
it 'allows recursive execution in the same thread' do
expect do
described_class.using_tmp_keychain do
described_class.using_tmp_keychain do
end
end
end.not_to raise_error(ThreadError)
end
end
end end
describe Gitlab::Gpg::CurrentKeyChain do describe Gitlab::Gpg::CurrentKeyChain do
......
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