From 73c7e2a1e3fb148b4ad45561f50db004d35a48f8 Mon Sep 17 00:00:00 2001 From: Jaap-Jan de Wit | DodoTech Date: Sat, 1 Aug 2026 21:12:00 +0200 Subject: [PATCH] Point a release build at the hosted server, and a debug build at the clone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shipped default was http://localhost:5233, which is the address the API serves under dotnet run and a machine an installed application is not running. Somebody who installs a release and accepts the field unread is signing in to nothing. Two defaults now, because the two audiences never overlap. A release build offers https://ssh.dodotech.cloud, so a first launch needs no address typed at all. A debug build keeps the loopback address, and that half matters as much: shipping the hosted address into a clone would point every development launch at production, and sign-in is the call that provisions an account there. The remark carries the reason the schemes differ, since the pair now looks like an oversight rather than the deliberate thing it is — the API's first launch profile is plaintext on 5233, and an HTTPS client meeting a plaintext port reports a TLS failure that reads like a certificate problem. The test spells out both branches rather than asserting the constant, which would pass however it were edited. What it is really guarding is that a release never ships a developer's loopback address and a debug build never points a clone at production, and it can only guard those by naming them. Verified by running the shell suite in Debug and in Release. Co-Authored-By: Claude Opus 5 (1M context) --- .../ViewModels/MainWindowViewModel.cs | 33 ++++++++++++++----- .../ShellFlowTests.cs | 24 ++++++++++---- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/DodoSSH.Client.Shell/ViewModels/MainWindowViewModel.cs b/src/DodoSSH.Client.Shell/ViewModels/MainWindowViewModel.cs index d9a5579..d51c132 100644 --- a/src/DodoSSH.Client.Shell/ViewModels/MainWindowViewModel.cs +++ b/src/DodoSSH.Client.Shell/ViewModels/MainWindowViewModel.cs @@ -332,18 +332,33 @@ internal sealed partial class MainWindowViewModel : ObservableObject, IAsyncDisp /// internal bool HasNoDeviceKeyOption => !CanRegisterDevice && !CanForgetDevice; + /// + /// The address offered on first launch, before anything is enrolled. + /// /// - /// The address dotnet run --project src/DodoSSH.Api actually serves, so the first launch after - /// a clone works without the user having to know a port. This was https://localhost:7217, which - /// is the API's second launch profile: the first is HTTP on 5233 and is the one both the - /// README and a plain dotnet run select, so nothing was listening on 7217. Pointing an HTTPS - /// client at a plaintext port fails as "The SSL connection could not be established", which sends - /// people looking for a certificate problem — see . A real - /// deployment is HTTPS behind a proxy and its address is typed over this one; the placeholder in the - /// setup card shows that shape. + /// + /// Two defaults, because the two audiences never overlap. A release build is installed by somebody + /// signing in to the hosted deployment, and typing its address is the only thing standing between + /// them and a working application. A debug build is run from a clone, next to + /// dotnet run --project src/DodoSSH.Api, and shipping the hosted address there would point + /// every development launch at production — which is worse than an inconvenience, since sign-in is + /// the step that enrolls a device. + /// + /// + /// Note the schemes. http locally is not an oversight: the API's first launch profile — the + /// one a plain dotnet run and the README both select — is plaintext on 5233, and pointing an + /// HTTPS client at a plaintext port fails as "The SSL connection could not be established", which + /// sends people looking for a certificate problem. See . + /// /// +#if DEBUG + internal const string DefaultServerUrl = "http://localhost:5233"; +#else + internal const string DefaultServerUrl = "https://ssh.dodotech.cloud"; +#endif + [ObservableProperty] - private string serverUrl = "http://localhost:5233"; + private string serverUrl = DefaultServerUrl; [ObservableProperty] private string passphrase = string.Empty; diff --git a/tests/DodoSSH.Client.App.Tests/ShellFlowTests.cs b/tests/DodoSSH.Client.App.Tests/ShellFlowTests.cs index acd6401..2b27a94 100644 --- a/tests/DodoSSH.Client.App.Tests/ShellFlowTests.cs +++ b/tests/DodoSSH.Client.App.Tests/ShellFlowTests.cs @@ -213,16 +213,28 @@ public sealed class ShellFlowTests : IAsyncLifetime } /// - /// The shipped default is a value a user is invited to accept unread, so it is worth one assertion. - /// It was https://localhost:7217 — the API's second launch profile — while the README, the - /// API's appsettings and a plain dotnet run all use HTTP on 5233, and pointing an HTTPS client - /// at a plaintext port reports a TLS failure that reads like a certificate problem. Nothing failed - /// except the first thing a new user does. + /// + /// The shipped default is a value a user is invited to accept unread — it is what the button under it + /// will actually contact — so it is worth one assertion. It has twice been an address nothing was + /// listening on: https://localhost:7217, the API's second launch profile, and then the first + /// profile's http://localhost:5233 in a release build, which is a machine an installed + /// application is not running. + /// + /// + /// Both branches are written out rather than compared against the constant itself. Asserting a + /// constant against itself would pass however it were edited, and the whole point of this test is + /// that a release build must not ship a developer's loopback address — or, since the split, that a + /// debug build must not point a clone at production. + /// /// [Fact] - public void TheDefaultServerUrl_IsTheAddressTheApiActuallyServes() + public void TheDefaultServerUrl_IsTheHostedDeployment_ExceptInADebugBuild() { +#if DEBUG shell.ServerUrl.ShouldBe("http://localhost:5233"); +#else + shell.ServerUrl.ShouldBe("https://ssh.dodotech.cloud"); +#endif } [Theory]