ssh

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 1, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package ssh provides SSH/SFTP transport for testfleet.

Index

Constants

View Source
const DefaultTransferTimeout = 30 * time.Minute

DefaultTransferTimeout is the default deadline for SFTP UploadDir / DownloadDir when callers use the *WithTimeout helpers without specifying one.

Variables

This section is empty.

Functions

func Dial

func Dial(host string, port int, user, keyPath, knownHostsPath string) (*ssh.Client, error)

Dial opens an SSH client to host:port using public-key authentication.

knownHostsPath enforces strict host-key checking with an "accept-new" twist: when a host is encountered for the first time, its key is appended to the known_hosts file. If the file does not exist it is created (mode 0600 with parent dirs created at 0700). Subsequent key changes for an already-known host are rejected, matching OpenSSH's StrictHostKeyChecking=accept-new.

All failures (TCP connect, auth, host-key mismatch) are wrapped in a *DialError with ErrSSHFailed so callers can branch on output.ErrSSHFailed.

func DownloadDir

func DownloadDir(client *ssh.Client, remoteDir, localDir string) error

DownloadDir is the inverse of UploadDir.

func DownloadDirContext

func DownloadDirContext(ctx context.Context, client *ssh.Client, remoteDir, localDir string) error

DownloadDirContext is the context-aware variant of DownloadDir.

func DownloadDirWithTimeout

func DownloadDirWithTimeout(ctx context.Context, client *ssh.Client, remoteDir, localDir string, timeout time.Duration) error

DownloadDirWithTimeout wraps DownloadDir with a per-call deadline.

func RemoteWriteFile

func RemoteWriteFile(ctx context.Context, client *ssh.Client, remotePath string, content []byte, isWindows bool) error

RemoteWriteFile writes content to remotePath on the remote host.

On Linux/macOS targets (isWindows=false) the file is written via SFTP — straightforward and binary-safe.

On Windows targets (isWindows=true) we instead base64-encode content and pipe it through a PowerShell one-liner that converts it back to bytes:

powershell -NoProfile -ExecutionPolicy Bypass -Command
  "$b='<base64>'; [System.IO.File]::WriteAllBytes('<path>',
   [System.Convert]::FromBase64String($b))"

This avoids the escape-quoting hell of embedding arbitrary JSON / config payloads through PowerShell + OpenSSH's command translation layer (cf. qmd B3). It also sidesteps Windows OpenSSH's SFTP server quirks around partial writes for small files.

func Run

func Run(ctx context.Context, client *ssh.Client, cmd string, stdin io.Reader) (stdoutBytes, stderrBytes []byte, exitCode int, err error)

Run executes cmd on the remote host. stdin (if non-nil) is fed to the remote process's standard input. The remote process is run inside an ssh.Session and its stdout/stderr are captured into memory.

When ctx is cancelled (timeout or explicit cancel) the session is closed, which kills the remote process; the returned error wraps ctx.Err().

exitCode reflects the remote process exit status:

  • 0 on clean exit
  • the remote-reported exit code on non-zero exit (no error returned — callers inspect exitCode themselves; the test fleet treats a non-zero exit as a normal test failure rather than an infra error).
  • -1 when the remote process was killed by a signal or transport died.

func RunWithTimeout

func RunWithTimeout(ctx context.Context, client *ssh.Client, cmd string, stdin io.Reader, timeout time.Duration) (stdout, stderr []byte, exitCode int, err error)

RunWithTimeout is Run with an explicit per-call deadline.

If timeout is <=0 the parent ctx is used unchanged. When the deadline elapses, the remote session is killed and the returned error wraps context.DeadlineExceeded with ErrTransferTimeout (matching the contract for SFTP transfers — the CLI surfaces "transfer_timeout" for any timed-out remote operation so the agent can branch on a single code).

func UploadDir

func UploadDir(client *ssh.Client, localDir, remoteDir string) error

UploadDir recursively uploads localDir to remoteDir on the remote host.

Behaviour:

  • remote paths are always built with path.Join (POSIX "/") regardless of the local OS, because the remote SFTP server speaks POSIX paths even on Windows OpenSSH.
  • missing intermediate remote directories are created (sftp.MkdirAll).
  • file modes are preserved best-effort via os.Stat → Chmod.
  • symlinks are followed (filepath.Walk default).

Failures are wrapped in *TransferError with ErrSSHFailed unless the context deadline fires, in which case ErrTransferTimeout is used.

func UploadDirContext

func UploadDirContext(ctx context.Context, client *ssh.Client, localDir, remoteDir string) error

UploadDirContext is the context-aware variant of UploadDir.

func UploadDirWithTimeout

func UploadDirWithTimeout(ctx context.Context, client *ssh.Client, localDir, remoteDir string, timeout time.Duration) error

UploadDirWithTimeout wraps UploadDir with a per-call deadline.

Types

type DialError

type DialError struct {
	Code output.ErrorCode
	Host string
	Err  error
}

DialError wraps the underlying ssh failure with the testfleet error code.

func (*DialError) Error

func (e *DialError) Error() string

func (*DialError) Unwrap

func (e *DialError) Unwrap() error

type ExecError

type ExecError struct {
	Code output.ErrorCode
	Cmd  string
	Err  error
}

ExecError wraps an exec failure with a testfleet error code.

func (*ExecError) Error

func (e *ExecError) Error() string

func (*ExecError) Unwrap

func (e *ExecError) Unwrap() error

type TransferError

type TransferError struct {
	Code output.ErrorCode
	Op   string
	Err  error
}

TransferError wraps an sftp failure with a testfleet error code.

func (*TransferError) Error

func (e *TransferError) Error() string

func (*TransferError) Unwrap

func (e *TransferError) Unwrap() error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL