net-ssh 3.2.0 → 7.2.0.rc1

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 (210) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/FUNDING.yml +1 -0
  5. data/.github/config/rubocop_linter_action.yml +4 -0
  6. data/.github/workflows/ci-with-docker.yml +44 -0
  7. data/.github/workflows/ci.yml +93 -0
  8. data/.github/workflows/rubocop.yml +16 -0
  9. data/.gitignore +13 -0
  10. data/.rubocop.yml +22 -0
  11. data/.rubocop_todo.yml +1081 -0
  12. data/CHANGES.txt +237 -7
  13. data/DEVELOPMENT.md +23 -0
  14. data/Dockerfile +27 -0
  15. data/Dockerfile.openssl3 +17 -0
  16. data/Gemfile +13 -0
  17. data/Gemfile.noed25519 +12 -0
  18. data/Gemfile.norbnacl +12 -0
  19. data/ISSUE_TEMPLATE.md +30 -0
  20. data/Manifest +4 -5
  21. data/README.md +298 -0
  22. data/Rakefile +125 -74
  23. data/SECURITY.md +4 -0
  24. data/appveyor.yml +58 -0
  25. data/docker-compose.yml +23 -0
  26. data/lib/net/ssh/authentication/agent.rb +279 -18
  27. data/lib/net/ssh/authentication/certificate.rb +183 -0
  28. data/lib/net/ssh/authentication/constants.rb +17 -15
  29. data/lib/net/ssh/authentication/ed25519.rb +186 -0
  30. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  31. data/lib/net/ssh/authentication/key_manager.rb +86 -39
  32. data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
  33. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  34. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +13 -13
  35. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  36. data/lib/net/ssh/authentication/methods/password.rb +27 -17
  37. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  38. data/lib/net/ssh/authentication/pageant.rb +471 -367
  39. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  40. data/lib/net/ssh/authentication/session.rb +131 -121
  41. data/lib/net/ssh/buffer.rb +399 -300
  42. data/lib/net/ssh/buffered_io.rb +154 -150
  43. data/lib/net/ssh/config.rb +308 -185
  44. data/lib/net/ssh/connection/channel.rb +635 -613
  45. data/lib/net/ssh/connection/constants.rb +29 -29
  46. data/lib/net/ssh/connection/event_loop.rb +123 -0
  47. data/lib/net/ssh/connection/keepalive.rb +55 -51
  48. data/lib/net/ssh/connection/session.rb +620 -551
  49. data/lib/net/ssh/connection/term.rb +125 -123
  50. data/lib/net/ssh/errors.rb +101 -99
  51. data/lib/net/ssh/key_factory.rb +197 -105
  52. data/lib/net/ssh/known_hosts.rb +214 -127
  53. data/lib/net/ssh/loggable.rb +50 -49
  54. data/lib/net/ssh/packet.rb +83 -79
  55. data/lib/net/ssh/prompt.rb +50 -81
  56. data/lib/net/ssh/proxy/command.rb +105 -90
  57. data/lib/net/ssh/proxy/errors.rb +12 -10
  58. data/lib/net/ssh/proxy/http.rb +82 -79
  59. data/lib/net/ssh/proxy/https.rb +50 -0
  60. data/lib/net/ssh/proxy/jump.rb +54 -0
  61. data/lib/net/ssh/proxy/socks4.rb +2 -6
  62. data/lib/net/ssh/proxy/socks5.rb +14 -17
  63. data/lib/net/ssh/service/forward.rb +370 -317
  64. data/lib/net/ssh/test/channel.rb +145 -136
  65. data/lib/net/ssh/test/extensions.rb +131 -110
  66. data/lib/net/ssh/test/kex.rb +34 -32
  67. data/lib/net/ssh/test/local_packet.rb +46 -44
  68. data/lib/net/ssh/test/packet.rb +89 -70
  69. data/lib/net/ssh/test/remote_packet.rb +32 -30
  70. data/lib/net/ssh/test/script.rb +156 -142
  71. data/lib/net/ssh/test/socket.rb +49 -48
  72. data/lib/net/ssh/test.rb +82 -77
  73. data/lib/net/ssh/transport/algorithms.rb +462 -359
  74. data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  75. data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  76. data/lib/net/ssh/transport/cipher_factory.rb +122 -99
  77. data/lib/net/ssh/transport/constants.rb +32 -24
  78. data/lib/net/ssh/transport/ctr.rb +42 -22
  79. data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
  80. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  81. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  82. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  83. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  84. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  85. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  86. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  87. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  88. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  89. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  90. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  91. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  92. data/lib/net/ssh/transport/hmac.rb +14 -12
  93. data/lib/net/ssh/transport/identity_cipher.rb +54 -44
  94. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  95. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  96. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  97. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  98. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  99. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  100. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
  101. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
  102. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  103. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  104. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  105. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  106. data/lib/net/ssh/transport/kex.rb +15 -12
  107. data/lib/net/ssh/transport/key_expander.rb +24 -20
  108. data/lib/net/ssh/transport/openssl.rb +161 -124
  109. data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  110. data/lib/net/ssh/transport/packet_stream.rb +246 -185
  111. data/lib/net/ssh/transport/server_version.rb +55 -56
  112. data/lib/net/ssh/transport/session.rb +306 -255
  113. data/lib/net/ssh/transport/state.rb +178 -176
  114. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  115. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  116. data/lib/net/ssh/verifiers/always.rb +58 -0
  117. data/lib/net/ssh/verifiers/never.rb +19 -0
  118. data/lib/net/ssh/version.rb +55 -53
  119. data/lib/net/ssh.rb +111 -47
  120. data/net-ssh-public_cert.pem +18 -18
  121. data/net-ssh.gemspec +38 -205
  122. data/support/ssh_tunnel_bug.rb +5 -5
  123. data.tar.gz.sig +0 -0
  124. metadata +173 -118
  125. metadata.gz.sig +0 -0
  126. data/.travis.yml +0 -18
  127. data/README.rdoc +0 -182
  128. data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
  129. data/lib/net/ssh/authentication/agent/socket.rb +0 -178
  130. data/lib/net/ssh/ruby_compat.rb +0 -46
  131. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  132. data/lib/net/ssh/verifiers/null.rb +0 -12
  133. data/lib/net/ssh/verifiers/secure.rb +0 -52
  134. data/lib/net/ssh/verifiers/strict.rb +0 -24
  135. data/setup.rb +0 -1585
  136. data/support/arcfour_check.rb +0 -20
  137. data/test/README.txt +0 -18
  138. data/test/authentication/methods/common.rb +0 -28
  139. data/test/authentication/methods/test_abstract.rb +0 -51
  140. data/test/authentication/methods/test_hostbased.rb +0 -114
  141. data/test/authentication/methods/test_keyboard_interactive.rb +0 -121
  142. data/test/authentication/methods/test_none.rb +0 -41
  143. data/test/authentication/methods/test_password.rb +0 -95
  144. data/test/authentication/methods/test_publickey.rb +0 -148
  145. data/test/authentication/test_agent.rb +0 -232
  146. data/test/authentication/test_key_manager.rb +0 -240
  147. data/test/authentication/test_session.rb +0 -107
  148. data/test/common.rb +0 -125
  149. data/test/configs/auth_off +0 -5
  150. data/test/configs/auth_on +0 -4
  151. data/test/configs/empty +0 -0
  152. data/test/configs/eqsign +0 -3
  153. data/test/configs/exact_match +0 -8
  154. data/test/configs/host_plus +0 -10
  155. data/test/configs/multihost +0 -4
  156. data/test/configs/negative_match +0 -6
  157. data/test/configs/nohost +0 -19
  158. data/test/configs/numeric_host +0 -4
  159. data/test/configs/proxy_remote_user +0 -2
  160. data/test/configs/send_env +0 -2
  161. data/test/configs/substitutes +0 -8
  162. data/test/configs/wild_cards +0 -14
  163. data/test/connection/test_channel.rb +0 -487
  164. data/test/connection/test_session.rb +0 -564
  165. data/test/integration/README.txt +0 -17
  166. data/test/integration/Vagrantfile +0 -12
  167. data/test/integration/common.rb +0 -63
  168. data/test/integration/playbook.yml +0 -56
  169. data/test/integration/test_forward.rb +0 -637
  170. data/test/integration/test_id_rsa_keys.rb +0 -96
  171. data/test/integration/test_proxy.rb +0 -93
  172. data/test/known_hosts/github +0 -1
  173. data/test/known_hosts/github_hash +0 -1
  174. data/test/manual/test_pageant.rb +0 -37
  175. data/test/start/test_connection.rb +0 -53
  176. data/test/start/test_options.rb +0 -57
  177. data/test/start/test_transport.rb +0 -28
  178. data/test/start/test_user_nil.rb +0 -27
  179. data/test/test_all.rb +0 -12
  180. data/test/test_buffer.rb +0 -433
  181. data/test/test_buffered_io.rb +0 -63
  182. data/test/test_config.rb +0 -268
  183. data/test/test_key_factory.rb +0 -191
  184. data/test/test_known_hosts.rb +0 -66
  185. data/test/transport/hmac/test_md5.rb +0 -41
  186. data/test/transport/hmac/test_md5_96.rb +0 -27
  187. data/test/transport/hmac/test_none.rb +0 -34
  188. data/test/transport/hmac/test_ripemd160.rb +0 -36
  189. data/test/transport/hmac/test_sha1.rb +0 -36
  190. data/test/transport/hmac/test_sha1_96.rb +0 -27
  191. data/test/transport/hmac/test_sha2_256.rb +0 -37
  192. data/test/transport/hmac/test_sha2_256_96.rb +0 -27
  193. data/test/transport/hmac/test_sha2_512.rb +0 -37
  194. data/test/transport/hmac/test_sha2_512_96.rb +0 -27
  195. data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
  196. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -150
  197. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -96
  198. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -19
  199. data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
  200. data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
  201. data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
  202. data/test/transport/test_algorithms.rb +0 -328
  203. data/test/transport/test_cipher_factory.rb +0 -443
  204. data/test/transport/test_hmac.rb +0 -34
  205. data/test/transport/test_identity_cipher.rb +0 -40
  206. data/test/transport/test_packet_stream.rb +0 -1762
  207. data/test/transport/test_server_version.rb +0 -74
  208. data/test/transport/test_session.rb +0 -331
  209. data/test/transport/test_state.rb +0 -181
  210. data/test/verifiers/test_secure.rb +0 -40
@@ -2,165 +2,179 @@ require 'net/ssh/test/channel'
2
2
  require 'net/ssh/test/local_packet'
3
3
  require 'net/ssh/test/remote_packet'
4
4
 
5
- module Net; module SSH; module Test
6
-
7
- # Represents a sequence of scripted events that identify the behavior that
8
- # a test expects. Methods named "sends_*" create events for packets being
9
- # sent from the local to the remote host, and methods named "gets_*" create
10
- # events for packets being received by the local from the remote host.
11
- #
12
- # A reference to a script. is generally obtained in a unit test via the
13
- # Net::SSH::Test#story helper method:
14
- #
15
- # story do |script|
16
- # channel = script.opens_channel
17
- # ...
18
- # end
19
- class Script
20
- # The list of scripted events. These will be Net::SSH::Test::LocalPacket
21
- # and Net::SSH::Test::RemotePacket instances.
22
- attr_reader :events
23
-
24
- # Create a new, empty script.
25
- def initialize
26
- @events = []
27
- end
5
+ module Net
6
+ module SSH
7
+ module Test
8
+ # Represents a sequence of scripted events that identify the behavior that
9
+ # a test expects. Methods named "sends_*" create events for packets being
10
+ # sent from the local to the remote host, and methods named "gets_*" create
11
+ # events for packets being received by the local from the remote host.
12
+ #
13
+ # A reference to a script. is generally obtained in a unit test via the
14
+ # Net::SSH::Test#story helper method:
15
+ #
16
+ # story do |script|
17
+ # channel = script.opens_channel
18
+ # ...
19
+ # end
20
+ class Script
21
+ # The list of scripted events. These will be Net::SSH::Test::LocalPacket
22
+ # and Net::SSH::Test::RemotePacket instances.
23
+ attr_reader :events
24
+
25
+ # Create a new, empty script.
26
+ def initialize
27
+ @events = []
28
+ end
28
29
 
29
- # Scripts the opening of a channel by adding a local packet sending the
30
- # channel open request, and if +confirm+ is true (the default), also
31
- # adding a remote packet confirming the new channel.
32
- #
33
- # A new Net::SSH::Test::Channel instance is returned, which can be used
34
- # to script additional channel operations.
35
- def opens_channel(confirm=true)
36
- channel = Channel.new(self)
37
- channel.remote_id = 5555
30
+ # Scripts the opening of a channel by adding a local packet sending the
31
+ # channel open request, and if +confirm+ is true (the default), also
32
+ # adding a remote packet confirming the new channel.
33
+ #
34
+ # A new Net::SSH::Test::Channel instance is returned, which can be used
35
+ # to script additional channel operations.
36
+ def opens_channel(confirm = true)
37
+ channel = Channel.new(self)
38
+ channel.remote_id = 5555
38
39
 
39
- events << LocalPacket.new(:channel_open) { |p| channel.local_id = p[:remote_id] }
40
+ events << LocalPacket.new(:channel_open) { |p| channel.local_id = p[:remote_id] }
40
41
 
41
- if confirm
42
- events << RemotePacket.new(:channel_open_confirmation, channel.local_id, channel.remote_id, 0x20000, 0x10000)
43
- end
42
+ events << RemotePacket.new(:channel_open_confirmation, channel.local_id, channel.remote_id, 0x20000, 0x10000) if confirm
44
43
 
45
- channel
46
- end
44
+ channel
45
+ end
47
46
 
48
- # A convenience method for adding an arbitrary local packet to the events
49
- # list.
50
- def sends(type, *args, &block)
51
- events << LocalPacket.new(type, *args, &block)
52
- end
47
+ # A convenience method for adding an arbitrary local packet to the events
48
+ # list.
49
+ def sends(type, *args, &block)
50
+ events << LocalPacket.new(type, *args, &block)
51
+ end
53
52
 
54
- # A convenience method for adding an arbitrary remote packet to the events
55
- # list.
56
- def gets(type, *args)
57
- events << RemotePacket.new(type, *args)
58
- end
53
+ # A convenience method for adding an arbitrary remote packet to the events
54
+ # list.
55
+ def gets(type, *args)
56
+ events << RemotePacket.new(type, *args)
57
+ end
59
58
 
60
- # Scripts the sending of a new channel request packet to the remote host.
61
- # +channel+ should be an instance of Net::SSH::Test::Channel. +request+
62
- # is a string naming the request type to send, +reply+ is a boolean
63
- # indicating whether a response to this packet is required , and +data+
64
- # is any additional request-specific data that this packet should send.
65
- # +success+ indicates whether the response (if one is required) should be
66
- # success or failure.
67
- #
68
- # If a reply is desired, a remote packet will also be queued, :channel_success
69
- # if +success+ is true, or :channel_failure if +success+ is false.
70
- #
71
- # This will typically be called via Net::SSH::Test::Channel#sends_exec or
72
- # Net::SSH::Test::Channel#sends_subsystem.
73
- def sends_channel_request(channel, request, reply, data, success=true)
74
- events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, data)
75
- if reply
76
- if success
77
- events << RemotePacket.new(:channel_success, channel.local_id)
78
- else
79
- events << RemotePacket.new(:channel_failure, channel.local_id)
59
+ # Scripts the sending of a new channel request packet to the remote host.
60
+ # +channel+ should be an instance of Net::SSH::Test::Channel. +request+
61
+ # is a string naming the request type to send, +reply+ is a boolean
62
+ # indicating whether a response to this packet is required , and +data+
63
+ # is any additional request-specific data that this packet should send.
64
+ # +success+ indicates whether the response (if one is required) should be
65
+ # success or failure. If +data+ is an array it will be treated as multiple
66
+ # data.
67
+ #
68
+ # If a reply is desired, a remote packet will also be queued, :channel_success
69
+ # if +success+ is true, or :channel_failure if +success+ is false.
70
+ #
71
+ # This will typically be called via Net::SSH::Test::Channel#sends_exec or
72
+ # Net::SSH::Test::Channel#sends_subsystem.
73
+ def sends_channel_request(channel, request, reply, data, success = true)
74
+ if data.is_a? Array
75
+ events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, *data)
76
+ else
77
+ events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, data)
78
+ end
79
+ if reply
80
+ if success
81
+ events << RemotePacket.new(:channel_success, channel.local_id)
82
+ else
83
+ events << RemotePacket.new(:channel_failure, channel.local_id)
84
+ end
85
+ end
80
86
  end
81
- end
82
- end
83
87
 
84
- # Scripts the sending of a channel data packet. +channel+ must be a
85
- # Net::SSH::Test::Channel object, and +data+ is the (string) data to
86
- # expect will be sent.
87
- #
88
- # This will typically be called via Net::SSH::Test::Channel#sends_data.
89
- def sends_channel_data(channel, data)
90
- events << LocalPacket.new(:channel_data, channel.remote_id, data)
91
- end
88
+ # Scripts the sending of a channel data packet. +channel+ must be a
89
+ # Net::SSH::Test::Channel object, and +data+ is the (string) data to
90
+ # expect will be sent.
91
+ #
92
+ # This will typically be called via Net::SSH::Test::Channel#sends_data.
93
+ def sends_channel_data(channel, data)
94
+ events << LocalPacket.new(:channel_data, channel.remote_id, data)
95
+ end
92
96
 
93
- # Scripts the sending of a channel EOF packet from the given
94
- # Net::SSH::Test::Channel +channel+. This will typically be called via
95
- # Net::SSH::Test::Channel#sends_eof.
96
- def sends_channel_eof(channel)
97
- events << LocalPacket.new(:channel_eof, channel.remote_id)
98
- end
97
+ # Scripts the sending of a channel EOF packet from the given
98
+ # Net::SSH::Test::Channel +channel+. This will typically be called via
99
+ # Net::SSH::Test::Channel#sends_eof.
100
+ def sends_channel_eof(channel)
101
+ events << LocalPacket.new(:channel_eof, channel.remote_id)
102
+ end
99
103
 
100
- # Scripts the sending of a channel close packet from the given
101
- # Net::SSH::Test::Channel +channel+. This will typically be called via
102
- # Net::SSH::Test::Channel#sends_close.
103
- def sends_channel_close(channel)
104
- events << LocalPacket.new(:channel_close, channel.remote_id)
105
- end
104
+ # Scripts the sending of a channel close packet from the given
105
+ # Net::SSH::Test::Channel +channel+. This will typically be called via
106
+ # Net::SSH::Test::Channel#sends_close.
107
+ def sends_channel_close(channel)
108
+ events << LocalPacket.new(:channel_close, channel.remote_id)
109
+ end
106
110
 
107
- # Scripts the reception of a channel data packet from the remote host by
108
- # the given Net::SSH::Test::Channel +channel+. This will typically be
109
- # called via Net::SSH::Test::Channel#gets_data.
110
- def gets_channel_data(channel, data)
111
- events << RemotePacket.new(:channel_data, channel.local_id, data)
112
- end
111
+ # Scripts the sending of a channel request pty packets from the given
112
+ # Net::SSH::Test::Channel +channel+. This will typically be called via
113
+ # Net::SSH::Test::Channel#sends_request_pty.
114
+ def sends_channel_request_pty(channel)
115
+ data = ['pty-req', false]
116
+ data += Net::SSH::Connection::Channel::VALID_PTY_OPTIONS.merge(modes: "\0").values
117
+ events << LocalPacket.new(:channel_request, channel.remote_id, *data)
118
+ end
113
119
 
114
- # Scripts the reception of a channel extended data packet from the remote
115
- # host by the given Net::SSH::Test::Channel +channel+. This will typically
116
- # be called via Net::SSH::Test::Channel#gets_extended_data.
117
- #
118
- # Currently the only extended data type is stderr == 1.
119
- def gets_channel_extended_data(channel, data)
120
- events << RemotePacket.new(:channel_extended_data, channel.local_id, 1, data)
121
- end
120
+ # Scripts the reception of a channel data packet from the remote host by
121
+ # the given Net::SSH::Test::Channel +channel+. This will typically be
122
+ # called via Net::SSH::Test::Channel#gets_data.
123
+ def gets_channel_data(channel, data)
124
+ events << RemotePacket.new(:channel_data, channel.local_id, data)
125
+ end
122
126
 
123
- # Scripts the reception of a channel request packet from the remote host by
124
- # the given Net::SSH::Test::Channel +channel+. This will typically be
125
- # called via Net::SSH::Test::Channel#gets_exit_status.
126
- def gets_channel_request(channel, request, reply, data)
127
- events << RemotePacket.new(:channel_request, channel.local_id, request, reply, data)
128
- end
127
+ # Scripts the reception of a channel extended data packet from the remote
128
+ # host by the given Net::SSH::Test::Channel +channel+. This will typically
129
+ # be called via Net::SSH::Test::Channel#gets_extended_data.
130
+ #
131
+ # Currently the only extended data type is stderr == 1.
132
+ def gets_channel_extended_data(channel, data)
133
+ events << RemotePacket.new(:channel_extended_data, channel.local_id, 1, data)
134
+ end
129
135
 
130
- # Scripts the reception of a channel EOF packet from the remote host by
131
- # the given Net::SSH::Test::Channel +channel+. This will typically be
132
- # called via Net::SSH::Test::Channel#gets_eof.
133
- def gets_channel_eof(channel)
134
- events << RemotePacket.new(:channel_eof, channel.local_id)
135
- end
136
+ # Scripts the reception of a channel request packet from the remote host by
137
+ # the given Net::SSH::Test::Channel +channel+. This will typically be
138
+ # called via Net::SSH::Test::Channel#gets_exit_status.
139
+ def gets_channel_request(channel, request, reply, data)
140
+ events << RemotePacket.new(:channel_request, channel.local_id, request, reply, data)
141
+ end
136
142
 
137
- # Scripts the reception of a channel close packet from the remote host by
138
- # the given Net::SSH::Test::Channel +channel+. This will typically be
139
- # called via Net::SSH::Test::Channel#gets_close.
140
- def gets_channel_close(channel)
141
- events << RemotePacket.new(:channel_close, channel.local_id)
142
- end
143
+ # Scripts the reception of a channel EOF packet from the remote host by
144
+ # the given Net::SSH::Test::Channel +channel+. This will typically be
145
+ # called via Net::SSH::Test::Channel#gets_eof.
146
+ def gets_channel_eof(channel)
147
+ events << RemotePacket.new(:channel_eof, channel.local_id)
148
+ end
143
149
 
144
- # By default, removes the next event in the list and returns it. However,
145
- # this can also be used to non-destructively peek at the next event in the
146
- # list, by passing :first as the argument.
147
- #
148
- # # remove the next event and return it
149
- # event = script.next
150
- #
151
- # # peek at the next event
152
- # event = script.next(:first)
153
- def next(mode=:shift)
154
- events.send(mode)
155
- end
150
+ # Scripts the reception of a channel close packet from the remote host by
151
+ # the given Net::SSH::Test::Channel +channel+. This will typically be
152
+ # called via Net::SSH::Test::Channel#gets_close.
153
+ def gets_channel_close(channel)
154
+ events << RemotePacket.new(:channel_close, channel.local_id)
155
+ end
156
+
157
+ # By default, removes the next event in the list and returns it. However,
158
+ # this can also be used to non-destructively peek at the next event in the
159
+ # list, by passing :first as the argument.
160
+ #
161
+ # # remove the next event and return it
162
+ # event = script.next
163
+ #
164
+ # # peek at the next event
165
+ # event = script.next(:first)
166
+ def next(mode = :shift)
167
+ events.send(mode)
168
+ end
156
169
 
157
- # Compare the given packet against the next event in the list. If there is
158
- # no next event, an exception will be raised. This is called by
159
- # Net::SSH::Test::Extensions::PacketStream#test_enqueue_packet.
160
- def process(packet)
161
- event = events.shift or raise "end of script reached, but got a packet type #{packet.read_byte}"
162
- event.process(packet)
170
+ # Compare the given packet against the next event in the list. If there is
171
+ # no next event, an exception will be raised. This is called by
172
+ # Net::SSH::Test::Extensions::PacketStream#test_enqueue_packet.
173
+ def process(packet)
174
+ event = events.shift or raise "end of script reached, but got a packet type #{packet.read_byte}"
175
+ event.process(packet)
176
+ end
177
+ end
163
178
  end
164
179
  end
165
-
166
- end; end; end
180
+ end
@@ -3,62 +3,63 @@ require 'stringio'
3
3
  require 'net/ssh/test/extensions'
4
4
  require 'net/ssh/test/script'
5
5
 
6
- module Net; module SSH; module Test
6
+ module Net
7
+ module SSH
8
+ module Test
9
+ # A mock socket implementation for use in testing. It implements the minimum
10
+ # necessary interface for interacting with the rest of the Net::SSH::Test
11
+ # system.
12
+ class Socket < StringIO
13
+ attr_reader :host, :port
7
14
 
8
- # A mock socket implementation for use in testing. It implements the minimum
9
- # necessary interface for interacting with the rest of the Net::SSH::Test
10
- # system.
11
- class Socket < StringIO
12
- attr_reader :host, :port
15
+ # The Net::SSH::Test::Script object in use by this socket. This is the
16
+ # canonical script instance that should be used for any test depending on
17
+ # this socket instance.
18
+ attr_reader :script
13
19
 
14
- # The Net::SSH::Test::Script object in use by this socket. This is the
15
- # canonical script instance that should be used for any test depending on
16
- # this socket instance.
17
- attr_reader :script
20
+ # Create a new test socket. This will also instantiate a new Net::SSH::Test::Script
21
+ # and seed it with the necessary events to power the initialization of the
22
+ # connection.
23
+ def initialize
24
+ extend(Net::SSH::Transport::PacketStream)
25
+ super "SSH-2.0-Test\r\n"
18
26
 
19
- # Create a new test socket. This will also instantiate a new Net::SSH::Test::Script
20
- # and seed it with the necessary events to power the initialization of the
21
- # connection.
22
- def initialize
23
- extend(Net::SSH::Transport::PacketStream)
24
- super "SSH-2.0-Test\r\n"
27
+ @script = Script.new
25
28
 
26
- @script = Script.new
29
+ script.sends(:kexinit)
30
+ script.gets(:kexinit, 1, 2, 3, 4, "test", "ssh-rsa", "none", "none", "none", "none", "none", "none", "", "", false)
31
+ script.sends(:newkeys)
32
+ script.gets(:newkeys)
33
+ end
27
34
 
28
- script.sends(:kexinit)
29
- script.gets(:kexinit, 1, 2, 3, 4, "test", "ssh-rsa", "none", "none", "none", "none", "none", "none", "", "", false)
30
- script.sends(:newkeys)
31
- script.gets(:newkeys)
32
- end
35
+ # This doesn't actually do anything, since we don't really care what gets
36
+ # written.
37
+ def write(data)
38
+ # black hole, because we don't actually care about what gets written
39
+ end
33
40
 
34
- # This doesn't actually do anything, since we don't really care what gets
35
- # written.
36
- def write(data)
37
- # black hole, because we don't actually care about what gets written
38
- end
41
+ # Allows the socket to also mimic a socket factory, simply returning
42
+ # +self+.
43
+ def open(host, port, options = {})
44
+ @host, @port = host, port
45
+ self
46
+ end
39
47
 
40
- # Allows the socket to also mimic a socket factory, simply returning
41
- # +self+.
42
- def open(host, port, options={})
43
- @host, @port = host, port
44
- self
45
- end
48
+ # Returns a sockaddr struct for the port and host that were used when the
49
+ # socket was instantiated.
50
+ def getpeername
51
+ ::Socket.sockaddr_in(port, host)
52
+ end
46
53
 
47
- # Returns a sockaddr struct for the port and host that were used when the
48
- # socket was instantiated.
49
- def getpeername
50
- ::Socket.sockaddr_in(port, host)
51
- end
54
+ # Alias to #read, but never returns nil (returns an empty string instead).
55
+ def recv(n)
56
+ read(n) || ""
57
+ end
52
58
 
53
- # Alias to #read, but never returns nil (returns an empty string instead).
54
- def recv(n)
55
- read(n) || ""
59
+ def readpartial(n)
60
+ recv(n)
61
+ end
62
+ end
56
63
  end
57
-
58
- def readpartial(n)
59
- recv(n)
60
- end
61
-
62
64
  end
63
-
64
- end; end; end
65
+ end
data/lib/net/ssh/test.rb CHANGED
@@ -3,87 +3,92 @@ require 'net/ssh/connection/session'
3
3
  require 'net/ssh/test/kex'
4
4
  require 'net/ssh/test/socket'
5
5
 
6
- module Net; module SSH
6
+ module Net
7
+ module SSH
8
+ # This module may be used in unit tests, for when you want to test that your
9
+ # SSH state machines are really doing what you expect they are doing. You will
10
+ # typically include this module in your unit test class, and then build a
11
+ # "story" of expected sends and receives:
12
+ #
13
+ # require 'minitest/autorun'
14
+ # require 'net/ssh/test'
15
+ #
16
+ # class MyTest < Minitest::Test
17
+ # include Net::SSH::Test
18
+ #
19
+ # def test_exec_via_channel_works
20
+ # story do |session|
21
+ # channel = session.opens_channel
22
+ # channel.sends_exec "ls"
23
+ # channel.gets_data "result of ls"
24
+ # channel.gets_close
25
+ # channel.sends_close
26
+ # end
27
+ #
28
+ # assert_scripted do
29
+ # result = nil
30
+ #
31
+ # connection.open_channel do |ch|
32
+ # ch.exec("ls") do |success|
33
+ # ch.on_data { |c, data| result = data }
34
+ # ch.on_close { |c| c.close }
35
+ # end
36
+ # end
37
+ #
38
+ # connection.loop
39
+ # assert_equal "result of ls", result
40
+ # end
41
+ # end
42
+ # end
43
+ #
44
+ # See Net::SSH::Test::Channel and Net::SSH::Test::Script for more options.
45
+ #
46
+ # Note that the Net::SSH::Test system is rather finicky yet, and can be kind
47
+ # of frustrating to get working. Any suggestions for improvement will be
48
+ # welcome!
49
+ module Test
50
+ # If a block is given, yields the script for the test socket (#socket).
51
+ # Otherwise, simply returns the socket's script. See Net::SSH::Test::Script.
52
+ def story
53
+ Net::SSH::Test::Extensions::IO.with_test_extension { yield socket.script if block_given? }
54
+ return socket.script
55
+ end
7
56
 
8
- # This module may be used in unit tests, for when you want to test that your
9
- # SSH state machines are really doing what you expect they are doing. You will
10
- # typically include this module in your unit test class, and then build a
11
- # "story" of expected sends and receives:
12
- #
13
- # require 'test/unit'
14
- # require 'net/ssh/test'
15
- #
16
- # class MyTest < Test::Unit::TestCase
17
- # include Net::SSH::Test
18
- #
19
- # def test_exec_via_channel_works
20
- # story do |session|
21
- # channel = session.opens_channel
22
- # channel.sends_exec "ls"
23
- # channel.gets_data "result of ls"
24
- # channel.gets_close
25
- # channel.sends_close
26
- # end
27
- #
28
- # assert_scripted do
29
- # result = nil
30
- #
31
- # connection.open_channel do |ch|
32
- # ch.exec("ls") do |success|
33
- # ch.on_data { |c, data| result = data }
34
- # ch.on_close { |c| c.close }
35
- # end
36
- # end
37
- #
38
- # connection.loop
39
- # assert_equal "result of ls", result
40
- # end
41
- # end
42
- # end
43
- #
44
- # See Net::SSH::Test::Channel and Net::SSH::Test::Script for more options.
45
- #
46
- # Note that the Net::SSH::Test system is rather finicky yet, and can be kind
47
- # of frustrating to get working. Any suggestions for improvement will be
48
- # welcome!
49
- module Test
50
- # If a block is given, yields the script for the test socket (#socket).
51
- # Otherwise, simply returns the socket's script. See Net::SSH::Test::Script.
52
- def story
53
- yield socket.script if block_given?
54
- return socket.script
55
- end
57
+ # Returns the test socket instance to use for these tests (see
58
+ # Net::SSH::Test::Socket).
59
+ def socket(options = {})
60
+ @socket ||= Net::SSH::Test::Socket.new
61
+ end
56
62
 
57
- # Returns the test socket instance to use for these tests (see
58
- # Net::SSH::Test::Socket).
59
- def socket(options={})
60
- @socket ||= Net::SSH::Test::Socket.new
61
- end
63
+ # Returns the connection session (Net::SSH::Connection::Session) for use
64
+ # in these tests. It is a fully functional SSH session, operating over
65
+ # a mock socket (#socket).
66
+ def connection(options = {})
67
+ @connection ||= Net::SSH::Connection::Session.new(transport(options), options)
68
+ end
62
69
 
63
- # Returns the connection session (Net::SSH::Connection::Session) for use
64
- # in these tests. It is a fully functional SSH session, operating over
65
- # a mock socket (#socket).
66
- def connection(options={})
67
- @connection ||= Net::SSH::Connection::Session.new(transport(options), options)
68
- end
70
+ # Returns the transport session (Net::SSH::Transport::Session) for use
71
+ # in these tests. It is a fully functional SSH transport session, operating
72
+ # over a mock socket (#socket).
73
+ def transport(options = {})
74
+ @transport ||= Net::SSH::Transport::Session.new(
75
+ options[:host] || "localhost",
76
+ options.merge(kex: "test", host_key: "ssh-rsa", append_all_supported_algorithms: true, verify_host_key: :never, proxy: socket(options))
77
+ )
78
+ end
69
79
 
70
- # Returns the transport session (Net::SSH::Transport::Session) for use
71
- # in these tests. It is a fully functional SSH transport session, operating
72
- # over a mock socket (#socket).
73
- def transport(options={})
74
- @transport ||= Net::SSH::Transport::Session.new(options[:host] || "localhost", options.merge(:kex => "test", :host_key => "ssh-rsa", :paranoid => false, :proxy => socket(options)))
75
- end
80
+ # First asserts that a story has been described (see #story). Then yields,
81
+ # and then asserts that all items described in the script have been
82
+ # processed. Typically, this is called immediately after a story has
83
+ # been built, and the SSH commands being tested are then executed within
84
+ # the block passed to this assertion.
85
+ def assert_scripted
86
+ raise "there is no script to be processed" if socket.script.events.empty?
76
87
 
77
- # First asserts that a story has been described (see #story). Then yields,
78
- # and then asserts that all items described in the script have been
79
- # processed. Typically, this is called immediately after a story has
80
- # been built, and the SSH commands being tested are then executed within
81
- # the block passed to this assertion.
82
- def assert_scripted
83
- raise "there is no script to be processed" if socket.script.events.empty?
84
- yield
85
- assert socket.script.events.empty?, "there should not be any remaining scripted events, but there are still #{socket.script.events.length} pending"
88
+ Net::SSH::Test::Extensions::IO.with_test_extension { yield }
89
+ assert socket.script.events.empty?, "there should not be any remaining scripted events, but there are still" \
90
+ "#{socket.script.events.length} pending"
91
+ end
86
92
  end
87
93
  end
88
-
89
- end; end
94
+ end