fix(startup): read platform at runtime via os.platform() so Windows Tailscale branches survive bundle DCE (#10293)

This commit is contained in:
adevwithpurpose
2026-08-15 19:10:13 -03:00
parent ee221d870c
commit 7695131dcb
3 changed files with 94 additions and 30 deletions

View File

@@ -15,9 +15,15 @@ const execFileAsync = promisify(execFile);
const WINDOWS_TAILSCALE_BIN = "C:\\Program Files\\Tailscale\\tailscale.exe";
const WINDOWS_TAILSCALED_BIN = "C:\\Program Files\\Tailscale\\tailscaled.exe";
const IS_MAC = process.platform === "darwin";
const IS_LINUX = process.platform === "linux";
const IS_WINDOWS = process.platform === "win32";
// Runtime platform getter. A bundler (Turbopack in `next build`) constant-folds
// `process.platform` to the BUILD machine's value on a non-Windows runner and prunes
// the other branches as dead code (#10293). `os.platform()` is a runtime call a
// bundler cannot fold, so Windows/macOS/Linux branches survive on any build machine.
function getCurrentPlatform(): NodeJS.Platform {
return os.platform();
}
const EXTENDED_PATH = `/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:${process.env.PATH || ""}`;
const LOGIN_TIMEOUT_MS = 15000;
const FUNNEL_TIMEOUT_MS = 30000;
@@ -35,12 +41,7 @@ type JsonRecord = Record<string, unknown>;
export type TailscaleTunnelInstallSource = "managed" | "path" | "env" | "windows-default";
export type TailscaleTunnelPhase =
| "unsupported"
| "not_installed"
| "needs_login"
| "stopped"
| "running"
| "error";
"unsupported" | "not_installed" | "needs_login" | "stopped" | "running" | "error";
type PersistedTailscaleState = {
binaryPath?: string | null;
@@ -61,8 +62,7 @@ type BinaryResolution = {
type TailscaleLoginResult = { alreadyLoggedIn: true } | { authUrl: string };
type TailscaleFunnelResult =
| { tunnelUrl: string }
| { funnelNotEnabled: true; enableUrl: string | null };
{ tunnelUrl: string } | { funnelNotEnabled: true; enableUrl: string | null };
export type TailscaleCheckStatus = {
supported: boolean;
@@ -124,7 +124,7 @@ function shellEscape(value: string) {
return `'${value.replace(/'/g, `'\"'\"'`)}'`;
}
function isSupportedPlatform(platform = process.platform) {
function isSupportedPlatform(platform = os.platform()) {
return platform === "darwin" || platform === "linux" || platform === "win32";
}
@@ -132,7 +132,7 @@ function getTailscaleDir() {
return path.join(resolveDataDir(), "tailscale");
}
function getManagedBinaryPath(platform = process.platform) {
function getManagedBinaryPath(platform = os.platform()) {
return path.join(getTailscaleDir(), "bin", platform === "win32" ? "tailscale.exe" : "tailscale");
}
@@ -212,7 +212,7 @@ function getTailscaleApiUrl(tunnelUrl: string | null) {
}
async function resolvePathCommand(command: string) {
const lookupCommand = process.platform === "win32" ? "where" : "which";
const lookupCommand = os.platform() === "win32" ? "where" : "which";
try {
const { stdout } = await execFileAsync(lookupCommand, [command], {
timeout: 3000,
@@ -248,7 +248,7 @@ async function resolveBinary(): Promise<BinaryResolution> {
return { binaryPath: pathBinary, installSource: "path", managedInstall: false };
}
if (IS_WINDOWS && fs.existsSync(WINDOWS_TAILSCALE_BIN)) {
if (getCurrentPlatform() === "win32" && fs.existsSync(WINDOWS_TAILSCALE_BIN)) {
return {
binaryPath: WINDOWS_TAILSCALE_BIN,
installSource: "windows-default",
@@ -263,7 +263,7 @@ async function resolveDaemonBinary(tailscaleBinaryPath: string | null) {
const envPath = toNonEmptyString(process.env.TAILSCALED_BIN);
if (envPath && fs.existsSync(envPath)) return envPath;
const daemonFilename = process.platform === "win32" ? "tailscaled.exe" : "tailscaled";
const daemonFilename = os.platform() === "win32" ? "tailscaled.exe" : "tailscaled";
const siblingDir = tailscaleBinaryPath ? path.dirname(tailscaleBinaryPath) : null;
// path.format avoids the path.join/resolve pattern flagged by CWE-22 linters;
// siblingDir is path.dirname of a trusted system binary from resolveBinary(), not user input.
@@ -273,7 +273,8 @@ async function resolveDaemonBinary(tailscaleBinaryPath: string | null) {
const pathBinary = await resolvePathCommand("tailscaled");
if (pathBinary) return pathBinary;
if (IS_WINDOWS && fs.existsSync(WINDOWS_TAILSCALED_BIN)) return WINDOWS_TAILSCALED_BIN;
if (getCurrentPlatform() === "win32" && fs.existsSync(WINDOWS_TAILSCALED_BIN))
return WINDOWS_TAILSCALED_BIN;
return null;
}
@@ -298,7 +299,9 @@ async function getActiveSocketPath(): Promise<string> {
}
// Check system sockets first
const systemSocket = IS_LINUX ? SYSTEM_SOCKET_LINUX : IS_MAC ? SYSTEM_SOCKET_MAC : null;
const platform = getCurrentPlatform();
const systemSocket =
platform === "linux" ? SYSTEM_SOCKET_LINUX : platform === "darwin" ? SYSTEM_SOCKET_MAC : null;
if (systemSocket && fs.existsSync(systemSocket)) {
_cachedActiveSocket = systemSocket;
_cachedActiveSocketTimestamp = now;
@@ -314,7 +317,9 @@ async function getActiveSocketPath(): Promise<string> {
/** Synchronous check: is the system daemon socket available? */
function isSystemDaemonAvailable(): boolean {
const systemSocket = IS_LINUX ? SYSTEM_SOCKET_LINUX : IS_MAC ? SYSTEM_SOCKET_MAC : null;
const platform = getCurrentPlatform();
const systemSocket =
platform === "linux" ? SYSTEM_SOCKET_LINUX : platform === "darwin" ? SYSTEM_SOCKET_MAC : null;
return Boolean(systemSocket && fs.existsSync(systemSocket));
}
@@ -341,19 +346,20 @@ export function tailscaleUpArgs(hostname?: string, authKey?: string): string[] {
}
async function buildTailscaleArgs(...args: string[]) {
if (IS_WINDOWS) return args;
if (getCurrentPlatform() === "win32") return args;
const socket = await getActiveSocketPath();
return ["--socket", socket, ...args];
}
/** Synchronous variant for places that cannot await */
function buildTailscaleArgsSync(...args: string[]) {
if (IS_WINDOWS) return args;
if (getCurrentPlatform() === "win32") return args;
// Use cached socket or default to system socket if available
const platform = getCurrentPlatform();
const socket =
_cachedActiveSocket ||
(isSystemDaemonAvailable()
? IS_LINUX
? platform === "linux"
? SYSTEM_SOCKET_LINUX
: SYSTEM_SOCKET_MAC
: getTailscaleSocketPath());
@@ -443,7 +449,7 @@ function getLastError(state: PersistedTailscaleState) {
}
async function hasBrew() {
if (!IS_MAC) return false;
if (getCurrentPlatform() !== "darwin") return false;
try {
await execFileAsync("which", ["brew"], {
timeout: 3000,
@@ -487,7 +493,7 @@ export async function getTailscaleCheckStatus(): Promise<TailscaleCheckStatus> {
running: isFunnelRunning(funnelPayload),
tunnelUrl,
apiUrl: getTailscaleApiUrl(tunnelUrl),
platform: process.platform,
platform: os.platform(),
brewAvailable,
lastError: getLastError(state),
pid: await readPidFile(),
@@ -561,7 +567,7 @@ export async function startTailscaleDaemon({
return { started: false };
}
if (IS_WINDOWS) {
if (getCurrentPlatform() === "win32") {
try {
await execFileAsync("net", ["start", "Tailscale"], {
timeout: 10000,
@@ -816,7 +822,7 @@ export async function stopTailscaleDaemon({
}
}
if (!IS_WINDOWS) {
if (getCurrentPlatform() !== "win32") {
try {
await execFileAsync("pkill", ["-x", "tailscaled"], {
timeout: 3000,
@@ -1155,7 +1161,7 @@ export async function installTailscale({
onProgress?: (message: string) => void;
} = {}) {
if (!isSupportedPlatform()) {
throw new Error(`Unsupported platform for Tailscale install: ${process.platform}`);
throw new Error(`Unsupported platform for Tailscale install: ${os.platform()}`);
}
const password = toNonEmptyString(sudoPassword) || getCachedPassword() || "";
@@ -1167,13 +1173,13 @@ export async function installTailscale({
const existingBinary = await resolveBinary();
if (existingBinary.binaryPath) {
onProgress?.("Tailscale is already installed.");
} else if (IS_WINDOWS) {
} else if (getCurrentPlatform() === "win32") {
onProgress?.("Downloading and installing Tailscale for Windows...");
await installTailscaleWindows(onProgress);
} else if (IS_MAC) {
} else if (getCurrentPlatform() === "darwin") {
onProgress?.("Installing Tailscale on macOS...");
await installTailscaleMac(password, onProgress);
} else if (IS_LINUX) {
} else if (getCurrentPlatform() === "linux") {
onProgress?.("Installing Tailscale on Linux...");
await installTailscaleLinux(password, onProgress);
}