t3-code-android-nightly/apps/desktop/scripts/verify-preload-bundle.mjs
Dara Adedeji d1a6448971
fix(web): dropped folders become path chips on the local environment and are refused on remote ones (#12001)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 13:28:28 -07:00

151 lines
4.8 KiB
JavaScript

import * as NodeEvents from "node:events";
import * as NodeFS from "node:fs";
import * as NodeFSP from "node:fs/promises";
import * as NodeTimers from "node:timers";
import * as NodeURL from "node:url";
import * as NodeVM from "node:vm";
import { parse } from "acorn";
const expectedDesktopBridgeApis = [
"getClientPlatform",
"getLocalEnvironmentBootstraps",
"getPathForFile",
"pickFolder",
];
const clerkPasskeysGlobal = "__clerk_internal_electron_passkeys";
const preloadExecutionTimeoutMs = 1_000;
const desktopPackage = JSON.parse(
NodeFS.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
);
const electronVersion = desktopPackage.dependencies.electron;
const isSyntaxNode = (value) =>
typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
const inspectBundle = (source) => {
const runtimeImports = [];
const visit = (node) => {
if (node.type === "ImportExpression") {
throw new Error("Desktop preload bundle contains a dynamic import() call");
}
if (node.type === "CallExpression" && node.callee.type === "Identifier") {
if (node.callee.name === "require") {
const [argument] = node.arguments;
if (node.arguments.length !== 1 || argument?.type !== "Literal") {
throw new Error("Desktop preload bundle contains a dynamic require() call");
}
if (typeof argument.value !== "string") {
throw new Error("Desktop preload bundle contains a dynamic require() call");
}
runtimeImports.push(argument.value);
}
}
for (const child of Object.values(node)) {
if (Array.isArray(child)) {
for (const item of child) {
if (isSyntaxNode(item)) visit(item);
}
} else if (isSyntaxNode(child)) {
visit(child);
}
}
};
visit(parse(source, { ecmaVersion: "latest", sourceType: "script" }));
return runtimeImports;
};
const createSandboxModules = (exposedGlobals) => {
const ipcRenderer = {
invoke: () => Promise.resolve(undefined),
on: () => undefined,
removeListener: () => undefined,
sendSync: () => undefined,
};
const electron = {
contextBridge: {
exposeInMainWorld: (name, api) => exposedGlobals.set(name, api),
},
ipcRenderer,
webUtils: {
getPathForFile: () => "",
},
};
return new Map([
["electron", electron],
["electron/common", electron],
["electron/renderer", electron],
["events", NodeEvents.default],
["node:events", NodeEvents.default],
["timers", NodeTimers.default],
["node:timers", NodeTimers.default],
["url", NodeURL.default],
["node:url", NodeURL.default],
]);
};
const executeBundle = (source, sandboxModules) => {
const sandboxProcess = {
contextIsolated: true,
// oxlint-disable-next-line t3code/no-global-process-runtime -- This standalone CI verifier supplies the preload's host platform without loading Effect.
platform: process.platform,
versions: { electron: electronVersion },
};
const requireSandboxModule = (moduleName) => {
if (!sandboxModules.has(moduleName)) {
throw new Error(
`Unsupported sandbox module requested during preload execution: ${moduleName}`,
);
}
return sandboxModules.get(moduleName);
};
NodeVM.runInNewContext(
source,
{
process: sandboxProcess,
require: requireSandboxModule,
},
{
filename: "desktop-preload.cjs",
timeout: preloadExecutionTimeoutMs,
},
);
};
export const verifyPreloadBundle = (source) => {
const runtimeImports = inspectBundle(source);
const exposedGlobals = new Map();
const sandboxModules = createSandboxModules(exposedGlobals);
const unsupportedImports = [...new Set(runtimeImports)]
.filter((moduleName) => !sandboxModules.has(moduleName))
.toSorted();
if (unsupportedImports.length > 0) {
throw new Error(
`Desktop preload bundle contains unsupported sandbox imports: ${unsupportedImports.join(", ")}`,
);
}
executeBundle(source, sandboxModules);
const desktopBridge = exposedGlobals.get("desktopBridge");
const missingApis = expectedDesktopBridgeApis.filter(
(api) => typeof desktopBridge?.[api] !== "function",
);
if (!exposedGlobals.has("desktopBridge")) missingApis.unshift("desktopBridge exposure");
if (!exposedGlobals.has(clerkPasskeysGlobal)) missingApis.push(`${clerkPasskeysGlobal} exposure`);
if (missingApis.length > 0) {
throw new Error(`Desktop preload bundle is missing executable APIs: ${missingApis.join(", ")}`);
}
};
if (process.argv[1] && NodeURL.pathToFileURL(process.argv[1]).href === import.meta.url) {
const preloadUrl = new URL("../dist-electron/preload.cjs", import.meta.url);
const source = await NodeFSP.readFile(preloadUrl, "utf8");
verifyPreloadBundle(source);
}