mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-11 09:42:15 +03:00
fix(build): lazy-resolve module-level fs paths to avoid Turbopack NFT whole-source trace (#9560)
This commit is contained in:
1
changelog.d/fixes/9560-turbopack-nft-guard.md
Normal file
1
changelog.d/fixes/9560-turbopack-nft-guard.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(build): lazy-resolve module-level fs paths to avoid Turbopack NFT whole-source trace (#9560)
|
||||
@@ -234,8 +234,12 @@ const urlPath =
|
||||
? decodeURIComponent(MITM_SERVER_URL.pathname.slice(1))
|
||||
: decodeURIComponent(MITM_SERVER_URL.pathname);
|
||||
|
||||
const cwdPath = path.join(process.cwd(), "src", "mitm", "server.cjs");
|
||||
const MITM_SERVER_PATH = fs.existsSync(cwdPath) ? cwdPath : urlPath;
|
||||
// Lazy-resolve to avoid module-level fs.existsSync + process.cwd() at module scope,
|
||||
// which causes Turbopack's NFT tracer to follow the path into the entire src/ tree.
|
||||
function resolveMitmServerPath(): string {
|
||||
const cwdPath = path.join(/* turbopackIgnore: true */ process.cwd(), "src", "mitm", "server.cjs");
|
||||
return fs.existsSync(cwdPath) ? cwdPath : urlPath;
|
||||
}
|
||||
|
||||
// Check if a PID is alive
|
||||
function isProcessAlive(pid: number): boolean {
|
||||
@@ -607,7 +611,7 @@ async function startMitmInternal(
|
||||
}
|
||||
}
|
||||
|
||||
serverProcess = spawn(process.execPath, [MITM_SERVER_PATH], {
|
||||
serverProcess = spawn(process.execPath, [resolveMitmServerPath()], {
|
||||
windowsHide: true,
|
||||
env: {
|
||||
...process.env,
|
||||
|
||||
@@ -528,9 +528,6 @@ const getExpectedParentPaths = (): string[] => {
|
||||
].filter(Boolean);
|
||||
};
|
||||
|
||||
// Cache expected parent paths at module startup (avoid recalculation on every checkKnownPath call)
|
||||
const EXPECTED_PARENT_PATHS = getExpectedParentPaths();
|
||||
|
||||
const getExtraPaths = () =>
|
||||
String(process.env.CLI_EXTRA_PATHS || "")
|
||||
.split(path.delimiter)
|
||||
@@ -820,7 +817,7 @@ export const checkKnownPath = async (commandPath: string) => {
|
||||
const isWithinExpected = await isLocationTrusted(
|
||||
commandPath,
|
||||
realPath,
|
||||
EXPECTED_PARENT_PATHS,
|
||||
getExpectedParentPaths(),
|
||||
isPathWithin,
|
||||
fs.realpath
|
||||
);
|
||||
|
||||
52
tests/unit/9560-turbopack-nft-lazy-module-fs.test.ts
Normal file
52
tests/unit/9560-turbopack-nft-lazy-module-fs.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import path from "node:path";
|
||||
|
||||
// The bug: module-level fs.existsSync(path.join(process.cwd(), ...)) calls cause
|
||||
// Turbopack's NFT tracer to follow paths into the entire src/ tree, producing
|
||||
// "Encountered unexpected file in NFT list" warnings during build.
|
||||
//
|
||||
// Fix: Move module-level fs/process.cwd calls to lazy functions so they are
|
||||
// invoked from route handlers (not at module scope), letting the NFT tracer
|
||||
// skip them during build.
|
||||
|
||||
describe("#9560 — Turbopack NFT guard: lazy module-level fs resolution", () => {
|
||||
it("MITM lazy resolver returns a non-empty string path", async () => {
|
||||
// resolveMitmServerPath() is not exported — test through the module's
|
||||
// startMitm-like path by exercising the lazy resolution indirectly.
|
||||
// Import the MITM module to verify it loads without module-level fs calls.
|
||||
const mitm = await import("../../src/mitm/manager.ts");
|
||||
// The module should export functions; just confirm it loaded cleanly.
|
||||
assert.ok(typeof mitm.startMitm === "function");
|
||||
assert.ok(typeof mitm.getMitmStatus === "function");
|
||||
});
|
||||
|
||||
it("cliRuntime exports known path check function", async () => {
|
||||
// Verify cliRuntime imports without module-level getExpectedParentPaths call.
|
||||
const cliRuntime = await import("../../src/shared/services/cliRuntime.ts");
|
||||
assert.ok(typeof cliRuntime.checkKnownPath === "function");
|
||||
});
|
||||
|
||||
it("known path check produces deterministic result for a known-bad input", async () => {
|
||||
const { checkKnownPath } = await import("../../src/shared/services/cliRuntime.ts");
|
||||
// A relative path is rejected without hitting any expected-parent-paths logic.
|
||||
const result = await checkKnownPath("../evil");
|
||||
assert.equal(result.installed, false);
|
||||
assert.equal(result.reason, "not_absolute");
|
||||
});
|
||||
|
||||
it("known path check rejects path with dangerous characters", async () => {
|
||||
const { checkKnownPath } = await import("../../src/shared/services/cliRuntime.ts");
|
||||
const result = await checkKnownPath("/tmp/foo;$PATH");
|
||||
assert.equal(result.installed, false);
|
||||
assert.equal(result.reason, "unsafe_path");
|
||||
});
|
||||
|
||||
it("getExpectedParentPathsCached returns same shape as direct call", async () => {
|
||||
// getExpectedParentPaths is module-internal, but we can indirectly verify
|
||||
// that cliRuntime's known-path logic reaches it by checking that absolute
|
||||
// paths to known-locations like /usr/bin/env resolve correctly.
|
||||
const { checkKnownPath } = await import("../../src/shared/services/cliRuntime.ts");
|
||||
await assert.doesNotReject(checkKnownPath("/usr/bin/env"));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user