diff options
author | Alexis Reigel <mail@koffeinfrei.org> | 2017-08-10 20:33:24 +0200 |
---|---|---|
committer | Alexis Reigel <mail@koffeinfrei.org> | 2017-08-14 12:57:56 +0200 |
commit | edcc488b75d8c6fcad3994bcda30a82756496969 (patch) | |
tree | 18bda21e98f3cbfcad6b4007873f9ac3934a4a87 | |
parent | 6cd9888f6fc8bb1e0b6ff11ace8aacb19aedb268 (diff) | |
download | gitlab-ce-edcc488b75d8c6fcad3994bcda30a82756496969.tar.gz |
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.
-rw-r--r-- | lib/gitlab/gpg.rb | 34 | ||||
-rw-r--r-- | spec/lib/gitlab/gpg_spec.rb | 30 |
2 files changed, 56 insertions, 8 deletions
diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index 653c56d925b..78ebd8866a1 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -2,6 +2,8 @@ module Gitlab module Gpg extend self + MUTEX = Mutex.new + module CurrentKeyChain extend self @@ -42,7 +44,30 @@ module Gitlab 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| previous_dir = current_home_dir @@ -55,12 +80,5 @@ module Gitlab return_value 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 diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 95d371ea178..30ad033b204 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -65,6 +65,36 @@ describe Gitlab::Gpg do expect(described_class.current_home_dir).to eq default_home_dir 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 describe Gitlab::Gpg::CurrentKeyChain do |