feat(ssh): native SSH as default, remove WebSocket relay#854
Merged
paulocsanz merged 8 commits intomasterfrom Apr 27, 2026
Merged
feat(ssh): native SSH as default, remove WebSocket relay#854paulocsanz merged 8 commits intomasterfrom
paulocsanz merged 8 commits intomasterfrom
Conversation
- Remove WebSocket relay, platform event loops, and --native flag - Add --session flag: tmux persistent sessions via native SSH with auto-reconnect - Add --deployment-instance flag: passes instance ID directly as SSH username - Add -T flag for non-interactive command execution
62f55c5 to
8c4f89d
Compare
The flag is kept hidden for backward compatibility with existing scripts and skills that pass --native, but now prints a deprecation warning.
coffee-cup
approved these changes
Apr 23, 2026
Replace unconditional -T-on-command with stdin/stdout TTY detection, mirroring docker exec / kubectl exec behavior: - command + both TTYs -> -t (so vim/htop/less work remotely) - command + non-TTY -> -T (clean pipes for scripts/CI) - no command + TTY -> ssh default (interactive shell with PTY) - no command + non-TTY -> -T (avoid mangling piped stdin) Fixes the previous behavior where `railway ssh -- vim foo` blocked PTY and made interactive remote tools unusable.
Accepts a path to a private key and forwards it to the spawned ssh process via -i, mirroring ssh(1). When set, skips the local ~/.ssh fingerprint scan — ssh surfaces any auth failures directly.
Adds a small tel helper that wraps each stage of the SSH flow and fires
a stage-tagged CliTrackEvent on failure, in addition to the generic
event from the commands! macro. Stages: key_setup, resolve_target,
instance_lookup, tmux_install, session_connect, spawn, exit_nonzero,
and keys_{list,add,remove,github}.
Also fixes a gap where a non-zero ssh child exit bypassed telemetry
entirely via std::process::exit, and splits run_native_ssh_with_session
so tmux-install failures are distinguishable from session connect
failures in telemetry.
Backend change (railwayapp/mono#27883) adds workspace-owned SSH keys — registered under a workspace instead of a user, so CI/CD can authenticate as the workspace over native SSH. Thread that through the CLI: - sshPublicKeys query now accepts workspaceId; sshPublicKeyCreate takes workspaceId in its input. Schema.json regenerated from the new backend schema. - get_registered_ssh_keys / register_ssh_key take Option<String> workspace_id. None → user keys (current behavior); Some → workspace. - `railway ssh keys` gains a global --workspace flag. `list / add / remove` operate on that workspace's keys when set; ADMIN access on the workspace is required for add / remove (enforced by backboard). - `railway ssh keys github` rejects --workspace explicitly — GitHub import is a user-only path. Error message points the user at `railway ssh keys add --workspace <id> --key <path>` after importing. - The auto-register prompt the regular `railway ssh` flow runs before connecting (ensure_ssh_key) stays user-scoped; workspace keys are registered once up front by an admin, not interactively per-connect. No change to the `railway ssh` command itself — once a workspace key is registered, the OS ssh client presents it and backboard's lookupOwnerByKeyFingerprint recognizes it as workspace-owned via the backend PR above.
…cope Adds the `ssh_keys` scope to the CLI's OAuth request so `railway login` sessions can manage SSH keys (backend gates list/create/delete on it per railwayapp/mono#27883). Under `RAILWAY_API_TOKEN` scoped to a single workspace, `railway ssh keys` and `railway ssh`'s preflight now auto-resolve the workspace via the `apiToken { workspaces }` introspection query — no explicit `--workspace` needed. Explicit `--workspace` is still accepted but must match the token's workspace, else the CLI errors locally with a clear message. `railway ssh keys` with `RAILWAY_TOKEN` (project token) bails up front since project tokens cannot manage SSH keys.
…s from ctx
Paired with the backboard change that defaults `sshPublicKey{s,Create}`
`workspaceId` to `ctx.workspace.id` when the caller is on a
workspace-scoped API token. The CLI no longer needs to pre-call
`apiToken { workspaces }` to discover what the backend already knew.
Removes:
- `src/gql/queries/strings/ApiToken.graphql` (+ registration)
- `resolve_token_workspace` / `TokenWorkspace` in controllers
- `resolve_workspace_arg` reconciler in `ssh keys`
- workspace-token branch in `ensure_ssh_key` preflight
Kept:
- `ssh_keys` in CLI OAuth scopes (required by OAuth auth path regardless)
- `RAILWAY_TOKEN` rejection at the top of `ssh keys` (project tokens still can't manage SSH keys)
- The `--workspace` flag and its explicit-override behavior
Net: one fewer GraphQL round-trip per `railway ssh` invocation, ~120
fewer lines of CLI code, same UX under a workspace token.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the WebSocket relay SSH implementation with native SSH (
ssh <serviceInstanceId>@ssh.railway.com) as the only connection mode.--nativeflag — native SSH is now the default (--nativekept hidden, no-op, prints deprecation warning)--sessionrelay dependency; tmux sessions now work via native SSH with auto-reconnect--deployment-instanceflag: passes instance ID directly as the SSH usernamedocker exec/kubectl exec):-t(interactive remote tools likevim,htopwork)-T(clean pipes for scripts / CI)-T(avoid mangling piped stdin)