Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/desktop
Steps to reproduce
- In a checkout with dependencies installed, create a disposable directory and put the following executable named
tailscalein it. This hand-written fixture follows Tailscale'sipn/ipnstateJSON field format; the hostname and address are examples, not a recorded node.
#!/bin/sh
if [ "$1" = status ] && [ "$2" = --json ]; then
printf '%s\n' '{"BackendState":"Running","Self":{"DNSName":"desktop.example.ts.net.","TailscaleIPs":["100.64.0.10"],"CapMap":{"https":[]}}}'
exit 0
fi
printf '%s\n' 'unexpected fake tailscale command' >&2
exit 64- Make it executable and prepend its containing directory to PATH for the test command only. Save the following temporary test as
apps/desktop/src/backend/zz-agentC-tailscale.test.ts.
import { assert, describe, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as NodeServices from "@effect/platform-node/NodeServices";
import { HttpClient, HttpClientResponse } from "effect/http";
import { resolveTailscaleAdvertisedEndpoints } from "./tailscaleEndpointProvider.ts";
const networkInterfaces = {
tailscale0: [{ address: "100.64.0.10", family: "IPv4", internal: false }],
};
describe("agent C desktop Tailscale probe", () => {
for (const [name, body, status] of [
["unrelated HTML application", "<!doctype html><title>Other application</title>", 200],
["empty response", "", 204],
["not found control", "not found", 404],
] as const) {
it.live(name, () => Effect.gen(function* () {
const requests: string[] = [];
const endpoints = yield* resolveTailscaleAdvertisedEndpoints({
port: 3773,
serveEnabled: true,
networkInterfaces,
}).pipe(Effect.provideService(HttpClient.HttpClient, HttpClient.make((request) => {
requests.push(request.url);
return Effect.succeed(HttpClientResponse.fromWeb(request, new Response(status === 204 ? null : body, { status })));
})));
const https = endpoints.find((endpoint) => endpoint.label === "Tailscale HTTPS")!;
console.log(JSON.stringify({ case: name, requests, https: { status: https.status, compatibility: https.compatibility, url: https.httpBaseUrl } }));
assert.equal(https.status, "unavailable", "An unrelated application must not be advertised as a working T3 HTTPS endpoint");
assert.deepEqual(requests, ["https://desktop.example.ts.net/.well-known/t3/environment"]);
}).pipe(Effect.provide(NodeServices.layer)));
}
});- Run
pnpm --dir apps/desktop exec vp test run src/backend/zz-agentC-tailscale.test.ts. The observed run usednpx -y pnpm@12.14.0in place ofpnpm. Delete the temporary test and fake CLI afterward.
Observed result: the HTML/200 and empty/204 cases both fail because actual status is available; the 404 control passes. This failure comparison was run once for each case. An earlier observation run asserted the current status values and passed all three cases. The two existing suites tailscaleEndpointProvider.test.ts and DesktopServerExposure.test.ts also passed all 15 existing tests in the failure-comparison run.
Expected behavior
A URL that returns unrelated HTML or an empty response must not be advertised as an available T3 HTTPS pairing endpoint. The remote-access guide's Tailscale HTTPS section promises a route to this backend, and ConnectionsSettings uses available endpoints for pairing. Reachability of another HTTP application does not establish that contract.
Restoration check: with the same fixture, unrelated HTML/200 and empty/204 remain unavailable for T3 pairing, 404 remains unavailable, and a correctly configured T3 discovery endpoint remains available. The exact verification mechanism is left to the implementer.
Actual behavior
With Tailscale Serve enabled, the desktop endpoint provider advertises the MagicDNS URL as available and hosted-web-compatible when /.well-known/t3/environment returns an unrelated HTML document with HTTP 200, or no document with HTTP 204. Neither response contains a T3 discovery descriptor. This was observed by running the production desktop provider with a fake tailscale executable on PATH and the package's injectable Effect HTTP transport; no installed desktop app or real Tailscale daemon was used.
The supported UI path is source-traced: desktop IPC getAdvertisedEndpoints calls DesktopServerExposure.getAdvertisedEndpoints, which passes the saved Serve setting to this provider. ConnectionsSettings uses the resulting available value to check the Tailscale HTTPS switch and allows that endpoint as a pairing target, including when Network access is off. The UI itself was not launched.
Impact
Minor bug or occasional failure.
Impact: P2 - A misdirected Serve mapping can appear healthy and be offered for sharing even though it cannot connect clients to T3. The provider failure is deterministic for the tested responses; its incidence on real installations was not measured.
The triggering state can arise when a user changes an existing Serve mapping while the desktop remains running, or when setup leaves a pre-existing application on the selected HTTPS port. Those live lifecycle sequences were not run. NOT_ENOUGH_INFO: an integrated desktop/tailscaled reproduction and a verified recovery sequence were not run; they would establish live frequency and a tested workaround. The report concerns endpoint validation, not ownership or automatic repair of Serve mappings.
Version or commit
Commit c0c7405b04148f7fa3de5352d0e0aa149806c040; desktop package version 0.1.9.
Environment
Linux x86_64, Node v26.13.1, repository-pinned Effect 4.1.2, Vite+ test runner v5.0.5. Tailscale is not installed; CLI output was supplied by the fake executable above, and HTTP responses by the test transport. Other operating systems were not run.
Logs or stack traces
Interface
UI: desktop Settings → Sharing & access → Tailscale HTTPS and pairing endpoints; observed at its production endpoint-provider boundary.
Earliest failure stage
Integration or transport
Evidence
- Expected source:
docs/user/remote-access.md, Tailscale HTTPS;apps/web/src/components/settings/ConnectionsSettings.tsx:705-722selects the HTTPS endpoint for pairing when Network access is off. - Failure source: the executed test above returns
availableandcompatibility.hostedHttpsApp: compatiblefor both non-T3 responses. - Evidence provenance: observed, using a fake CLI and injected HTTP responses. UI reachability and consequences are established by source inspection.
- Local verification: reproduced at the endpoint-provider boundary; no real desktop or daemon session was launched.
- Reproduction completeness: complete for the endpoint-provider failure; the live-app lifecycle sequence is untested as stated above.
HTML application: GET https://desktop.example.ts.net/.well-known/t3/environment -> 200 HTML
https.status = available
https.compatibility.hostedHttpsApp = compatible
Empty response: GET https://desktop.example.ts.net/.well-known/t3/environment -> 204
https.status = available
https.compatibility.hostedHttpsApp = compatible
AssertionError: expected 'available' to equal 'unavailable'
Test Files: 1 failed | 2 passed (3)
Tests: 2 failed | 16 passed (18)
The fake status fixture is based on Tailscale's status schema. No identifying values were taken from a real machine.
Analysis
Source: the shared probe accepts any 2xx status without reading the response body. The desktop provider converts that boolean into available and hosted-compatible. The sharing row displays it as enabled. These source links explain the observed provider result; no claim about real-world frequency is made.
Additional context and references
Related issue 14746 concerns a failed local DNS probe hiding configured intent; this report concerns a successful HTTP response that is not T3 discovery. Issue 10363 concerns claiming and reconciling shared Serve mappings, while this report's closure is rejecting a non-T3 response even if the mapping is intentionally managed elsewhere. Issue 16238 concerns surfacing or retrying a failed Serve command. None needs to be fixed before this response-validation test can be verified.
Prepared by Codex (gpt-6.1-sol) in T3 Code from source inspection and the isolated test above; not generated by t3 triage.
Workaround
No live workaround was verified. Using another correctly configured direct route is a possible bypass; the test did not exercise it.
Activity