Repository navigation
fix(server): let operators set the SSH host for open-in-editor links #11207
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,11 +2,17 @@ | |
| * RemoteOpenTargets - resolves the SSH hostnames this environment advertises | ||
| * for remote open-in-editor deep links (`vscode://vscode-remote/ssh-remote+…`). | ||
| * | ||
| * The server can only check itself: sshd listening locally, tailscaled | ||
| * reporting a MagicDNS name, and the machine hostname for mDNS. Whether a | ||
| * given name resolves from the viewer's machine is inherently client-side. | ||
| * Targets are ordered most-reachable first (tailnet name works from anywhere | ||
| * on the tailnet; `<hostname>.local` only on the same LAN). | ||
| * An operator-configured host (`T3CODE_REMOTE_OPEN_HOST`) comes first: an | ||
| * ssh config alias there resolves user, port and key through the viewer's | ||
| * own `~/.ssh/config`, which a bare hostname cannot express. The probed names | ||
| * still follow it so clients that predate the `configured` kind keep the | ||
| * target they had. | ||
| * | ||
| * For probing, the server can only check itself: sshd listening locally, | ||
| * tailscaled reporting a MagicDNS name, and the machine hostname for mDNS. | ||
| * Whether a given name resolves from the viewer's machine is inherently | ||
| * client-side. Targets are ordered most-reachable first (tailnet name works | ||
| * from anywhere on the tailnet; `<hostname>.local` only on the same LAN). | ||
| */ | ||
| import { type RemoteOpenTarget } from "@t3tools/contracts"; | ||
| import { HostProcessHostname } from "@t3tools/shared/hostProcess"; | ||
|
|
@@ -17,6 +23,8 @@ import * as Effect from "effect/Effect"; | |
| import * as Layer from "effect/Layer"; | ||
| import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner"; | ||
|
|
||
| import { ServerConfig } from "../config.ts"; | ||
|
|
||
| const SSH_PORT = 22; | ||
|
|
||
| export class RemoteOpenTargets extends Context.Service< | ||
|
|
@@ -30,8 +38,9 @@ export class RemoteOpenTargets extends Context.Service< | |
| export const make = Effect.gen(function* () { | ||
| const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; | ||
| const net = yield* NetService.NetService; | ||
| const { remoteOpenHost } = yield* ServerConfig; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Import the local service module as a namespace and acquire it through its public tag ( Posted via Macroscope — Effect Service Conventions |
||
|
|
||
| const resolveTargets = Effect.gen(function* () { | ||
| const probeTargets = Effect.gen(function* () { | ||
| // No local sshd means no name can work; advertise nothing so clients | ||
| // render a clear "no SSH route" state instead of links that hang. | ||
| // Check both loopback families: sshd can be bound IPv6-only. | ||
|
|
@@ -67,6 +76,12 @@ export const make = Effect.gen(function* () { | |
| return targets; | ||
| }); | ||
|
|
||
| const resolveTargets = Effect.map(probeTargets, (probed): ReadonlyArray<RemoteOpenTarget> => | ||
| remoteOpenHost === undefined | ||
| ? probed | ||
| : [{ kind: "configured", host: remoteOpenHost }, ...probed], | ||
| ); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| return RemoteOpenTargets.of({ resolveTargets: () => resolveTargets }); | ||
| }); | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.