Skip to content

Commit dbad3bc

Browse files
t3dotggclaude
andcommitted
Decline --share for dev:desktop
Desktop dev is not single-origin: the renderer gets VITE_HTTP_URL and VITE_WS_URL baked to loopback, so a tailnet visitor would load the UI and then watch it dial its own 127.0.0.1 for the backend. Sharing also overwrote VITE_DEV_SERVER_URL, which is the origin Electron loads the renderer from. Warn and carry on serving locally instead of handing out a URL that is broken in a way the user cannot see. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
1 parent 8684ca4 commit dbad3bc

2 files changed

Lines changed: 38 additions & 0 deletions

File tree

‎scripts/dev-runner.test.ts‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,34 @@ it.layer(NodeServices.layer)("dev-runner", (it) => {
654654
}),
655655
);
656656

657+
// Sharing dev:desktop would publish a URL whose renderer dials the
658+
// visitor's own loopback, and would clobber the VITE_DEV_SERVER_URL that
659+
// Electron loads from. It must decline, not half-work.
660+
it.effect("declines to share for dev:desktop and still starts the stack", () => {
661+
let spawnCount = 0;
662+
const spawnerLayer = Layer.succeed(
663+
ChildProcessSpawner.ChildProcessSpawner,
664+
ChildProcessSpawner.make(() => {
665+
spawnCount += 1;
666+
return Effect.succeed(mockProcess(0));
667+
}),
668+
);
669+
670+
return Effect.gen(function* () {
671+
yield* runDevRunnerWithInput({
672+
...devServerInput,
673+
mode: "dev:desktop",
674+
port: undefined,
675+
share: true,
676+
}).pipe(
677+
Effect.provide(Layer.mergeAll(emptyConfigLayer, netServiceLayer, spawnerLayer)),
678+
Effect.provideService(HostProcessPlatform, "linux"),
679+
);
680+
681+
assert.equal(spawnCount, 1);
682+
});
683+
});
684+
657685
it.effect("spawns nothing when --dry-run is combined with --share", () => {
658686
let spawnCount = 0;
659687
const spawnerLayer = Layer.succeed(

‎scripts/dev-runner.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,16 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) {
591591
if (input.share) {
592592
if (input.mode === "dev:server") {
593593
yield* Effect.logInfo("[dev-runner] --share has no effect for dev:server (no web server).");
594+
} else if (input.mode === "dev:desktop") {
595+
// Desktop is not single-origin: the renderer gets VITE_HTTP_URL and
596+
// VITE_WS_URL baked to loopback, so a tailnet visitor would load the UI
597+
// and then watch it dial its own 127.0.0.1 for the backend. Worse,
598+
// sharing would overwrite VITE_DEV_SERVER_URL, which is the origin
599+
// Electron itself loads the renderer from. Refuse rather than hand out
600+
// a URL that is broken in a way the user cannot see.
601+
yield* Effect.logWarning(
602+
"[dev-runner] --share is not supported for dev:desktop (the renderer is pinned to loopback). Use `dev` or `dev:web`.",
603+
);
594604
} else {
595605
// acquireRelease, not share-then-addFinalizer: the mapping outlives this
596606
// process (and reboots), so the cleanup has to be registered atomically

0 commit comments

Comments
 (0)