Repository navigation
bug: SSH forwarding drops HTTPS behind TLS termination #3674
Description
User Story
As an OpenShell user connecting through a TLS-terminating gateway, I want SSH-backed connect and forwarding operations to use the registered HTTPS endpoint so that sandbox sessions work through the gateway.
Problem Statement
When the gateway reports an internal loopback or unspecified HTTP endpoint, the client replaces its host and port with the registered external gateway authority but retains the internal http scheme. It therefore sends plaintext HTTP/2 to the external TLS listener. The operation fails with a misleading GOAWAY FRAME_SIZE_ERROR.
This affects shared client logic used by the CLI and TUI and is not specific to agentgateway.
Impact / Why This Matters
Sandbox creation can succeed while connect, exec, and port-forwarding operations fail as soon as they establish the SSH relay. Users must avoid frontend TLS termination or use a topology whose backend scheme happens to match the frontend scheme. Neither workaround supports a general TLS-terminating ingress deployment.
Acceptance Criteria
- When a loopback or unspecified server authority is replaced with the registered external authority, its external
httporhttpsscheme is used too. - A reachable non-loopback server-provided endpoint retains its reported scheme and authority.
- CLI and TUI SSH connect, exec, and forwarding paths share the corrected behavior.
- Unit coverage includes an internal
http://0.0.0.0:8080endpoint resolved through an externalhttps://localhost:<port>endpoint. - Kubernetes E2E coverage exercises an SSH-backed operation through frontend TLS termination with a plaintext OpenShell backend.
Reproduction Steps
- Deploy OpenShell with backend TLS disabled.
- Expose its gRPC service through a TLS-terminating Gateway API implementation.
- Register the externally reachable
https://endpoint with the OpenShell CLI. - Create a sandbox and run an SSH-backed connect or port-forward operation.
- Observe
GOAWAY FRAME_SIZE_ERRORon the client andInvalidContentTypeon the TLS proxy.
Environment
- OpenShell:
590ab2abdwith the in-progress feat(helm): support agentgateway ingress #2469 agentgateway E2E changes - OS: macOS 26.6.2
- Runtime: k3d/Kubernetes
- Integration: reproduced with agentgateway v1.5.0 and
v0.0.0-alpha.3528a428 - Topologies: shared ListenerSet and dedicated Gateway HTTPS listeners; both
kubectl port-forwardand direct k3d load-balancer access
Logs
h2 protocol error: connection error detected: frame with invalid size
GoAway(b"", FRAME_SIZE_ERROR, Library)
failed to terminate TLS ... error="received corrupt message of type InvalidContentType"Investigation
CreateSshSession reports the backend bind scheme, which is http when TLS terminates at the ingress. Client endpoint reconstruction replaces only the internal host and port with the external endpoint authority. For example:
internal: http://0.0.0.0:8080
external: https://localhost:18443
actual: http://localhost:18443
expected: https://localhost:18443
Activity
danehans commentedon Sep 24, 2026
/assign
danehans commentedon Sep 24, 2026
Implementation Plan
Issue type:
fixComplexity: Low
Confidence: High — root cause reproduced and isolated
Summary
Make the shared SSH gateway resolver return a complete, scheme-aware endpoint. When OpenShell replaces an internal bind authority with the registered external authority, it will carry the external
httporhttpsscheme with it for both CLI and TUI paths.Scope
crates/openshell-core/src/forward.rs: resolve scheme, host, and port as one endpoint decision and expand its unit-test matrix.crates/openshell-cli/src/ssh.rs: use the resolved scheme in the non-bearer SSH path; retain the existing bearer-auth behavior.crates/openshell-tui/src/lib.rs: use the shared resolved scheme for connect, exec, and automatic forwarding.tasks/test.toml: add the focused Rustport_forwardregression to the shared and dedicated frontend-TLS tasks, since conformance alone passed during reproduction and did not exercise the failing SSH relay path.Implementation Steps
Test Plan
openshell-coreresolver matrix, includinghttp://0.0.0.0:8080throughhttps://localhost:<port>.port_forwardtest over a plaintext OpenShell backend.Risks & Open Questions
Documentation Impact
None expected. This restores intended transport behavior without changing configuration, public APIs, architecture boundaries, or LSM-sensitive behavior.
Revision 1 — initial plan
purp commentedon Sep 24, 2026
Hi, @danehans. Thanks for finding this and working to fix. We're not going to hold the 0.1.0 release for it, but we'll welcome it any time after that. Tagged it for the next weekly after for now.
danehans commentedon Oct 1, 2026
@purp thanks for the feedback. The fix for this issue is included in a larger PR that adds support for agentgateway as a k8s ingress. Let me know if you need me to split the fix out of this PR but I'm hoping both can land.
purp commentedon Oct 1, 2026
No worries, and no need to split it just for this.
danehans commentedon Oct 7, 2026
@purp just wanted to follow-up on this issue now that 0.1.0 was cut. I see the PR that fixes this issue is also referenced by a few other Issues/PRs. Is the plan to include this PR in 0.1.5 since it includes a fix for #3674?
fix(cli): preserve external TLS for SSH forwarding
danehans commentedon Oct 8, 2026
@purp since #3714 was closed, I pulled the fix for this issue into a dedicated PR- #4344
fix(cli): preserve external TLS for SSH forwarding (NVIDIA#4344)