-
Notifications
You must be signed in to change notification settings - Fork 166
feat: expose host ports between host and containers via ssh sidecar #846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for testcontainers-rust ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
testcontainers/Cargo.toml
Outdated
memchr = "2.7.2" | ||
parse-display = "0.9.0" | ||
pin-project-lite = "0.2.14" | ||
russh = { version = "0.54.3", default-features = false, features = ["ring", "rsa"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to keep it under a feature - looks like a good candidate.
Isolated functionality and we can enable feature by default later.
It's common request to be able to use testcontainers without ring
or aws-lc-rs
.
Hi @DDtKey, thanks again for the earlier review—your feedback made it much easier to tighten things up. Since that round I’ve:
|
It seems the failing test is unrelated to this patch and may just be flaky. The same CI job passes on my fork, so I don’t have a repro tied to these changes. Since I don’t have permissions to retry the job here, I may have to wait for someone who does to rerun it. |
Close #821
host.rs
is the core of this change and contains the implementation of host port exposure via SSH reverse tunnels. The file is fairly large and assumes familiarity with the background, so here is a top-down walkthrough to lower the reviewer’s cognitive load, plus an explanation of howtcpip_forward
andserver_channel_open_forwarded_tcpip
work together in the forwarding flow.HostPortExposure
setup
orchestrates the flow in four stages—build plan → launch sidecar → establish SSH → register ports—highlighting the control path and failure handling.shutdown
/Drop
perform cleanup: trigger the cancellation token and, when running inside Tokio, disconnect the SSH session gracefully.HostExposurePlan
Preparation stage
prepare_host_exposure
handles port deduplication, rejects reserved ports, disallows incompatible network modes and reusable containers, and generates the random password, ensuring the plan has valid inputs.Sidecar launch
spawn_sshd_sidecar
boots the ephemeral SSHD based ontestcontainers/sshd:1.3.0
, exposes port 22, injects the single-use password, and attaches to the user network if present.SSH session setup
connect_with_retry
performs an exponential backoff TCP connect to the sidecar and enablesTCP_NODELAY
.establish_ssh_connection
selects IPv4/IPv6 host-port resolution, creates the russh client, authenticates with the generated password, and wires up the handler.Port registration and callbacks
register_requested_ports
invokestcpip_forward
for each host port so the SSHD listens on the exact requested value; it fails fast if the server attempts to allocate a different port.tcpip_forward
is the SSH remote port forwarding request, effectively mirroring the first half ofssh -R <port>:localhost:<port>
: the client asks the server to listen on that port and tunnel any incoming connection back over SSH.server_channel_open_forwarded_tcpip
is the russh callback triggered when the SSH server accepts a new connection on a forwarded port. The handler dialslocalhost:<remote_port>
on the host, then bridges the SSH channel and the local TCP stream withcopy_bidirectional
, completing the second half of thessh -R
behavior. In other words, the full forwarding chain is “declare the listener viatcpip_forward
→ handle incoming traffic in the callback by wiring up the data path.”Tunnel handling and teardown
HostExposeHandler
keeps aCancellationToken
so every forwarding task can be cancelled consistently;start_forward_connection
spawns the async proxy, whileforward_connection
pumps data in both directions and shuts streams down cleanly.HostExposeError
wraps russh and framework errors and converts them back intoTestcontainersError
, producing actionable diagnostics.Reviewing in this order lets you understand the high-level contract first, then drill into port validation, sidecar management, SSH session establishment, forwarding callbacks, and resource cleanup without getting lost in the details.