1require 'spec_helper'
2
3describe Gitlab::Git::SshAuth do
4  describe Gitlab::Git::SshAuth::Option do
5    it 'invalid keys' do
6      ['foo=bar', 'foo bar', "foo\nbar", %(foo'bar)].each do |key|
7        expect { described_class.new(key, 'zzz') }.to raise_error(ArgumentError)
8      end
9    end
10
11    it 'invalid values' do
12      ['foo bar', "foo\nbar", %(foo'bar)].each do |value|
13        expect { described_class.new('zzz', value) }.to raise_error(ArgumentError)
14      end
15    end
16  end
17
18  describe '.from_gitaly' do
19    it 'initializes based on ssh_key and known_hosts in the request' do
20      result = described_class.from_gitaly(double(ssh_key: 'SSH KEY', known_hosts: 'KNOWN HOSTS'))
21
22      expect(result.class).to eq(described_class)
23      expect(result.ssh_key).to eq('SSH KEY')
24      expect(result.known_hosts).to eq('KNOWN HOSTS')
25    end
26  end
27
28  describe '#setup' do
29    subject { described_class.new(ssh_key, known_hosts).setup { |env| env } }
30
31    context 'no credentials' do
32      let(:ssh_key) { nil }
33      let(:known_hosts) { nil }
34
35      it 'writes no tempfiles' do
36        expect(Tempfile).not_to receive(:new)
37
38        is_expected.to eq({})
39      end
40    end
41
42    context 'just the SSH key' do
43      let(:ssh_key) { 'Fake SSH key' }
44      let(:known_hosts) { nil }
45
46      it 'writes the SSH key file' do
47        ssh_key_file = stub_tempfile('/tmpfiles/keyFile', 'gitlab-shell-key-file', chmod: 0o400)
48
49        is_expected.to eq(build_env(ssh_key_file: ssh_key_file.path))
50
51        expect(ssh_key_file.string).to eq(ssh_key)
52      end
53    end
54
55    context 'just the known_hosts file' do
56      let(:ssh_key) { nil }
57      let(:known_hosts) { 'Fake known_hosts data' }
58
59      it 'writes the known_hosts file and script' do
60        known_hosts_file = stub_tempfile('/tmpfiles/knownHosts', 'gitlab-shell-known-hosts', chmod: 0o400)
61
62        is_expected.to eq(build_env(known_hosts_file: known_hosts_file.path))
63
64        expect(known_hosts_file.string).to eq(known_hosts)
65      end
66    end
67
68    context 'SSH key and known_hosts file' do
69      let(:ssh_key) { 'Fake SSH key' }
70      let(:known_hosts) { 'Fake known_hosts data' }
71
72      it 'writes SSH key, known_hosts and script files' do
73        ssh_key_file = stub_tempfile('id_rsa', 'gitlab-shell-key-file', chmod: 0o400)
74        known_hosts_file = stub_tempfile('known_hosts', 'gitlab-shell-known-hosts', chmod: 0o400)
75
76        is_expected.to eq(build_env(ssh_key_file: ssh_key_file.path, known_hosts_file: known_hosts_file.path))
77
78        expect(ssh_key_file.string).to eq(ssh_key)
79        expect(known_hosts_file.string).to eq(known_hosts)
80      end
81    end
82  end
83
84  def build_env(ssh_key_file: nil, known_hosts_file: nil)
85    opts = []
86
87    if ssh_key_file
88      opts << "-oIdentityFile=#{ssh_key_file}"
89      opts << '-oIdentitiesOnly=yes'
90    end
91
92    if known_hosts_file
93      opts << '-oStrictHostKeyChecking=yes'
94      opts << '-oCheckHostIP=no'
95      opts << "-oUserKnownHostsFile=#{known_hosts_file}"
96    end
97
98    { 'GIT_SSH_COMMAND' => %(ssh #{opts.join(' ')}) }
99  end
100
101  def stub_tempfile(name, filename, chmod:)
102    file = StringIO.new
103
104    allow(file).to receive(:path).and_return(name)
105
106    expect(Tempfile).to receive(:new).with(filename).and_return(file)
107    expect(file).to receive(:chmod).with(chmod)
108    expect(file).to receive(:close!)
109
110    file
111  end
112end
113