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:
VDT-91
2026-02-04 12:18:02 +01:00
committed by GitHub
parent e6e8da17c8
commit 5f63daa3cc
3 changed files with 29 additions and 11 deletions
@@ -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 {
+7 -3
View File
@@ -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';
}
/**
+21 -6
View File
@@ -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,