sshkit 1.21.7 → 1.22.1
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.
- checksums.yaml +4 -4
- data/.github/workflows/push.yml +1 -1
- data/EXAMPLES.md +25 -13
- data/README.md +2 -1
- data/lib/sshkit/backends/netssh/known_hosts.rb +3 -1
- data/lib/sshkit/backends/netssh/scp_transfer.rb +26 -0
- data/lib/sshkit/backends/netssh/sftp_transfer.rb +46 -0
- data/lib/sshkit/backends/netssh.rb +36 -6
- data/lib/sshkit/host.rb +7 -0
- data/lib/sshkit/version.rb +1 -1
- data/sshkit.gemspec +2 -0
- data/test/functional/backends/netssh_transfer_tests.rb +83 -0
- data/test/functional/backends/test_netssh.rb +0 -66
- data/test/functional/backends/test_netssh_scp.rb +23 -0
- data/test/functional/backends/test_netssh_sftp.rb +23 -0
- data/test/unit/backends/test_abstract.rb +1 -1
- data/test/unit/backends/test_netssh.rb +48 -0
- data/test/unit/test_deprecation_logger.rb +1 -1
- data/test/unit/test_host.rb +27 -0
- metadata +39 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 9678c16acec683a599b5cca548346060ba08fd5616e79109af71deac743d33f3
         | 
| 4 | 
            +
              data.tar.gz: 6213ece3ddf070a9bf715452da5883f27eb0d3cff81bc5b8a5ccd73f4649c03d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 265bf603d9c5d7557beaf9e33270acb8e626238016f4bd892017ac4cf2afa1a3f7364612c85d10a239c93fc278a2a6fe2904011688fac78e871388b4b9249c0b
         | 
| 7 | 
            +
              data.tar.gz: ee46c52f728b8d550182332f88c07dd8b885717afe12291248a6b5a200a3d8180dacc7de863ef3e0ee8f23c264def9dff670cd97e84eea6cfee4d8c3534d2350
         | 
    
        data/.github/workflows/push.yml
    CHANGED
    
    
    
        data/EXAMPLES.md
    CHANGED
    
    | @@ -121,9 +121,6 @@ on hosts do |host| | |
| 121 121 | 
             
            end
         | 
| 122 122 | 
             
            ```
         | 
| 123 123 |  | 
| 124 | 
            -
            **Note:** The `upload!()` method doesn't honor the values of `as()` etc, this
         | 
| 125 | 
            -
            will be improved as the library matures, but we're not there yet.
         | 
| 126 | 
            -
             | 
| 127 124 | 
             
            ## Upload a file from a stream
         | 
| 128 125 |  | 
| 129 126 | 
             
            ```ruby
         | 
| @@ -148,9 +145,6 @@ end | |
| 148 145 | 
             
            This spares one from having to figure out the correct escaping sequences for
         | 
| 149 146 | 
             
            something like "echo(:cat, '...?...', '> /etc/sudoers.d/yolo')".
         | 
| 150 147 |  | 
| 151 | 
            -
            **Note:** The `upload!()` method doesn't honor the values of `within()`, `as()`
         | 
| 152 | 
            -
            etc, this will be improved as the library matures, but we're not there yet.
         | 
| 153 | 
            -
             | 
| 154 148 | 
             
            ## Upload a directory of files
         | 
| 155 149 |  | 
| 156 150 | 
             
            ```ruby
         | 
| @@ -160,7 +154,25 @@ end | |
| 160 154 | 
             
            ```
         | 
| 161 155 |  | 
| 162 156 | 
             
            In this case the `recursive: true` option mirrors the same options which are
         | 
| 163 | 
            -
            available to [`Net:: | 
| 157 | 
            +
            available to [`Net::SCP`](https://github.com/net-ssh/net-scp) and
         | 
| 158 | 
            +
            [`Net::SFTP`](https://github.com/net-ssh/net-sftp).
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            ## Set the upload/download method (SCP or SFTP).
         | 
| 161 | 
            +
             | 
| 162 | 
            +
            SSHKit can use SCP or SFTP for file transfers. The default is SCP, but this can be changed to SFTP per host:
         | 
| 163 | 
            +
             | 
| 164 | 
            +
            ```ruby
         | 
| 165 | 
            +
            host = SSHKit::Host.new('user@example.com')
         | 
| 166 | 
            +
            host.transfer_method = :sftp
         | 
| 167 | 
            +
            ```
         | 
| 168 | 
            +
             | 
| 169 | 
            +
            or globally:
         | 
| 170 | 
            +
             | 
| 171 | 
            +
            ```ruby
         | 
| 172 | 
            +
            SSHKit::Backend::Netssh.configure do |ssh|
         | 
| 173 | 
            +
              ssh.transfer_method = :sftp
         | 
| 174 | 
            +
            end
         | 
| 175 | 
            +
            ```
         | 
| 164 176 |  | 
| 165 177 | 
             
            ## Setting global SSH options
         | 
| 166 178 |  | 
| @@ -235,16 +247,16 @@ end | |
| 235 247 |  | 
| 236 248 | 
             
            ```ruby
         | 
| 237 249 | 
             
            # The default format is pretty, which outputs colored text
         | 
| 238 | 
            -
            SSHKit.config. | 
| 250 | 
            +
            SSHKit.config.use_format :pretty
         | 
| 239 251 |  | 
| 240 252 | 
             
            # Text with no coloring
         | 
| 241 | 
            -
            SSHKit.config. | 
| 253 | 
            +
            SSHKit.config.use_format :simpletext
         | 
| 242 254 |  | 
| 243 255 | 
             
            # Red / Green dots for each completed step
         | 
| 244 | 
            -
            SSHKit.config. | 
| 256 | 
            +
            SSHKit.config.use_format :dot
         | 
| 245 257 |  | 
| 246 258 | 
             
            # No output
         | 
| 247 | 
            -
            SSHKit.config. | 
| 259 | 
            +
            SSHKit.config.use_format :blackhole
         | 
| 248 260 | 
             
            ```
         | 
| 249 261 |  | 
| 250 262 | 
             
            ## Implement a dirt-simple formatter class
         | 
| @@ -254,7 +266,7 @@ module SSHKit | |
| 254 266 | 
             
              module Formatter
         | 
| 255 267 | 
             
                class MyFormatter < SSHKit::Formatter::Abstract
         | 
| 256 268 | 
             
                  def write(obj)
         | 
| 257 | 
            -
                     | 
| 269 | 
            +
                    if obj.is_a? SSHKit::Command
         | 
| 258 270 | 
             
                      # Do something here, see the SSHKit::Command documentation
         | 
| 259 271 | 
             
                    end
         | 
| 260 272 | 
             
                  end
         | 
| @@ -263,7 +275,7 @@ module SSHKit | |
| 263 275 | 
             
            end
         | 
| 264 276 |  | 
| 265 277 | 
             
            # If your formatter is defined in the SSHKit::Formatter module configure with the format option:
         | 
| 266 | 
            -
            SSHKit.config. | 
| 278 | 
            +
            SSHKit.config.use_format :myformatter
         | 
| 267 279 |  | 
| 268 280 | 
             
            # Or configure the output directly
         | 
| 269 281 | 
             
            SSHKit.config.output = MyFormatter.new($stdout)
         | 
    
        data/README.md
    CHANGED
    
    | @@ -68,7 +68,8 @@ you can pass the `strip: false` option: `capture(:ls, '-l', strip: false)` | |
| 68 68 | 
             
            ### Transferring files
         | 
| 69 69 |  | 
| 70 70 | 
             
            All backends also support the `upload!` and `download!` methods for transferring files.
         | 
| 71 | 
            -
            For the remote backend, the file is transferred with scp | 
| 71 | 
            +
            For the remote backend, the file is transferred with scp by default, but sftp is also
         | 
| 72 | 
            +
            supported. See [EXAMPLES.md](EXAMPLES.md) for details.
         | 
| 72 73 |  | 
| 73 74 | 
             
            ```ruby
         | 
| 74 75 | 
             
            on '1.example.com' do
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require "net/scp"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module SSHKit
         | 
| 4 | 
            +
              module Backend
         | 
| 5 | 
            +
                class Netssh < Abstract
         | 
| 6 | 
            +
                  class ScpTransfer
         | 
| 7 | 
            +
                    def initialize(ssh, summarizer)
         | 
| 8 | 
            +
                      @ssh = ssh
         | 
| 9 | 
            +
                      @summarizer = summarizer
         | 
| 10 | 
            +
                    end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    def upload!(local, remote, options)
         | 
| 13 | 
            +
                      ssh.scp.upload!(local, remote, options, &summarizer)
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    def download!(remote, local, options)
         | 
| 17 | 
            +
                      ssh.scp.download!(remote, local, options, &summarizer)
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    private
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    attr_reader :ssh, :summarizer
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            require "net/sftp"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module SSHKit
         | 
| 4 | 
            +
              module Backend
         | 
| 5 | 
            +
                class Netssh < Abstract
         | 
| 6 | 
            +
                  class SftpTransfer
         | 
| 7 | 
            +
                    def initialize(ssh, summarizer)
         | 
| 8 | 
            +
                      @ssh = ssh
         | 
| 9 | 
            +
                      @summarizer = summarizer
         | 
| 10 | 
            +
                    end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    def upload!(local, remote, options)
         | 
| 13 | 
            +
                      options = { progress: self }.merge(options || {})
         | 
| 14 | 
            +
                      ssh.sftp.connect!
         | 
| 15 | 
            +
                      ssh.sftp.upload!(local, remote, options)
         | 
| 16 | 
            +
                    ensure
         | 
| 17 | 
            +
                      ssh.sftp.close_channel
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    def download!(remote, local, options)
         | 
| 21 | 
            +
                      options = { progress: self }.merge(options || {})
         | 
| 22 | 
            +
                      destination = local ? local : StringIO.new.tap { |io| io.set_encoding('BINARY') }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                      ssh.sftp.connect!
         | 
| 25 | 
            +
                      ssh.sftp.download!(remote, destination, options)
         | 
| 26 | 
            +
                      local ? true : destination.string
         | 
| 27 | 
            +
                    ensure
         | 
| 28 | 
            +
                      ssh.sftp.close_channel
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    def on_get(download, entry, offset, data)
         | 
| 32 | 
            +
                      entry.size ||= download.sftp.file.open(entry.remote) { |file| file.stat.size }
         | 
| 33 | 
            +
                      summarizer.call(nil, entry.remote, offset + data.bytesize, entry.size)
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    def on_put(_upload, file, offset, data)
         | 
| 37 | 
            +
                      summarizer.call(nil, file.local, offset + data.bytesize, file.size)
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    private
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    attr_reader :ssh, :summarizer
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| @@ -2,7 +2,6 @@ require 'English' | |
| 2 2 | 
             
            require 'strscan'
         | 
| 3 3 | 
             
            require 'mutex_m'
         | 
| 4 4 | 
             
            require 'net/ssh'
         | 
| 5 | 
            -
            require 'net/scp'
         | 
| 6 5 |  | 
| 7 6 | 
             
            module Net
         | 
| 8 7 | 
             
              module SSH
         | 
| @@ -23,10 +22,27 @@ module SSHKit | |
| 23 22 | 
             
              module Backend
         | 
| 24 23 |  | 
| 25 24 | 
             
                class Netssh < Abstract
         | 
| 25 | 
            +
                  def self.assert_valid_transfer_method!(method)
         | 
| 26 | 
            +
                    return if [:scp, :sftp].include?(method)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    raise ArgumentError, "#{method.inspect} is not a valid transfer method. Supported methods are :scp, :sftp."
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 26 31 | 
             
                  class Configuration
         | 
| 27 32 | 
             
                    attr_accessor :connection_timeout, :pty
         | 
| 33 | 
            +
                    attr_reader :transfer_method
         | 
| 28 34 | 
             
                    attr_writer :ssh_options
         | 
| 29 35 |  | 
| 36 | 
            +
                    def initialize
         | 
| 37 | 
            +
                      self.transfer_method = :scp
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    def transfer_method=(method)
         | 
| 41 | 
            +
                      Netssh.assert_valid_transfer_method!(method)
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                      @transfer_method = method
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
             | 
| 30 46 | 
             
                    def ssh_options
         | 
| 31 47 | 
             
                      default_options.merge(@ssh_options ||= {})
         | 
| 32 48 | 
             
                    end
         | 
| @@ -64,16 +80,16 @@ module SSHKit | |
| 64 80 | 
             
                  def upload!(local, remote, options = {})
         | 
| 65 81 | 
             
                    summarizer = transfer_summarizer('Uploading', options)
         | 
| 66 82 | 
             
                    remote = File.join(pwd_path, remote) unless remote.to_s.start_with?("/") || pwd_path.nil?
         | 
| 67 | 
            -
                     | 
| 68 | 
            -
                       | 
| 83 | 
            +
                    with_transfer(summarizer) do |transfer|
         | 
| 84 | 
            +
                      transfer.upload!(local, remote, options)
         | 
| 69 85 | 
             
                    end
         | 
| 70 86 | 
             
                  end
         | 
| 71 87 |  | 
| 72 88 | 
             
                  def download!(remote, local=nil, options = {})
         | 
| 73 89 | 
             
                    summarizer = transfer_summarizer('Downloading', options)
         | 
| 74 90 | 
             
                    remote = File.join(pwd_path, remote) unless remote.to_s.start_with?("/") || pwd_path.nil?
         | 
| 75 | 
            -
                     | 
| 76 | 
            -
                       | 
| 91 | 
            +
                    with_transfer(summarizer) do |transfer|
         | 
| 92 | 
            +
                      transfer.download!(remote, local, options)
         | 
| 77 93 | 
             
                    end
         | 
| 78 94 | 
             
                  end
         | 
| 79 95 |  | 
| @@ -105,7 +121,7 @@ module SSHKit | |
| 105 121 | 
             
                    last_percentage = nil
         | 
| 106 122 | 
             
                    proc do |_ch, name, transferred, total|
         | 
| 107 123 | 
             
                      percentage = (transferred.to_f * 100 / total.to_f)
         | 
| 108 | 
            -
                      unless percentage.nan?
         | 
| 124 | 
            +
                      unless percentage.nan? || percentage.infinite?
         | 
| 109 125 | 
             
                        message = "#{action} #{name} #{percentage.round(2)}%"
         | 
| 110 126 | 
             
                        percentage_r = (percentage / log_percent).truncate * log_percent
         | 
| 111 127 | 
             
                        if percentage_r > 0 && (last_name != name || last_percentage != percentage_r)
         | 
| @@ -183,6 +199,20 @@ module SSHKit | |
| 183 199 | 
             
                    )
         | 
| 184 200 | 
             
                  end
         | 
| 185 201 |  | 
| 202 | 
            +
                  def with_transfer(summarizer)
         | 
| 203 | 
            +
                    transfer_method = host.transfer_method || self.class.config.transfer_method
         | 
| 204 | 
            +
                    transfer_class = if transfer_method == :sftp
         | 
| 205 | 
            +
                                       require_relative "netssh/sftp_transfer"
         | 
| 206 | 
            +
                                       SftpTransfer
         | 
| 207 | 
            +
                                     else
         | 
| 208 | 
            +
                                       require_relative "netssh/scp_transfer"
         | 
| 209 | 
            +
                                       ScpTransfer
         | 
| 210 | 
            +
                                     end
         | 
| 211 | 
            +
             | 
| 212 | 
            +
                    with_ssh do |ssh|
         | 
| 213 | 
            +
                      yield(transfer_class.new(ssh, summarizer))
         | 
| 214 | 
            +
                    end
         | 
| 215 | 
            +
                  end
         | 
| 186 216 | 
             
                end
         | 
| 187 217 | 
             
              end
         | 
| 188 218 |  | 
    
        data/lib/sshkit/host.rb
    CHANGED
    
    | @@ -7,6 +7,7 @@ module SSHKit | |
| 7 7 | 
             
              class Host
         | 
| 8 8 |  | 
| 9 9 | 
             
                attr_accessor :password, :hostname, :port, :user, :ssh_options
         | 
| 10 | 
            +
                attr_reader :transfer_method
         | 
| 10 11 |  | 
| 11 12 | 
             
                def key=(new_key)
         | 
| 12 13 | 
             
                  @keys = [new_key]
         | 
| @@ -41,6 +42,12 @@ module SSHKit | |
| 41 42 | 
             
                  end
         | 
| 42 43 | 
             
                end
         | 
| 43 44 |  | 
| 45 | 
            +
                def transfer_method=(method)
         | 
| 46 | 
            +
                  Backend::Netssh.assert_valid_transfer_method!(method) unless method.nil?
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  @transfer_method = method
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 44 51 | 
             
                def local?
         | 
| 45 52 | 
             
                  @local
         | 
| 46 53 | 
             
                end
         | 
    
        data/lib/sshkit/version.rb
    CHANGED
    
    
    
        data/sshkit.gemspec
    CHANGED
    
    | @@ -20,9 +20,11 @@ Gem::Specification.new do |gem| | |
| 20 20 | 
             
              gem.require_paths = ["lib"]
         | 
| 21 21 | 
             
              gem.version       = SSHKit::VERSION
         | 
| 22 22 |  | 
| 23 | 
            +
              gem.add_runtime_dependency('base64') if RUBY_VERSION >= "2.4"
         | 
| 23 24 | 
             
              gem.add_runtime_dependency('mutex_m')
         | 
| 24 25 | 
             
              gem.add_runtime_dependency('net-ssh',  '>= 2.8.0')
         | 
| 25 26 | 
             
              gem.add_runtime_dependency('net-scp',  '>= 1.1.2')
         | 
| 27 | 
            +
              gem.add_runtime_dependency('net-sftp', '>= 2.1.2')
         | 
| 26 28 |  | 
| 27 29 | 
             
              gem.add_development_dependency('danger')
         | 
| 28 30 | 
             
              gem.add_development_dependency('minitest', '>= 5.0.0')
         | 
| @@ -0,0 +1,83 @@ | |
| 1 | 
            +
            require 'securerandom'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module SSHKit
         | 
| 4 | 
            +
              module Backend
         | 
| 5 | 
            +
                module NetsshTransferTests
         | 
| 6 | 
            +
                  def setup
         | 
| 7 | 
            +
                    super
         | 
| 8 | 
            +
                    @output = String.new
         | 
| 9 | 
            +
                    SSHKit.config.output_verbosity = :debug
         | 
| 10 | 
            +
                    SSHKit.config.output = SSHKit::Formatter::SimpleText.new(@output)
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def a_host
         | 
| 14 | 
            +
                    VagrantWrapper.hosts['one']
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def test_upload_and_then_capture_file_contents
         | 
| 18 | 
            +
                    actual_file_contents = ""
         | 
| 19 | 
            +
                    file_name = File.join("/tmp", SecureRandom.uuid)
         | 
| 20 | 
            +
                    File.open file_name, 'w+' do |f|
         | 
| 21 | 
            +
                      f.write "Some Content\nWith a newline and trailing spaces    \n "
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                    Netssh.new(a_host) do
         | 
| 24 | 
            +
                      upload!(file_name, file_name)
         | 
| 25 | 
            +
                      actual_file_contents = capture(:cat, file_name, strip: false)
         | 
| 26 | 
            +
                    end.run
         | 
| 27 | 
            +
                    assert_equal "Some Content\nWith a newline and trailing spaces    \n ", actual_file_contents
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def test_upload_within
         | 
| 31 | 
            +
                    file_name = SecureRandom.uuid
         | 
| 32 | 
            +
                    file_contents = "Some Content"
         | 
| 33 | 
            +
                    dir_name = SecureRandom.uuid
         | 
| 34 | 
            +
                    actual_file_contents = ""
         | 
| 35 | 
            +
                    Netssh.new(a_host) do |_host|
         | 
| 36 | 
            +
                      within("/tmp") do
         | 
| 37 | 
            +
                        execute :mkdir, "-p", dir_name
         | 
| 38 | 
            +
                        within(dir_name) do
         | 
| 39 | 
            +
                          upload!(StringIO.new(file_contents), file_name)
         | 
| 40 | 
            +
                        end
         | 
| 41 | 
            +
                      end
         | 
| 42 | 
            +
                      actual_file_contents = capture(:cat, "/tmp/#{dir_name}/#{file_name}", strip: false)
         | 
| 43 | 
            +
                    end.run
         | 
| 44 | 
            +
                    assert_equal file_contents, actual_file_contents
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def test_upload_string_io
         | 
| 48 | 
            +
                    file_contents = ""
         | 
| 49 | 
            +
                    Netssh.new(a_host) do |_host|
         | 
| 50 | 
            +
                      file_name = File.join("/tmp", SecureRandom.uuid)
         | 
| 51 | 
            +
                      upload!(StringIO.new('example_io'), file_name)
         | 
| 52 | 
            +
                      file_contents = download!(file_name)
         | 
| 53 | 
            +
                    end.run
         | 
| 54 | 
            +
                    assert_equal "example_io", file_contents
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def test_upload_large_file
         | 
| 58 | 
            +
                    size      = 25
         | 
| 59 | 
            +
                    fills     = SecureRandom.random_bytes(1024*1024)
         | 
| 60 | 
            +
                    file_name = "/tmp/file-#{size}.txt"
         | 
| 61 | 
            +
                    File.open(file_name, 'wb') do |f|
         | 
| 62 | 
            +
                      (size).times {f.write(fills) }
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
                    file_contents = ""
         | 
| 65 | 
            +
                    Netssh.new(a_host) do
         | 
| 66 | 
            +
                      upload!(file_name, file_name)
         | 
| 67 | 
            +
                      file_contents = download!(file_name)
         | 
| 68 | 
            +
                    end.run
         | 
| 69 | 
            +
                    assert_equal File.open(file_name, 'rb').read, file_contents
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  def test_upload_via_pathname
         | 
| 73 | 
            +
                    file_contents = ""
         | 
| 74 | 
            +
                    Netssh.new(a_host) do |_host|
         | 
| 75 | 
            +
                      file_name = Pathname.new(File.join("/tmp", SecureRandom.uuid))
         | 
| 76 | 
            +
                      upload!(StringIO.new('example_io'), file_name)
         | 
| 77 | 
            +
                      file_contents = download!(file_name)
         | 
| 78 | 
            +
                    end.run
         | 
| 79 | 
            +
                    assert_equal "example_io", file_contents
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
            end
         | 
| @@ -1,5 +1,4 @@ | |
| 1 1 | 
             
            require 'helper'
         | 
| 2 | 
            -
            require 'securerandom'
         | 
| 3 2 | 
             
            require 'benchmark'
         | 
| 4 3 |  | 
| 5 4 | 
             
            module SSHKit
         | 
| @@ -136,71 +135,6 @@ module SSHKit | |
| 136 135 | 
             
                    end.run
         | 
| 137 136 | 
             
                  end
         | 
| 138 137 |  | 
| 139 | 
            -
                  def test_upload_and_then_capture_file_contents
         | 
| 140 | 
            -
                    actual_file_contents = ""
         | 
| 141 | 
            -
                    file_name = File.join("/tmp", SecureRandom.uuid)
         | 
| 142 | 
            -
                    File.open file_name, 'w+' do |f|
         | 
| 143 | 
            -
                      f.write "Some Content\nWith a newline and trailing spaces    \n "
         | 
| 144 | 
            -
                    end
         | 
| 145 | 
            -
                    Netssh.new(a_host) do
         | 
| 146 | 
            -
                      upload!(file_name, file_name)
         | 
| 147 | 
            -
                      actual_file_contents = capture(:cat, file_name, strip: false)
         | 
| 148 | 
            -
                    end.run
         | 
| 149 | 
            -
                    assert_equal "Some Content\nWith a newline and trailing spaces    \n ", actual_file_contents
         | 
| 150 | 
            -
                  end
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                  def test_upload_within
         | 
| 153 | 
            -
                    file_name = SecureRandom.uuid
         | 
| 154 | 
            -
                    file_contents = "Some Content"
         | 
| 155 | 
            -
                    dir_name = SecureRandom.uuid
         | 
| 156 | 
            -
                    actual_file_contents = ""
         | 
| 157 | 
            -
                    Netssh.new(a_host) do |_host|
         | 
| 158 | 
            -
                      within("/tmp") do
         | 
| 159 | 
            -
                        execute :mkdir, "-p", dir_name
         | 
| 160 | 
            -
                        within(dir_name) do
         | 
| 161 | 
            -
                          upload!(StringIO.new(file_contents), file_name)
         | 
| 162 | 
            -
                        end
         | 
| 163 | 
            -
                      end
         | 
| 164 | 
            -
                      actual_file_contents = capture(:cat, "/tmp/#{dir_name}/#{file_name}", strip: false)
         | 
| 165 | 
            -
                    end.run
         | 
| 166 | 
            -
                    assert_equal file_contents, actual_file_contents
         | 
| 167 | 
            -
                  end
         | 
| 168 | 
            -
             | 
| 169 | 
            -
                  def test_upload_string_io
         | 
| 170 | 
            -
                    file_contents = ""
         | 
| 171 | 
            -
                    Netssh.new(a_host) do |_host|
         | 
| 172 | 
            -
                      file_name = File.join("/tmp", SecureRandom.uuid)
         | 
| 173 | 
            -
                      upload!(StringIO.new('example_io'), file_name)
         | 
| 174 | 
            -
                      file_contents = download!(file_name)
         | 
| 175 | 
            -
                    end.run
         | 
| 176 | 
            -
                    assert_equal "example_io", file_contents
         | 
| 177 | 
            -
                  end
         | 
| 178 | 
            -
             | 
| 179 | 
            -
                  def test_upload_large_file
         | 
| 180 | 
            -
                    size      = 25
         | 
| 181 | 
            -
                    fills     = SecureRandom.random_bytes(1024*1024)
         | 
| 182 | 
            -
                    file_name = "/tmp/file-#{size}.txt"
         | 
| 183 | 
            -
                    File.open(file_name, 'wb') do |f|
         | 
| 184 | 
            -
                      (size).times {f.write(fills) }
         | 
| 185 | 
            -
                    end
         | 
| 186 | 
            -
                    file_contents = ""
         | 
| 187 | 
            -
                    Netssh.new(a_host) do
         | 
| 188 | 
            -
                      upload!(file_name, file_name)
         | 
| 189 | 
            -
                      file_contents = download!(file_name)
         | 
| 190 | 
            -
                    end.run
         | 
| 191 | 
            -
                    assert_equal File.open(file_name, 'rb').read, file_contents
         | 
| 192 | 
            -
                  end
         | 
| 193 | 
            -
             | 
| 194 | 
            -
                  def test_upload_via_pathname
         | 
| 195 | 
            -
                    file_contents = ""
         | 
| 196 | 
            -
                    Netssh.new(a_host) do |_host|
         | 
| 197 | 
            -
                      file_name = Pathname.new(File.join("/tmp", SecureRandom.uuid))
         | 
| 198 | 
            -
                      upload!(StringIO.new('example_io'), file_name)
         | 
| 199 | 
            -
                      file_contents = download!(file_name)
         | 
| 200 | 
            -
                    end.run
         | 
| 201 | 
            -
                    assert_equal "example_io", file_contents
         | 
| 202 | 
            -
                  end
         | 
| 203 | 
            -
             | 
| 204 138 | 
             
                  def test_interaction_handler
         | 
| 205 139 | 
             
                    captured_command_result = nil
         | 
| 206 140 | 
             
                    Netssh.new(a_host) do
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
            require_relative 'netssh_transfer_tests'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module SSHKit
         | 
| 5 | 
            +
              module Backend
         | 
| 6 | 
            +
                class TestNetsshScp < FunctionalTest
         | 
| 7 | 
            +
                  include NetsshTransferTests
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def setup
         | 
| 10 | 
            +
                    super
         | 
| 11 | 
            +
                    SSHKit::Backend::Netssh.configure do |ssh|
         | 
| 12 | 
            +
                      ssh.transfer_method = :scp
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def test_scp_implementation_is_used
         | 
| 17 | 
            +
                    Netssh.new(a_host).send(:with_transfer, nil) do |transfer|
         | 
| 18 | 
            +
                      assert_instance_of Netssh::ScpTransfer, transfer
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
            require_relative 'netssh_transfer_tests'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module SSHKit
         | 
| 5 | 
            +
              module Backend
         | 
| 6 | 
            +
                class TestNetsshSftp < FunctionalTest
         | 
| 7 | 
            +
                  include NetsshTransferTests
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def setup
         | 
| 10 | 
            +
                    super
         | 
| 11 | 
            +
                    SSHKit::Backend::Netssh.configure do |ssh|
         | 
| 12 | 
            +
                      ssh.transfer_method = :sftp
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def test_sftp_implementation_is_used
         | 
| 17 | 
            +
                    Netssh.new(a_host).send(:with_transfer, nil) do |transfer|
         | 
| 18 | 
            +
                      assert_instance_of Netssh::SftpTransfer, transfer
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -124,7 +124,7 @@ module SSHKit | |
| 124 124 | 
             
                    assert_equal 2, lines.length
         | 
| 125 125 |  | 
| 126 126 | 
             
                    assert_equal("[Deprecated] The background method is deprecated. Blame badly behaved pseudo-daemons!\n", lines[0])
         | 
| 127 | 
            -
                    assert_match(/    \(Called from.*test_abstract.rb:\d+:in  | 
| 127 | 
            +
                    assert_match(/    \(Called from.*test_abstract.rb:\d+:in .block in .*test_background_logs_deprecation_warnings.\)\n/, lines[1])
         | 
| 128 128 | 
             
                  end
         | 
| 129 129 |  | 
| 130 130 | 
             
                  def test_calling_abstract_with_undefined_execute_command_raises_exception
         | 
| @@ -5,6 +5,12 @@ module SSHKit | |
| 5 5 | 
             
              module Backend
         | 
| 6 6 | 
             
                class TestNetssh < UnitTest
         | 
| 7 7 |  | 
| 8 | 
            +
                  def teardown
         | 
| 9 | 
            +
                    super
         | 
| 10 | 
            +
                    # Reset config to defaults after each test
         | 
| 11 | 
            +
                    backend.instance_variable_set :@config, nil
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 8 14 | 
             
                  def backend
         | 
| 9 15 | 
             
                    @backend ||= Netssh
         | 
| 10 16 | 
             
                  end
         | 
| @@ -13,6 +19,7 @@ module SSHKit | |
| 13 19 | 
             
                    backend.configure do |ssh|
         | 
| 14 20 | 
             
                      ssh.pty = true
         | 
| 15 21 | 
             
                      ssh.connection_timeout = 30
         | 
| 22 | 
            +
                      ssh.transfer_method = :sftp
         | 
| 16 23 | 
             
                      ssh.ssh_options = {
         | 
| 17 24 | 
             
                        keys: %w(/home/user/.ssh/id_rsa),
         | 
| 18 25 | 
             
                        forward_agent: false,
         | 
| @@ -21,6 +28,7 @@ module SSHKit | |
| 21 28 | 
             
                    end
         | 
| 22 29 |  | 
| 23 30 | 
             
                    assert_equal 30, backend.config.connection_timeout
         | 
| 31 | 
            +
                    assert_equal :sftp, backend.config.transfer_method
         | 
| 24 32 | 
             
                    assert_equal true, backend.config.pty
         | 
| 25 33 |  | 
| 26 34 | 
             
                    assert_equal %w(/home/user/.ssh/id_rsa),  backend.config.ssh_options[:keys]
         | 
| @@ -29,6 +37,46 @@ module SSHKit | |
| 29 37 | 
             
                    assert_instance_of backend::KnownHosts,   backend.config.ssh_options[:known_hosts]
         | 
| 30 38 | 
             
                  end
         | 
| 31 39 |  | 
| 40 | 
            +
                  def test_transfer_method_prohibits_invalid_values
         | 
| 41 | 
            +
                    error = assert_raises ArgumentError do
         | 
| 42 | 
            +
                      backend.configure do |ssh|
         | 
| 43 | 
            +
                        ssh.transfer_method = :nope
         | 
| 44 | 
            +
                      end
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    assert_match ":nope is not a valid transfer method", error.message
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def test_transfer_method_does_not_allow_nil
         | 
| 51 | 
            +
                    error = assert_raises ArgumentError do
         | 
| 52 | 
            +
                      backend.configure do |ssh|
         | 
| 53 | 
            +
                        ssh.transfer_method = nil
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    assert_match "nil is not a valid transfer method", error.message
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def test_transfer_method_defaults_to_scp
         | 
| 61 | 
            +
                    assert_equal :scp, backend.config.transfer_method
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  def test_host_can_override_transfer_method
         | 
| 65 | 
            +
                    backend.configure do |ssh|
         | 
| 66 | 
            +
                      ssh.transfer_method = :scp
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    host = Host.new("fake")
         | 
| 70 | 
            +
                    host.transfer_method = :sftp
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    netssh = backend.new(host)
         | 
| 73 | 
            +
                    netssh.stubs(:with_ssh).yields(nil)
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    netssh.send(:with_transfer, nil) do |transfer|
         | 
| 76 | 
            +
                      assert_instance_of Netssh::SftpTransfer, transfer
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 32 80 | 
             
                  def test_netssh_ext
         | 
| 33 81 | 
             
                    assert_includes  Net::SSH::Config.default_files, "#{Dir.pwd}/.ssh/config"
         | 
| 34 82 | 
             
                  end
         | 
| @@ -20,7 +20,7 @@ module SSHKit | |
| 20 20 |  | 
| 21 21 | 
             
                  assert_equal(2, actual_lines.size)
         | 
| 22 22 | 
             
                  assert_equal "[Deprecated] Some message\n", actual_lines[0]
         | 
| 23 | 
            -
                  assert_match %r{    \(Called from .*sshkit/test/unit/test_deprecation_logger.rb:#{line_number}:in  | 
| 23 | 
            +
                  assert_match %r{    \(Called from .*sshkit/test/unit/test_deprecation_logger.rb:#{line_number}:in .*generate_warning.\)\n}, actual_lines[1]
         | 
| 24 24 | 
             
                end
         | 
| 25 25 |  | 
| 26 26 | 
             
                def test_handles_nil_output
         | 
    
        data/test/unit/test_host.rb
    CHANGED
    
    | @@ -142,6 +142,33 @@ module SSHKit | |
| 142 142 | 
             
                  end
         | 
| 143 143 | 
             
                end
         | 
| 144 144 |  | 
| 145 | 
            +
                def test_transfer_method_defaults_to_nil
         | 
| 146 | 
            +
                  host = Host.new 'example.com'
         | 
| 147 | 
            +
                  assert_nil host.transfer_method
         | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                def test_transfer_method_can_be_configured
         | 
| 151 | 
            +
                  host = Host.new 'example.com'
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                  host.transfer_method = :scp
         | 
| 154 | 
            +
                  assert_equal :scp, host.transfer_method
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                  host.transfer_method = :sftp
         | 
| 157 | 
            +
                  assert_equal :sftp, host.transfer_method
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                  host.transfer_method = nil
         | 
| 160 | 
            +
                  assert_nil host.transfer_method
         | 
| 161 | 
            +
                end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                def test_transfer_method_prohibits_invalid_values
         | 
| 164 | 
            +
                  host = Host.new 'example.com'
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                  error = assert_raises ArgumentError do
         | 
| 167 | 
            +
                    host.transfer_method = :nope
         | 
| 168 | 
            +
                  end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                  assert_match ":nope is not a valid transfer method", error.message
         | 
| 171 | 
            +
                end
         | 
| 145 172 | 
             
              end
         | 
| 146 173 |  | 
| 147 174 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: sshkit
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.22.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Lee Hambley
         | 
| @@ -9,8 +9,22 @@ authors: | |
| 9 9 | 
             
            autorequire:
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date:  | 
| 12 | 
            +
            date: 2024-04-01 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 15 | 
            +
              name: base64
         | 
| 16 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 17 | 
            +
                requirements:
         | 
| 18 | 
            +
                - - ">="
         | 
| 19 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 20 | 
            +
                    version: '0'
         | 
| 21 | 
            +
              type: :runtime
         | 
| 22 | 
            +
              prerelease: false
         | 
| 23 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 24 | 
            +
                requirements:
         | 
| 25 | 
            +
                - - ">="
         | 
| 26 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 27 | 
            +
                    version: '0'
         | 
| 14 28 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 29 | 
             
              name: mutex_m
         | 
| 16 30 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -53,6 +67,20 @@ dependencies: | |
| 53 67 | 
             
                - - ">="
         | 
| 54 68 | 
             
                  - !ruby/object:Gem::Version
         | 
| 55 69 | 
             
                    version: 1.1.2
         | 
| 70 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 71 | 
            +
              name: net-sftp
         | 
| 72 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 73 | 
            +
                requirements:
         | 
| 74 | 
            +
                - - ">="
         | 
| 75 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 76 | 
            +
                    version: 2.1.2
         | 
| 77 | 
            +
              type: :runtime
         | 
| 78 | 
            +
              prerelease: false
         | 
| 79 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 80 | 
            +
                requirements:
         | 
| 81 | 
            +
                - - ">="
         | 
| 82 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 83 | 
            +
                    version: 2.1.2
         | 
| 56 84 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 57 85 | 
             
              name: danger
         | 
| 58 86 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -228,6 +256,8 @@ files: | |
| 228 256 | 
             
            - lib/sshkit/backends/local.rb
         | 
| 229 257 | 
             
            - lib/sshkit/backends/netssh.rb
         | 
| 230 258 | 
             
            - lib/sshkit/backends/netssh/known_hosts.rb
         | 
| 259 | 
            +
            - lib/sshkit/backends/netssh/scp_transfer.rb
         | 
| 260 | 
            +
            - lib/sshkit/backends/netssh/sftp_transfer.rb
         | 
| 231 261 | 
             
            - lib/sshkit/backends/printer.rb
         | 
| 232 262 | 
             
            - lib/sshkit/backends/skipper.rb
         | 
| 233 263 | 
             
            - lib/sshkit/color.rb
         | 
| @@ -255,8 +285,11 @@ files: | |
| 255 285 | 
             
            - lib/sshkit/version.rb
         | 
| 256 286 | 
             
            - sshkit.gemspec
         | 
| 257 287 | 
             
            - test/boxes.json
         | 
| 288 | 
            +
            - test/functional/backends/netssh_transfer_tests.rb
         | 
| 258 289 | 
             
            - test/functional/backends/test_local.rb
         | 
| 259 290 | 
             
            - test/functional/backends/test_netssh.rb
         | 
| 291 | 
            +
            - test/functional/backends/test_netssh_scp.rb
         | 
| 292 | 
            +
            - test/functional/backends/test_netssh_sftp.rb
         | 
| 260 293 | 
             
            - test/functional/test_ssh_server_comes_up_for_functional_tests.rb
         | 
| 261 294 | 
             
            - test/helper.rb
         | 
| 262 295 | 
             
            - test/known_hosts/github
         | 
| @@ -305,14 +338,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 305 338 | 
             
                - !ruby/object:Gem::Version
         | 
| 306 339 | 
             
                  version: '0'
         | 
| 307 340 | 
             
            requirements: []
         | 
| 308 | 
            -
            rubygems_version: 3.5. | 
| 341 | 
            +
            rubygems_version: 3.5.6
         | 
| 309 342 | 
             
            signing_key:
         | 
| 310 343 | 
             
            specification_version: 4
         | 
| 311 344 | 
             
            summary: SSHKit makes it easy to write structured, testable SSH commands in Ruby
         | 
| 312 345 | 
             
            test_files:
         | 
| 313 346 | 
             
            - test/boxes.json
         | 
| 347 | 
            +
            - test/functional/backends/netssh_transfer_tests.rb
         | 
| 314 348 | 
             
            - test/functional/backends/test_local.rb
         | 
| 315 349 | 
             
            - test/functional/backends/test_netssh.rb
         | 
| 350 | 
            +
            - test/functional/backends/test_netssh_scp.rb
         | 
| 351 | 
            +
            - test/functional/backends/test_netssh_sftp.rb
         | 
| 316 352 | 
             
            - test/functional/test_ssh_server_comes_up_for_functional_tests.rb
         | 
| 317 353 | 
             
            - test/helper.rb
         | 
| 318 354 | 
             
            - test/known_hosts/github
         |