SSH port forwarding (direct-tcpip) not implemented #1

Open
opened 2026-04-24 15:19:56 +00:00 by qwolff · 0 comments
Owner

claudify attach -L 3000:3000 silently fails. The CLI passes -L through to ssh, and the ssh client tries to open a direct-tcpip channel when traffic arrives on the local port. The russh server in claudify-gateway has no channel_open_direct_tcpip handler, so the channel open is rejected and local forwards never connect.

Required for

Live-preview URLs (e.g. bun dev on 5173, next dev on 3000). Not a v0.1.0 blocker per the user's deployment checklist, but expected for 'use Claudify like your dev laptop.'

Implementation sketch

In crates/gateway/src/ssh/server.rs, implement the Handler trait's channel_open_direct_tcpip(host_to_connect, port_to_connect, originator_host, originator_port, session) method:

  1. Reject if the authenticated fingerprint is not set.
  2. Look up which ClaudifySession this SSH connection belongs to — by keeping a per-handler Option<String> alongside fingerprint that subsystem_request("claudify-attach:...") sets.
  3. Use kube::Api<Pod>::portforward(pod_name, [port_to_connect]) to establish a kubelet port-forward stream into the session pod.
  4. Bridge bytes between the russh direct-tcpip Channel and the portforward stream, similar to the attach byte plumbing in ssh/attach.rs.

Test coverage to add

  • New e2e scenario: start a session, inside the pod python3 -m http.server 8080, attach with -L 8080:8080, curl http://localhost:8080 from the host, expect a directory listing.
  • Unit test for per-handler session lookup state.
`claudify attach -L 3000:3000` silently fails. The CLI passes `-L` through to `ssh`, and the `ssh` client tries to open a `direct-tcpip` channel when traffic arrives on the local port. The russh server in `claudify-gateway` has no `channel_open_direct_tcpip` handler, so the channel open is rejected and local forwards never connect. ## Required for Live-preview URLs (e.g. `bun dev` on 5173, `next dev` on 3000). Not a v0.1.0 blocker per the user's deployment checklist, but expected for 'use Claudify like your dev laptop.' ## Implementation sketch In `crates/gateway/src/ssh/server.rs`, implement the Handler trait's `channel_open_direct_tcpip(host_to_connect, port_to_connect, originator_host, originator_port, session)` method: 1. Reject if the authenticated fingerprint is not set. 2. Look up which ClaudifySession this SSH connection belongs to — by keeping a per-handler `Option<String>` alongside `fingerprint` that `subsystem_request("claudify-attach:...")` sets. 3. Use `kube::Api<Pod>::portforward(pod_name, [port_to_connect])` to establish a kubelet port-forward stream into the session pod. 4. Bridge bytes between the russh direct-tcpip Channel and the portforward stream, similar to the attach byte plumbing in `ssh/attach.rs`. ## Test coverage to add - New e2e scenario: start a session, inside the pod `python3 -m http.server 8080`, attach with `-L 8080:8080`, curl `http://localhost:8080` from the host, expect a directory listing. - Unit test for per-handler session lookup state.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
qwolff/claudify#1
No description provided.