Module: Xshellz::Ssh

Defined in:
lib/xshellz/ssh.rb

Overview

SSH/SFTP data plane, behind a small transport interface for testability.

The real implementation (NetSshTransport) speaks SSH as root to the sandbox. Host keys are auto-accepted (+verify_host_key: :never+): sandboxes are throwaway boxes whose host keys are generated at spawn time, so there is no out-of-band fingerprint to pin against.

Defined Under Namespace

Classes: NetSshTransport

Constant Summary collapse

ENV_NAME =
/\A[A-Za-z_][A-Za-z0-9_]*\z/

Class Method Summary collapse

Class Method Details

.build_shell_command(command, cwd: nil, env: nil) ⇒ Object

Wrap a command with optional cd and environment exports.

Environment variable names are validated (sshd rarely honours AcceptEnv, so variables are exported in the remote shell instead).



22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/xshellz/ssh.rb', line 22

def self.build_shell_command(command, cwd: nil, env: nil)
  parts = []
  if env && !env.empty?
    exports = env.map do |key, value|
      raise Error, "Invalid environment variable name: #{key.inspect}" unless key.to_s.match?(ENV_NAME)

      "#{key}=#{Shellwords.escape(value.to_s)}"
    end
    parts << "export #{exports.join(" ")}"
  end
  parts << "cd #{Shellwords.escape(cwd)}" if cwd
  parts << command
  parts.join(" && ")
end

.load_private_key!(private_key) ⇒ Object

Load/validate an OpenSSH-format private key string; raises a helpful Xshellz::Error when it cannot be parsed.



39
40
41
42
43
44
45
46
# File 'lib/xshellz/ssh.rb', line 39

def self.load_private_key!(private_key)
  Net::SSH::KeyFactory.load_data_private_key(private_key.to_s, nil, false)
rescue StandardError => e
  raise Error,
        "Could not load the private key. Expected an unencrypted " \
        "OpenSSH-format private key (e.g. Sandbox#private_key_openssh). " \
        "Details: #{e.class}: #{e.message}"
end