Contributing Guide
Relevant source files
The following files were used as context for generating this wiki page:
This guide provides technical instructions for developers wishing to contribute to the sshpiper project. sshpiper acts as a reverse proxy for SSH, routing connections from a downstream client to an upstream server based on logic defined in plugins. The project architecture is designed to be extensible, allowing contributors to enhance the core daemon (sshpiperd), develop new plugins via gRPC, or improve the seasoned crypto/ssh library.
Sources: README.md:9-16, CONTRIBUTING.md:46-55
Development Environment Setup
To start developing on sshpiper, you must satisfy specific software requirements and initialize the repository including its submodules.
Software Requirements
- Go: The primary language for the daemon and most plugins.
- Docker & Docker Compose: Used for the end-to-end (e2e) test environment.
- Git: Required for version control and submodule management.
Sources: CONTRIBUTING.md:7-12
Initializing the Codebase
Developers must clone the repository recursively to ensure all submodules, particularly the seasoned crypto library, are present.
git clone https://github.com/tg123/sshpiper
cd sshpiper
git submodule update --init --recursive
Sources: CONTRIBUTING.md:16-20
Local Sandbox (E2E Environment)
A pre-configured development environment is available in the e2e folder. Running docker-compose up starts sshpiperd alongside two target SSH servers:
host-password:2222: A password-only SSH server.host-publickey:2222: A public-key-only SSH server.
Sources: CONTRIBUTING.md:24-32
Core Architecture Overview
The system is divided into three primary components: the low-level crypto library, the main daemon, and the gRPC-based plugin system.
This diagram illustrates the flow of a connection request handled by the daemon and routed via a plugin.
Sources: CONTRIBUTING.md:46-63
Component Responsibilities
| Component | Description |
|---|---|
| crypto/ | A seasoned version of golang.org/x/crypto/ssh with low-level API exposures via sshpiper.go. |
| sshpiperd | The daemon that manages connections and wraps the crypto library. |
| plugin | A typically separate process acting as a gRPC server to determine routing and authentication mapping. |
Sources: CONTRIBUTING.md:48-60, README.md:120-125
Plugin Development
Plugins are first-class citizens in v1. They are separate binaries that communicate with sshpiperd primarily through stdin/stdout wrapped in gRPC via ioconn.
The Plugin Protocol
The communication is governed by plugin.proto. Plugins must implement the SshPiperPlugin service, which includes lifecycle and authentication callbacks.
This sequence shows the standard gRPC handshake between the daemon and a plugin during client authentication.
Sources: libplugin/plugin.proto:43-57, CONTRIBUTING.md:57-63
Creating a Simple Plugin
A plugin is initialized using a configuration struct that defines how to handle various authentication attempts. The plugin returns an Upstream object containing the target host, port, and the credentials to be used for the upstream connection.
&libplugin.SshPiperPluginConfig{
PasswordCallback: func(conn libplugin.ConnMetadata, password []byte) (*libplugin.Upstream, error) {
return &libplugin.Upstream{
Host: host,
Port: int32(port),
IgnoreHostKey: true,
Auth: libplugin.CreatePasswordAuth(password),
}, nil
},
}
Sources: CONTRIBUTING.md:68-79
Testing and Quality Assurance
Running Tests
After making changes, developers should verify their work by running the e2e tests within the testrunner container.
- Attach to the container:
docker exec -ti e2e-testrunner-1 bash - Run tests:
go testinside the/src/e2edirectory.
Sources: CONTRIBUTING.md:36-42
Plugin Chaining Logic
For advanced routing, sshpiperd supports plugin chaining. The ChainPlugins structure manages multiple plugins, passing metadata between them to refine routing decisions.
- NextPluginAuth: Allows a plugin to pass control (and optional metadata) to the next plugin in the chain.
- RetryCurrentPluginAuth: Requests a retry of the current plugin, often used for multi-step authentication like TOTP.
Sources: cmd/sshpiperd/internal/plugin/chain.go:12-42, libplugin/plugin.proto:26-28
Summary of Contribution Workflow
- Fork the repository and clone with submodules.
- Setup the e2e environment using Docker Compose.
- Implement changes in the daemon, crypto lib, or create new plugins in the
plugin/directory. - Test using the internal e2e test suite.
- Submit a Pull Request via GitHub.
Sources: CONTRIBUTING.md:16-44