diff --git a/eslint.config.mjs b/eslint.config.mjs index 664ef02d0..5e6b6a82c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -391,6 +391,42 @@ export default defineConfig([ ], }, }, + { + // Renderer process (frontend) architectural boundary - prevent Node.js API usage + files: ["src/**/*.ts", "src/**/*.tsx"], + ignores: [ + "src/main*.ts", + "src/preload.ts", + "src/services/**", + "src/runtime/**", + "src/utils/main/**", + "src/utils/providers/**", + "src/telemetry/**", + "src/git.ts", + "src/config.ts", + "src/debug/**", + "**/*.test.ts", + "**/*.test.tsx", + ], + rules: { + "no-restricted-globals": [ + "error", + { + name: "process", + message: + "Renderer code cannot access 'process' global (not available in renderer). Use IPC to communicate with main process or use constants for environment-agnostic values.", + }, + ], + "no-restricted-syntax": [ + "error", + { + selector: "MemberExpression[object.name='process'][property.name='env']", + message: + "Renderer code cannot access process.env (not available in renderer). Use IPC to get environment variables from main process or use constants.", + }, + ], + }, + }, { // Test file configuration files: ["**/*.test.ts", "**/*.test.tsx"], diff --git a/src/utils/chatCommands.test.ts b/src/utils/chatCommands.test.ts index 306838a5f..b72d92ba9 100644 --- a/src/utils/chatCommands.test.ts +++ b/src/utils/chatCommands.test.ts @@ -18,7 +18,7 @@ describe("parseRuntimeString", () => { expect(result).toEqual({ type: "ssh", host: "user@host", - srcBaseDir: "/home/user/cmux", + srcBaseDir: "~/cmux", }); }); @@ -27,7 +27,7 @@ describe("parseRuntimeString", () => { expect(result).toEqual({ type: "ssh", host: "User@Host.Example.Com", - srcBaseDir: "/home/User/cmux", + srcBaseDir: "~/cmux", }); }); @@ -36,7 +36,7 @@ describe("parseRuntimeString", () => { expect(result).toEqual({ type: "ssh", host: "user@host", - srcBaseDir: "/home/user/cmux", + srcBaseDir: "~/cmux", }); }); @@ -47,34 +47,31 @@ describe("parseRuntimeString", () => { test("accepts SSH with hostname only (user will be inferred)", () => { const result = parseRuntimeString("ssh hostname", workspaceName); - // When no user is specified, uses current user (process.env.USER) - const expectedUser = process.env.USER ?? "user"; - const expectedHomeDir = expectedUser === "root" ? "/root" : `/home/${expectedUser}`; + // Uses tilde path - backend will resolve it via runtime.resolvePath() expect(result).toEqual({ type: "ssh", host: "hostname", - srcBaseDir: `${expectedHomeDir}/cmux`, + srcBaseDir: "~/cmux", }); }); test("accepts SSH with hostname.domain only", () => { const result = parseRuntimeString("ssh dev.example.com", workspaceName); - // When no user is specified, uses current user (process.env.USER) - const expectedUser = process.env.USER ?? "user"; - const expectedHomeDir = expectedUser === "root" ? "/root" : `/home/${expectedUser}`; + // Uses tilde path - backend will resolve it via runtime.resolvePath() expect(result).toEqual({ type: "ssh", host: "dev.example.com", - srcBaseDir: `${expectedHomeDir}/cmux`, + srcBaseDir: "~/cmux", }); }); - test("uses /root for root user", () => { + test("uses tilde path for root user too", () => { const result = parseRuntimeString("ssh root@hostname", workspaceName); + // Backend will resolve ~ to /root for root user expect(result).toEqual({ type: "ssh", host: "root@hostname", - srcBaseDir: "/root/cmux", + srcBaseDir: "~/cmux", }); }); diff --git a/src/utils/chatCommands.ts b/src/utils/chatCommands.ts index dbd9fa140..710bcb7a9 100644 --- a/src/utils/chatCommands.ts +++ b/src/utils/chatCommands.ts @@ -51,20 +51,13 @@ export function parseRuntimeString( throw new Error("SSH runtime requires host (e.g., 'ssh hostname' or 'ssh user@host')"); } - // Extract username from user@host format, or default to current user - const atIndex = hostPart.indexOf("@"); - const user = atIndex > 0 ? hostPart.substring(0, atIndex) : (process.env.USER ?? "user"); - - // Determine home directory path based on user - // root user's home is /root, all others are /home/ - const homeDir = user === "root" ? "/root" : `/home/${user}`; - // Accept both "hostname" and "user@hostname" formats // SSH will use current user or ~/.ssh/config if user not specified + // Use tilde path - backend will resolve it via runtime.resolvePath() return { type: RUNTIME_MODE.SSH, host: hostPart, - srcBaseDir: `${homeDir}/cmux`, // Default remote base directory (NOT including workspace name) + srcBaseDir: "~/cmux", // Default remote base directory (tilde will be resolved by backend) }; }