net-ssh 2.9.4 → 2.10.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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