net-ssh 2.9.4 → 2.10.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +11 -4
  5. data/CHANGES.txt +15 -5
  6. data/README.rdoc +1 -1
  7. data/Rakefile +12 -5
  8. data/lib/net/ssh.rb +16 -1
  9. data/lib/net/ssh/authentication/key_manager.rb +20 -11
  10. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +11 -4
  11. data/lib/net/ssh/authentication/methods/password.rb +3 -1
  12. data/lib/net/ssh/authentication/pageant.rb +32 -12
  13. data/lib/net/ssh/connection/channel.rb +7 -26
  14. data/lib/net/ssh/connection/session.rb +2 -11
  15. data/lib/net/ssh/proxy/command.rb +14 -3
  16. data/lib/net/ssh/ruby_compat.rb +0 -5
  17. data/lib/net/ssh/transport/algorithms.rb +3 -4
  18. data/lib/net/ssh/transport/cipher_factory.rb +0 -1
  19. data/lib/net/ssh/transport/session.rb +8 -7
  20. data/lib/net/ssh/version.rb +4 -4
  21. data/net-ssh-public_cert.pem +15 -15
  22. data/net-ssh.gemspec +9 -5
  23. data/setup.rb +1 -1
  24. data/test/README.txt +6 -13
  25. data/test/authentication/methods/test_keyboard_interactive.rb +21 -0
  26. data/test/authentication/test_key_manager.rb +5 -1
  27. data/test/connection/test_channel.rb +0 -3
  28. data/test/connection/test_session.rb +8 -17
  29. data/test/integration/README.txt +19 -0
  30. data/test/integration/Vagrantfile +12 -0
  31. data/test/integration/common.rb +57 -0
  32. data/test/integration/playbook.yml +46 -0
  33. data/test/integration/test_id_rsa_keys.rb +78 -0
  34. data/test/start/test_options.rb +8 -1
  35. data/test/test_all.rb +1 -0
  36. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +5 -1
  37. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +5 -1
  38. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +2 -17
  39. data/test/transport/test_algorithms.rb +21 -17
  40. data/test/transport/test_session.rb +1 -1
  41. metadata +24 -20
  42. metadata.gz.sig +0 -0
  43. data/Rudyfile +0 -96
@@ -1,4 +1,5 @@
1
1
  require 'socket'
2
+ require 'rubygems'
2
3
  require 'net/ssh/proxy/errors'
3
4
  require 'net/ssh/ruby_compat'
4
5
 
@@ -66,12 +67,22 @@ module Net; module SSH; module Proxy
66
67
  raise ConnectError, "#{e}: #{command_line}"
67
68
  end
68
69
  @command_line = command_line
69
- class << io
70
- def send(data, flag)
70
+ if Gem.win_platform?
71
+ # read_nonblock and write_nonblock are not available on Windows
72
+ # pipe. Use sysread and syswrite as a replacement works.
73
+ def io.send(data, flag)
74
+ syswrite(data)
75
+ end
76
+
77
+ def io.recv(size)
78
+ sysread(size)
79
+ end
80
+ else
81
+ def io.send(data, flag)
71
82
  write_nonblock(data)
72
83
  end
73
84
 
74
- def recv(size)
85
+ def io.recv(size)
75
86
  read_nonblock(size)
76
87
  end
77
88
  end
@@ -9,11 +9,6 @@ class String
9
9
  self[index] = c
10
10
  end
11
11
  end
12
- if RUBY_VERSION < "1.8.7"
13
- def bytesize
14
- self.size
15
- end
16
- end
17
12
  end
18
13
 
19
14
  module Net; module SSH
@@ -224,10 +224,9 @@ module Net; module SSH; module Transport
224
224
  end
225
225
  lwarn { "unsupported #{algorithm} algorithm: `#{unsupported}'" } unless unsupported.empty?
226
226
 
227
- # make sure all of our supported algorithms are tacked onto the
228
- # end, so that if the user tries to give a list of which none are
229
- # supported, we can still proceed.
230
- list.each { |name| algorithms[algorithm] << name unless algorithms[algorithm].include?(name) }
227
+ if options[:append_all_supported_algorithms]
228
+ list.each { |name| algorithms[algorithm] << name unless algorithms[algorithm].include?(name) }
229
+ end
231
230
  end
232
231
  end
233
232
 
@@ -76,7 +76,6 @@ module Net; module SSH; module Transport
76
76
  cipher.padding = 0
77
77
 
78
78
  cipher.extend(Net::SSH::Transport::CTR) if (name =~ /-ctr(@openssh.org)?$/)
79
-
80
79
  cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options) if ossl_name != "rc4"
81
80
 
82
81
  key_len = KEY_LEN_OVERRIDE[name] || cipher.key_len
@@ -63,14 +63,15 @@ module Net; module SSH; module Transport
63
63
  @options = options
64
64
 
65
65
  debug { "establishing connection to #{@host}:#{@port}" }
66
- factory = options[:proxy] || TCPSocket
67
- @socket = timeout(options[:timeout] || 0) {
68
- case
69
- when options[:proxy] then factory.open(@host, @port, options)
70
- when @bind_address.nil? then factory.open(@host, @port)
71
- else factory.open(@host, @port, @bind_address)
66
+
67
+ @socket = timeout(options[:timeout] || 0) do
68
+ if (factory = options[:proxy])
69
+ factory.open(@host, @port, options)
70
+ else
71
+ TCPSocket.open(@host, @port, @bind_address)
72
72
  end
73
- }
73
+ end
74
+
74
75
  @socket.extend(PacketStream)
75
76
  @socket.logger = @logger
76
77
 
@@ -48,14 +48,14 @@ module Net; module SSH
48
48
  MAJOR = 2
49
49
 
50
50
  # The minor component of this version of the Net::SSH library
51
- MINOR = 9
51
+ MINOR = 10
52
52
 
53
53
  # The tiny component of this version of the Net::SSH library
54
- TINY = 4
54
+ TINY = 0
55
55
 
56
- # The prerelease component of this version of the Net::SSH library
56
+ # The prerelease component of this version of the Net::SSH library
57
57
  # nil allowed
58
- PRE = nil
58
+ PRE = 'beta1'
59
59
 
60
60
  # The current version of the Net::SSH library as a Version instance
61
61
  CURRENT = new(*[MAJOR, MINOR, TINY, PRE].compact)
@@ -1,20 +1,20 @@
1
1
  -----BEGIN CERTIFICATE-----
2
2
  MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAduZXQt
3
3
  c3NoMRkwFwYKCZImiZPyLGQBGRYJc29sdXRpb3VzMRMwEQYKCZImiZPyLGQBGRYD
4
- Y29tMB4XDTE1MTIwNjIxMDYyNFoXDTE2MTIwNTIxMDYyNFowQjEQMA4GA1UEAwwH
4
+ Y29tMB4XDTE0MTIwMjE3MzkyMFoXDTE1MTIwMjE3MzkyMFowQjEQMA4GA1UEAwwH
5
5
  bmV0LXNzaDEZMBcGCgmSJomT8ixkARkWCXNvbHV0aW91czETMBEGCgmSJomT8ixk
6
- ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMYnhNtn0f6p
7
- nTylB8mE8lMdoMLJC8KwpMWsvk73Pe2WVDsH/OSwwwz6oUGk1i70cJyDjIEBNpwT
8
- 88GpVXJSumvqVsf9fCg3mWNeb5t0J+aeNm9MIvYVMTqj5tydoXQiwnILRDYHV9tZ
9
- 1c3o59/VlahSTpZ7YEgzVufpAkvEGkbJiG849exiipK7MN/ZIkMOxYVnyRXk43Xc
10
- 6GYlsHOfSgPwcXwW5g57DCwLQLWrjDsTka28dxDmO7B5Lv5EqzINxVxWsu43OgZG
11
- 21Io/jIyf5PNpeKPKNGDuAQJ8mvdMYBJoDhtCwgsUYbl0BZzA7g4ytl51HtIeP+j
12
- Qp/eAvs/RrECAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUBfKiwO2eM4NE
13
- iRrVG793qEPLYyMwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQCfZFdb
14
- p4jzkfIzGDbiOxd0R8sdqJoC4nMLEgnQ7dLulawwA3IXe3sHAKgA5kmH3prsKc5H
15
- zVmM5NlH2P1nRbegIkQTYiIod1hZQCNxdmVG/fprMqPq0ybpUOjjrP5pj0OtszE1
16
- F2dQia1hOEstMR+n0nAtWII9HJAEyeZjVV0s2Cl7Pt85XJ3hxFcCKwzqsK5xRI7a
17
- B3vwh3/JJYrFonIohQ//Lg9qTZASEkoKLlq1/hFeICoCGGIGLq45ZB7CzXLooCKi
18
- s/ZUKye79ELwFYKJOhjW5g725OL3hy+llhEleytwKRwgXFQBPTC4f5UkdxZVVWGH
19
- e2C9M1m/2odPZo8h
6
+ ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0qnw4JV5JN
7
+ MWelqu7pnW2z6GZJ7+zLFYJQNETJyF0U5zo7aCRK08OeUxnpu/TCCXK8iQVkNLfz
8
+ 9pVIhF+X8pMEIruAkYGwBt1aWfuSNeyodyMk0vpZdxBHbOTJ4qBRUc6qOtNOeOzv
9
+ 8ObYUX52P/EMMaeXTRU+e7MGkB9pb6FvPPNx5akxwIaoRvtcMsc/hJnQuP5r96w6
10
+ t06MgKbXhWAX6gev0RVlrQqzxXst6iuvsrgZGjFqzob5wbTiX9M0+bFAB0EI7tJC
11
+ sv5keEbtNRaU7p3ZbMm4wTHHJLOtD+BpUCSzwv4ToNj9mZtJBMYw2Eeo7z1DklEG
12
+ mr95zbe+zNMCAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1bTfpzmitXwv
13
+ LmTXi0IO5vd8NGYwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQA0Aps8
14
+ UPINGa8XUUtrZtzrgX0/iyXNkKY1ld85g1N3WKEAVLfQI7TlGr0Qv2Ekx6RqlxbR
15
+ Vyq08pytSnghW2otR3bIGMGQzqxAeRLb25cjEwH7YIJ32n7ZC1fpMnBZOBDmueWA
16
+ B9EonmoO3ne7AJSgIvBbZzBPhzM4HrQGRW8LsPFsuj+dcJI43HOQwkmv2TRz0+t6
17
+ mGZldmqLcK0abv4JepLfB9XTue3kuyA29NGBibqyvRwlKckLpvKfHZX6Jxad8xxm
18
+ MbvRpzgROzyfw1qYi4dnIyMwTtXFFcZ0a2jpxHPkcTYFK6TzvFgDLAP0Y/u9jqUQ
19
+ eZ7/3CdSi/isZHEw
20
20
  -----END CERTIFICATE-----
@@ -2,17 +2,17 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: net-ssh 2.9.4 ruby lib
5
+ # stub: net-ssh 2.10.0.beta1 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "net-ssh"
9
- s.version = "2.9.4"
9
+ s.version = "2.10.0.beta1"
10
10
 
11
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Jamis Buck", "Delano Mandelbaum", "Mikl\u{f3}s Fazekas"]
14
14
  s.cert_chain = ["net-ssh-public_cert.pem"]
15
- s.date = "2016-01-30"
15
+ s.date = "2015-05-21"
16
16
  s.description = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol. It allows you to write programs that invoke and interact with processes on remote servers, via SSH2."
17
17
  s.email = "net-ssh@solutious.com"
18
18
  s.extra_rdoc_files = [
@@ -26,7 +26,6 @@ Gem::Specification.new do |s|
26
26
  "Manifest",
27
27
  "README.rdoc",
28
28
  "Rakefile",
29
- "Rudyfile",
30
29
  "THANKS.txt",
31
30
  "lib/net/ssh.rb",
32
31
  "lib/net/ssh/authentication/agent.rb",
@@ -140,6 +139,11 @@ Gem::Specification.new do |s|
140
139
  "test/configs/wild_cards",
141
140
  "test/connection/test_channel.rb",
142
141
  "test/connection/test_session.rb",
142
+ "test/integration/README.txt",
143
+ "test/integration/Vagrantfile",
144
+ "test/integration/common.rb",
145
+ "test/integration/playbook.yml",
146
+ "test/integration/test_id_rsa_keys.rb",
143
147
  "test/known_hosts/github",
144
148
  "test/manual/test_forward.rb",
145
149
  "test/manual/test_pageant.rb",
data/setup.rb CHANGED
@@ -1460,7 +1460,7 @@ class Installer
1460
1460
  begin
1461
1461
  require 'test/unit'
1462
1462
  rescue LoadError
1463
- setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
1463
+ setup_rb_error 'test/unit cannot loaded. You need Ruby 1.9 or later to invoke this task.'
1464
1464
  end
1465
1465
  runner = Test::Unit::AutoRunner.new(true)
1466
1466
  runner.to_run << TESTDIR
@@ -1,28 +1,21 @@
1
- 2011-01-19
2
-
3
1
  RUNNING TESTS
4
2
 
5
3
  Run the test suite from the net-ssh directory with the following command:
6
4
 
7
- ruby -Ilib -Itest -rrubygems test/test_all.rb
5
+ ruby -Ilib -Itest test/test_all.rb
8
6
 
9
7
  Run a single test file like this:
10
8
 
11
- ruby -Ilib -Itest -rrubygems test/transport/test_server_version.rb
12
-
9
+ ruby -Ilib -Itest test/transport/test_server_version.rb
13
10
 
14
11
  EXPECTED RESULTS
15
12
 
16
- * Ruby 1.9: all tests pass
17
-
18
- * Ruby 1.8: all tests pass (up until version 2.5)
19
-
20
- * JRuby 1.7: 98% test pass (510 tests, 1914 assertions, 2 failures, 9 errors)
21
-
22
- * JRuby 1.6: 98% test pass (510 tests, 1914 assertions, 4 failures, 5 errors)
13
+ https://travis-ci.org/net-ssh/net-ssh/
23
14
 
24
- * JRuby 1.5: 98% tests pass (510 tests, 1914 assertions, 5 failures, 5 errors)
15
+ INTEGRATION TESTS
25
16
 
17
+ brew install ansible ; ansible-galaxy install rvm_io.rvm1-ruby ; vagrant up ; vagrant ssh
18
+ cd /net-ssh ; rake integration-test
26
19
 
27
20
  PORT FORWARDING TESTS
28
21
 
@@ -71,6 +71,27 @@ module Authentication; module Methods
71
71
  assert subject.authenticate("ssh-connection", "jamis", "the-password")
72
72
  end
73
73
 
74
+ def test_authenticate_should_not_prompt_for_input_when_in_non_interactive_mode
75
+
76
+ def transport.options
77
+ {non_interactive: true}
78
+ end
79
+ transport.expect do |t,packet|
80
+ assert_equal USERAUTH_REQUEST, packet.type
81
+ t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 2, :string, "Name:", :bool, true, :string, "Password:", :bool, false)
82
+ t.expect do |t2,packet2|
83
+ assert_equal USERAUTH_INFO_RESPONSE, packet2.type
84
+ assert_equal 2, packet2.read_long
85
+ assert_equal "", packet2.read_string
86
+ assert_equal "", packet2.read_string
87
+ t2.return(USERAUTH_SUCCESS)
88
+ end
89
+ end
90
+
91
+ assert subject.authenticate("ssh-connection", "jamis", nil)
92
+ end
93
+
94
+
74
95
  def test_authenticate_should_prompt_for_input_when_password_is_not_given
75
96
  subject.expects(:prompt).with("Name:", true).returns("name")
76
97
  subject.expects(:prompt).with("Password:", false).returns("password")
@@ -156,7 +156,9 @@ module Authentication
156
156
 
157
157
  def stub_file_private_key(name, key, options = {})
158
158
  manager.add(name)
159
+ File.stubs(:file?).with(name).returns(true)
159
160
  File.stubs(:readable?).with(name).returns(true)
161
+ File.stubs(:file?).with(name + ".pub").returns(true)
160
162
  File.stubs(:readable?).with(name + ".pub").returns(false)
161
163
 
162
164
  case options.fetch(:passphrase, :indifferently)
@@ -179,7 +181,9 @@ module Authentication
179
181
 
180
182
  def stub_file_public_key(name, key)
181
183
  manager.add(name)
182
- File.stubs(:readable?).with(name).returns(false)
184
+ File.stubs(:file?).with(name).returns(true)
185
+ File.stubs(:readable?).with(name).returns(true)
186
+ File.stubs(:file?).with(name + ".pub").returns(true)
183
187
  File.stubs(:readable?).with(name + ".pub").returns(true)
184
188
 
185
189
  Net::SSH::KeyFactory.expects(:load_public_key).with(name + ".pub").returns(key).at_least_once
@@ -74,11 +74,8 @@ module Connection
74
74
  assert !channel.closing?
75
75
 
76
76
  connection.expect { |t,packet| assert_equal CHANNEL_CLOSE, packet.type }
77
- connection.expects(:cleanup_channel).with(channel)
78
77
  channel.close
79
78
 
80
- channel.process
81
-
82
79
  assert channel.closing?
83
80
  end
84
81
 
@@ -117,14 +117,14 @@ module Connection
117
117
  end
118
118
 
119
119
  def test_process_should_exit_after_processing_if_block_is_true_then_false
120
- session.channels[0] = stub("channel", :local_closed? => false)
120
+ session.channels[0] = stub("channel", :closing? => false)
121
121
  session.channels[0].expects(:process)
122
122
  IO.expects(:select).never
123
123
  process_times(2)
124
124
  end
125
125
 
126
126
  def test_process_should_not_process_channels_that_are_closing
127
- session.channels[0] = stub("channel", :local_closed? => true)
127
+ session.channels[0] = stub("channel", :closing? => true)
128
128
  session.channels[0].expects(:process).never
129
129
  IO.expects(:select).never
130
130
  process_times(2)
@@ -299,17 +299,8 @@ module Connection
299
299
  end
300
300
 
301
301
  def test_channel_close_packet_should_be_routed_to_corresponding_channel_and_channel_should_be_closed_and_removed
302
- session.channels[14] = stub("channel") do
303
- # this simulates the case where we closed the channel first, sent
304
- # CHANNEL_CLOSE to server and are waiting for server's response.
305
- expects(:local_closed?).returns(true)
306
- expects(:do_close)
307
- expects(:close).with()
308
- expects(:remote_closed!).with()
309
- expects(:remote_closed?).with().returns(true)
310
- expects(:local_id).returns(14)
311
- end
312
-
302
+ channel_at(14).expects(:do_close).with()
303
+ session.channels[14].expects(:close).with()
313
304
  transport.return(CHANNEL_CLOSE, :long, 14)
314
305
  process_times(2)
315
306
  assert session.channels.empty?
@@ -386,13 +377,13 @@ module Connection
386
377
  options = { :keepalive => true, :keepalive_interval => 300, :keepalive_maxcount => 3 }
387
378
  expected_packet = P(:byte, Net::SSH::Packet::GLOBAL_REQUEST, :string, "keepalive@openssh.com", :bool, true)
388
379
  [1,2,3].each do |i|
389
- Time.stubs(:now).returns(i*300)
380
+ Time.stubs(:now).returns(Time.at(i*300))
390
381
  IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
391
- transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
382
+ transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
392
383
  session(options).process
393
384
  end
394
385
 
395
- Time.stubs(:now).returns(4*300)
386
+ Time.stubs(:now).returns(Time.at(4*300))
396
387
  IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
397
388
  transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
398
389
  assert_raises(Net::SSH::Timeout) { session(options).process }
@@ -532,7 +523,7 @@ module Connection
532
523
  end
533
524
 
534
525
  def channel_at(local_id)
535
- session.channels[local_id] = stub("channel", :process => true, :local_closed? => false)
526
+ session.channels[local_id] = stub("channel", :process => true, :closing? => false)
536
527
  end
537
528
 
538
529
  def transport(options={})
@@ -0,0 +1,19 @@
1
+ # Integration tests with vagrant
2
+
3
+ Requirements:
4
+
5
+ * Vagrant (https://www.vagrantup.com/)
6
+ * Ansible (http://docs.ansible.com/intro_installation.html)
7
+
8
+ Setup:
9
+
10
+ ansible-galaxy install rvm_io.rvm1-ruby
11
+ vagrant up
12
+ vagrant ssh
13
+ cd /net-ssh
14
+ rake integration-test
15
+
16
+ # TODO
17
+
18
+ * get it running on ci (probalby needs docker)
19
+ * could not get gem install jeweler to work
@@ -0,0 +1,12 @@
1
+ VAGRANTFILE_API_VERSION = "2"
2
+
3
+ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
4
+ config.vm.box = "ubuntu/trusty64"
5
+ config.vm.provision "ansible" do |ansible|
6
+ ansible.playbook = "./playbook.yml"
7
+ ansible.sudo = true
8
+ ansible.verbose ='vvvv'
9
+ end
10
+
11
+ config.vm.synced_folder "../..", "/net-ssh"
12
+ end
@@ -0,0 +1,57 @@
1
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
2
+ gem "test-unit" # http://rubyforge.org/pipermail/test-unit-tracker/2009-July/000075.html
3
+ gem 'mocha'
4
+ require 'test/unit'
5
+ require 'mocha/setup'
6
+ require 'pty'
7
+ require 'expect'
8
+
9
+ module IntegrationTestHelpers
10
+ def sh command
11
+ puts "$ #{command}"
12
+ res = system(command)
13
+ status = $?
14
+ raise "Command: #{command} failed:#{status.exitstatus}" unless res
15
+ end
16
+
17
+ def set_authorized_key(user,pubkey)
18
+ authorized_key = "/home/#{user}/.ssh/authorized_keys"
19
+ sh "sudo cp #{pubkey} #{authorized_key}"
20
+ sh "sudo chown #{user} #{authorized_key}"
21
+ sh "sudo chmod 0744 #{authorized_key}"
22
+ end
23
+
24
+ def with_agent(&block)
25
+ puts "/usr/bin/ssh-agent -c"
26
+ agent_out = `/usr/bin/ssh-agent -c`
27
+ agent_out.split("\n").each do |line|
28
+ if line =~ /setenv (\S+) (\S+);/
29
+ ENV[$1] = $2
30
+ puts "ENV[#{$1}]=#{$2}"
31
+ end
32
+ end
33
+ begin
34
+ yield
35
+ ensure
36
+ sh "/usr/bin/ssh-agent -k"
37
+ end
38
+ end
39
+
40
+ def ssh_add(key,password)
41
+ command = "ssh-add #{key}"
42
+ status = nil
43
+ PTY.spawn(command) do |reader, writer, pid|
44
+ begin
45
+ reader.expect(/Enter passphrase for .*:/) { |data| puts data }
46
+ writer.puts(password)
47
+ until reader.eof? do
48
+ puts reader.readline
49
+ end
50
+ rescue Errno::EIO => e
51
+ end
52
+ pid, status = Process.wait2 pid
53
+ end
54
+ raise "Command: #{command} failed:#{status.exitstatus}" unless status
55
+ status.exitstatus
56
+ end
57
+ end