fix(windows): use full path to where.exe for reliable executable lookup (#1659)
* fix(windows): use full path to where.exe for reliable executable lookup Use full path to where.exe (C:\Windows\System32\where.exe) instead of relying on it being in PATH. This fixes issues in restricted environments or when Electron doesn't inherit the full system PATH. Changes: - Export getWhereExePath() from windows-paths.ts as single source of truth - Update getWhichCommand() in paths.ts to use the shared helper - Fix shell injection vulnerability in release-handlers.ts by using execFileSync with array arguments instead of string template - Standardize SystemRoot env var fallback (check both SystemRoot and SYSTEMROOT variants) for consistency across all usages Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: resolve CI failures from outdated develop branch - Fix Ruff formatting in parallel_orchestrator_reviewer.py and pydantic_models.py - Fix test_integration_phase4.py to register module in sys.modules before exec_module for Python 3.12+ dataclass compatibility Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
This commit is contained in:
@@ -19,8 +19,7 @@ import { getWhichCommand } from '../../platform';
|
||||
*/
|
||||
function checkGhCli(): { installed: boolean; error?: string } {
|
||||
try {
|
||||
const checkCmd = `${getWhichCommand()} gh`;
|
||||
execSync(checkCmd, { encoding: 'utf-8', stdio: 'pipe' });
|
||||
execFileSync(getWhichCommand(), ['gh'], { encoding: 'utf-8', stdio: 'pipe' });
|
||||
return { installed: true };
|
||||
} catch {
|
||||
return {
|
||||
|
||||
@@ -9,6 +9,7 @@ import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import { existsSync, readdirSync } from 'fs';
|
||||
import { isWindows, isMacOS, getHomebrewPath, joinPaths, getExecutableExtension } from './index';
|
||||
import { getWhereExePath } from '../utils/windows-paths';
|
||||
|
||||
/**
|
||||
* Resolve Claude CLI executable path
|
||||
@@ -174,7 +175,7 @@ export function getWindowsShellPaths(): Record<string, string[]> {
|
||||
return {};
|
||||
}
|
||||
|
||||
const systemRoot = process.env.SystemRoot || 'C:\\Windows';
|
||||
const systemRoot = process.env.SystemRoot || process.env.SYSTEMROOT || 'C:\\Windows';
|
||||
|
||||
// Note: path.join('C:', 'foo') produces 'C:foo' (relative to C: drive), not 'C:\foo'
|
||||
// We must use 'C:\\' or raw paths like 'C:\\Program Files' to get absolute paths
|
||||
@@ -297,11 +298,14 @@ export function getOllamaInstallCommand(): string {
|
||||
/**
|
||||
* Get the command to find executables in PATH
|
||||
*
|
||||
* Windows: where.exe
|
||||
* Windows: Full path to where.exe (C:\Windows\System32\where.exe)
|
||||
* Using full path ensures it works even when System32 isn't in PATH,
|
||||
* which can happen in restricted environments or when Electron doesn't
|
||||
* inherit the full system PATH.
|
||||
* Unix: which
|
||||
*/
|
||||
export function getWhichCommand(): string {
|
||||
return isWindows() ? 'where.exe' : 'which';
|
||||
return isWindows() ? getWhereExePath() : 'which';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -130,6 +130,19 @@ export function getWindowsExecutablePaths(
|
||||
return validPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full path to where.exe.
|
||||
* Using the full path ensures where.exe works even when System32 isn't in PATH,
|
||||
* which can happen in restricted environments or when Electron doesn't inherit
|
||||
* the full system PATH.
|
||||
*
|
||||
* @returns Full path to where.exe (e.g., C:\Windows\System32\where.exe)
|
||||
*/
|
||||
export function getWhereExePath(): string {
|
||||
const systemRoot = process.env.SystemRoot || process.env.SYSTEMROOT || 'C:\\Windows';
|
||||
return path.join(systemRoot, 'System32', 'where.exe');
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a Windows executable using the `where` command.
|
||||
* This is the most reliable method as it searches:
|
||||
@@ -158,9 +171,10 @@ export function findWindowsExecutableViaWhere(
|
||||
}
|
||||
|
||||
try {
|
||||
// Use 'where' command to find the executable
|
||||
// where.exe is a built-in Windows command that finds executables
|
||||
const result = execFileSync('where.exe', [executable], {
|
||||
// Use full path to where.exe to ensure it works even when System32 isn't in PATH
|
||||
// This fixes issues in restricted environments or when Electron doesn't inherit system PATH
|
||||
const whereExe = getWhereExePath();
|
||||
const result = execFileSync(whereExe, [executable], {
|
||||
encoding: 'utf-8',
|
||||
timeout: 5000,
|
||||
windowsHide: true,
|
||||
@@ -261,9 +275,10 @@ export async function findWindowsExecutableViaWhereAsync(
|
||||
}
|
||||
|
||||
try {
|
||||
// Use 'where' command to find the executable
|
||||
// where.exe is a built-in Windows command that finds executables
|
||||
const { stdout } = await execFileAsync('where.exe', [executable], {
|
||||
// Use full path to where.exe to ensure it works even when System32 isn't in PATH
|
||||
// This fixes issues in restricted environments or when Electron doesn't inherit system PATH
|
||||
const whereExe = getWhereExePath();
|
||||
const { stdout } = await execFileAsync(whereExe, [executable], {
|
||||
encoding: 'utf-8',
|
||||
timeout: 5000,
|
||||
windowsHide: true,
|
||||
|
||||
Reference in New Issue
Block a user