mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-16 20:22:21 +03:00
Compare commits
3 Commits
fix/10293-
...
fix/codeql
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af6813ca12 | ||
|
|
864e817eda | ||
|
|
ab36b35035 |
@@ -1 +0,0 @@
|
||||
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()` → `win32` guards the anti-fold invariant (RED before, GREEN after).
|
||||
@@ -15,15 +15,9 @@ const execFileAsync = promisify(execFile);
|
||||
|
||||
const WINDOWS_TAILSCALE_BIN = "C:\\Program Files\\Tailscale\\tailscale.exe";
|
||||
const WINDOWS_TAILSCALED_BIN = "C:\\Program Files\\Tailscale\\tailscaled.exe";
|
||||
|
||||
// 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 IS_MAC = process.platform === "darwin";
|
||||
const IS_LINUX = process.platform === "linux";
|
||||
const IS_WINDOWS = process.platform === "win32";
|
||||
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;
|
||||
@@ -41,7 +35,12 @@ 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;
|
||||
@@ -62,7 +61,8 @@ 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 = os.platform()) {
|
||||
function isSupportedPlatform(platform = process.platform) {
|
||||
return platform === "darwin" || platform === "linux" || platform === "win32";
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ function getTailscaleDir() {
|
||||
return path.join(resolveDataDir(), "tailscale");
|
||||
}
|
||||
|
||||
function getManagedBinaryPath(platform = os.platform()) {
|
||||
function getManagedBinaryPath(platform = process.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 = os.platform() === "win32" ? "where" : "which";
|
||||
const lookupCommand = process.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 (getCurrentPlatform() === "win32" && fs.existsSync(WINDOWS_TAILSCALE_BIN)) {
|
||||
if (IS_WINDOWS && 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 = os.platform() === "win32" ? "tailscaled.exe" : "tailscaled";
|
||||
const daemonFilename = process.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,8 +273,7 @@ async function resolveDaemonBinary(tailscaleBinaryPath: string | null) {
|
||||
const pathBinary = await resolvePathCommand("tailscaled");
|
||||
if (pathBinary) return pathBinary;
|
||||
|
||||
if (getCurrentPlatform() === "win32" && fs.existsSync(WINDOWS_TAILSCALED_BIN))
|
||||
return WINDOWS_TAILSCALED_BIN;
|
||||
if (IS_WINDOWS && fs.existsSync(WINDOWS_TAILSCALED_BIN)) return WINDOWS_TAILSCALED_BIN;
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -299,9 +298,7 @@ async function getActiveSocketPath(): Promise<string> {
|
||||
}
|
||||
|
||||
// Check system sockets first
|
||||
const platform = getCurrentPlatform();
|
||||
const systemSocket =
|
||||
platform === "linux" ? SYSTEM_SOCKET_LINUX : platform === "darwin" ? SYSTEM_SOCKET_MAC : null;
|
||||
const systemSocket = IS_LINUX ? SYSTEM_SOCKET_LINUX : IS_MAC ? SYSTEM_SOCKET_MAC : null;
|
||||
if (systemSocket && fs.existsSync(systemSocket)) {
|
||||
_cachedActiveSocket = systemSocket;
|
||||
_cachedActiveSocketTimestamp = now;
|
||||
@@ -317,9 +314,7 @@ async function getActiveSocketPath(): Promise<string> {
|
||||
|
||||
/** Synchronous check: is the system daemon socket available? */
|
||||
function isSystemDaemonAvailable(): boolean {
|
||||
const platform = getCurrentPlatform();
|
||||
const systemSocket =
|
||||
platform === "linux" ? SYSTEM_SOCKET_LINUX : platform === "darwin" ? SYSTEM_SOCKET_MAC : null;
|
||||
const systemSocket = IS_LINUX ? SYSTEM_SOCKET_LINUX : IS_MAC ? SYSTEM_SOCKET_MAC : null;
|
||||
return Boolean(systemSocket && fs.existsSync(systemSocket));
|
||||
}
|
||||
|
||||
@@ -346,20 +341,19 @@ export function tailscaleUpArgs(hostname?: string, authKey?: string): string[] {
|
||||
}
|
||||
|
||||
async function buildTailscaleArgs(...args: string[]) {
|
||||
if (getCurrentPlatform() === "win32") return args;
|
||||
if (IS_WINDOWS) return args;
|
||||
const socket = await getActiveSocketPath();
|
||||
return ["--socket", socket, ...args];
|
||||
}
|
||||
|
||||
/** Synchronous variant for places that cannot await */
|
||||
function buildTailscaleArgsSync(...args: string[]) {
|
||||
if (getCurrentPlatform() === "win32") return args;
|
||||
if (IS_WINDOWS) return args;
|
||||
// Use cached socket or default to system socket if available
|
||||
const platform = getCurrentPlatform();
|
||||
const socket =
|
||||
_cachedActiveSocket ||
|
||||
(isSystemDaemonAvailable()
|
||||
? platform === "linux"
|
||||
? IS_LINUX
|
||||
? SYSTEM_SOCKET_LINUX
|
||||
: SYSTEM_SOCKET_MAC
|
||||
: getTailscaleSocketPath());
|
||||
@@ -449,7 +443,7 @@ function getLastError(state: PersistedTailscaleState) {
|
||||
}
|
||||
|
||||
async function hasBrew() {
|
||||
if (getCurrentPlatform() !== "darwin") return false;
|
||||
if (!IS_MAC) return false;
|
||||
try {
|
||||
await execFileAsync("which", ["brew"], {
|
||||
timeout: 3000,
|
||||
@@ -493,7 +487,7 @@ export async function getTailscaleCheckStatus(): Promise<TailscaleCheckStatus> {
|
||||
running: isFunnelRunning(funnelPayload),
|
||||
tunnelUrl,
|
||||
apiUrl: getTailscaleApiUrl(tunnelUrl),
|
||||
platform: os.platform(),
|
||||
platform: process.platform,
|
||||
brewAvailable,
|
||||
lastError: getLastError(state),
|
||||
pid: await readPidFile(),
|
||||
@@ -567,7 +561,7 @@ export async function startTailscaleDaemon({
|
||||
return { started: false };
|
||||
}
|
||||
|
||||
if (getCurrentPlatform() === "win32") {
|
||||
if (IS_WINDOWS) {
|
||||
try {
|
||||
await execFileAsync("net", ["start", "Tailscale"], {
|
||||
timeout: 10000,
|
||||
@@ -822,7 +816,7 @@ export async function stopTailscaleDaemon({
|
||||
}
|
||||
}
|
||||
|
||||
if (getCurrentPlatform() !== "win32") {
|
||||
if (!IS_WINDOWS) {
|
||||
try {
|
||||
await execFileAsync("pkill", ["-x", "tailscaled"], {
|
||||
timeout: 3000,
|
||||
@@ -1161,7 +1155,7 @@ export async function installTailscale({
|
||||
onProgress?: (message: string) => void;
|
||||
} = {}) {
|
||||
if (!isSupportedPlatform()) {
|
||||
throw new Error(`Unsupported platform for Tailscale install: ${os.platform()}`);
|
||||
throw new Error(`Unsupported platform for Tailscale install: ${process.platform}`);
|
||||
}
|
||||
|
||||
const password = toNonEmptyString(sudoPassword) || getCachedPassword() || "";
|
||||
@@ -1173,13 +1167,13 @@ export async function installTailscale({
|
||||
const existingBinary = await resolveBinary();
|
||||
if (existingBinary.binaryPath) {
|
||||
onProgress?.("Tailscale is already installed.");
|
||||
} else if (getCurrentPlatform() === "win32") {
|
||||
} else if (IS_WINDOWS) {
|
||||
onProgress?.("Downloading and installing Tailscale for Windows...");
|
||||
await installTailscaleWindows(onProgress);
|
||||
} else if (getCurrentPlatform() === "darwin") {
|
||||
} else if (IS_MAC) {
|
||||
onProgress?.("Installing Tailscale on macOS...");
|
||||
await installTailscaleMac(password, onProgress);
|
||||
} else if (getCurrentPlatform() === "linux") {
|
||||
} else if (IS_LINUX) {
|
||||
onProgress?.("Installing Tailscale on Linux...");
|
||||
await installTailscaleLinux(password, onProgress);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const ROUTES = [
|
||||
|
||||
for (const route of ROUTES) {
|
||||
test(`${route.name} early-heartbeat gate uses the real stream resolver`, () => {
|
||||
const escapedBodyExpression = route.bodyExpression.replace(/[?.]/g, "\\$&");
|
||||
const escapedBodyExpression = route.bodyExpression.replace(/[.?\\]/g, "\\$&");
|
||||
assert.match(
|
||||
route.source,
|
||||
new RegExp(
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
// #10293 — anti-fold regression guard.
|
||||
//
|
||||
// The reported defect: Turbopack constant-folds module-load `process.platform` to the
|
||||
// BUILD machine's value (a non-Windows runner) and prunes every Windows branch as dead
|
||||
// code, so `dist` builds ship a tailscaleTunnel where the Windows paths are unreachable.
|
||||
// That cannot be reproduced in a unit test (no published `dist`, no Windows runner), so
|
||||
// this guard enforces the SOURCE invariant that makes the fold impossible: platform reads
|
||||
// go through the runtime call `os.platform()` (a bundler cannot fold an arbitrary function
|
||||
// call), never a module-load `process.platform` constant.
|
||||
//
|
||||
// If a future edit re-introduces `const IS_WINDOWS = process.platform === "win32"` (or any
|
||||
// module-scope direct `process.platform` read), the folded-build failure returns — this test
|
||||
// turns RED.
|
||||
|
||||
const modulePath = fileURLToPath(new URL("../../src/lib/tailscaleTunnel.ts", import.meta.url));
|
||||
const source = fs.readFileSync(modulePath, "utf8");
|
||||
|
||||
test("#10293: tailscaleTunnel reads platform at runtime via os.platform(), never a module-load process.platform constant", () => {
|
||||
const lines = source.split("\n");
|
||||
|
||||
// Any module-scope (non-function) direct read of process.platform is the foldable pattern.
|
||||
const foldable = lines.filter((line, idx) => {
|
||||
if (/process\.platform/.test(line) && !/^\s*\/\//.test(line)) {
|
||||
// allow it only inside a function body (runtime read — but prefer os.platform there too);
|
||||
// a module-load constant assignment at top level with process.platform is the defect.
|
||||
return line.includes("= process.platform") && idx < 60;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
assert.deepEqual(
|
||||
foldable,
|
||||
[],
|
||||
`module-load constant(s) reading process.platform reintroduced the foldable pattern: ${foldable.join(" | ")}`
|
||||
);
|
||||
|
||||
// The runtime getter must exist and delegate to os.platform (the anti-fold call).
|
||||
assert.match(source, /function getCurrentPlatform\(\):\s*NodeJS\.Platform\s*\{\s*return os\.platform\(\);?\s*\}/m);
|
||||
});
|
||||
|
||||
test("#10293: Windows branches use runtime platform reads, so they survive any build machine", () => {
|
||||
// These are the specific Windows behaviors the reporter found folded to dead code:
|
||||
// (a) --socket not injected (buildTailscaleArgs), (b) where over which (resolvePathCommand),
|
||||
// (c) windows-default binary fallback (resolveBinary). Each must read platform at runtime
|
||||
// through os.platform()/getCurrentPlatform().
|
||||
const socketBranch = /getCurrentPlatform\(\) === "win32"[\s\S]{0,80}return args/.test(source);
|
||||
const whereBranch = /os\.platform\(\) === "win32" \? "where" : "which"/.test(source);
|
||||
const windowsDefaultBranch = /getCurrentPlatform\(\) === "win32" && fs\.existsSync\(WINDOWS_TAILSCALE_BIN\)/.test(source);
|
||||
assert.ok(socketBranch, "buildTailscaleArgs must not inject --socket on win32 (runtime platform read)");
|
||||
assert.ok(whereBranch, "resolvePathCommand must select 'where' when os.platform() === 'win32'");
|
||||
assert.ok(windowsDefaultBranch, "resolveBinary must reach the Windows default binary fallback via runtime platform read");
|
||||
});
|
||||
Reference in New Issue
Block a user