-
Notifications
You must be signed in to change notification settings - Fork 670
fix(windows): eliminate console windows from proxy-internal identity & process lookups #1279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,7 +9,15 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { execFileSync } from "node:child_process"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { resolveTrustedWindowsPowerShellExe } from "../lib/windows-elevation"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { isProcessAlive, waitForExit } from "../lib/process-control"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentWindowsAccount, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parseWmicCreationDate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parseWmicListRecords, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resolveWmicExe, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wmicGetOwner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from "../lib/windows-wmic"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { readCodexCatalogPath } from "./catalog/parsing"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const STALE_CODEX_APP_SERVER_HINT = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -306,17 +314,61 @@ function listDarwinSnapshots(uid: number | undefined): ProcessSnapshot[] { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Windows snapshots scoped to the invoking user via Win32_Process GetOwner. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * PowerShell is the sole path: WMIC lacks reliable owner data and is disabled on | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * many Windows 11 installs; returning unscoped rows would contradict the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * current-user restart contract. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * WMIC is preferred when present (faster cold start, no .NET runtime) and the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * hidden PowerShell CIM enumeration is the fallback for hosts where WMIC is | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * absent (a deprecated optional component on modern Windows 11 images). Both | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * paths spawn with windowsHide: true — a console-less proxy presenting a child | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * console window is the v2.11.0 popup bug this enumeration must not revive. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * CIM instance methods must use Invoke-CimMethod (direct .GetOwner() calls fail). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Candidates are pre-filtered to Codex basename / code-mode-host command lines | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * so we do not pay GetOwner per every process on the machine. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Exported for the Windows integration regression that exercises the real | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * PowerShell enumeration. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * so we do not pay GetOwner per every process on the machine. A candidate | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * whose owner cannot be verified makes the whole enumeration incomplete; WMIC | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * absence falls back rather than failing. Exported for the Windows | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * integration regression. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function listWindowsSnapshots(): ProcessSnapshot[] { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const wmic = resolveWmicExe(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return wmic ? listWindowsSnapshotsViaWmic(wmic) : listWindowsSnapshotsViaPowerShell(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function listWindowsSnapshotsViaWmic(wmic: string): ProcessSnapshot[] { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const me = currentWindowsAccount(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!me) throw new Error("windows_enum_incomplete"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const wql = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "(Name like 'codex%' or CommandLine like '%codex app-server%' or CommandLine like '%codex-code-mode-host%')"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Top-level exec failure propagates (see listDarwinSnapshots note). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const output = execFileSync( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wmic, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ["process", "where", wql, "get", "ProcessId,CommandLine,CreationDate", "/format:list"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: 8_000, windowsHide: true }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const out: ProcessSnapshot[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const record of parseWmicListRecords(output)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!record.commandLine) continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const commandLine = record.commandLine.replace(/\t/g, " ").trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The WMIC helper's own CommandLine embeds the WQL literals ("codex | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // app-server", "codex-code-mode-host"), so it matches the candidate | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // pre-filter. Skip any process that is the WMIC executable itself. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (commandLine.toLowerCase().includes(wmic.toLowerCase())) continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isWindowsCodexCandidateCommandLine(commandLine)) continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const owner = wmicGetOwner(record.processId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // A candidate whose owner could not be verified makes the whole | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // enumeration incomplete — the staleness collector must not read the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // partial result as "nothing running". | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!owner) throw new Error("windows_enum_incomplete"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ownerName = `${owner.domain}\\${owner.user}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (ownerName.toLowerCase() !== me.toLowerCase()) continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out.push({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pid: record.processId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| commandLine, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner: ownerName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| startedAtMs: parseWmicCreationDate(record.creationDate) ?? undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return out; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function listWindowsSnapshotsViaPowerShell(): ProcessSnapshot[] { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const out: ProcessSnapshot[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Newlines keep -Command as a real script (space-joined statements need ';'). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Double-quoted format string so `t expands to a real tab. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -326,6 +378,7 @@ export function listWindowsSnapshots(): ProcessSnapshot[] { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // path with "opencodex". | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const basenameMatch = powerShellSingleQuotedIgnoreCaseMatch(WINDOWS_CODEX_BASENAME_CANDIDATE_RE.source); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const codeModeMatch = powerShellSingleQuotedIgnoreCaseMatch(WINDOWS_CODEX_CODE_MODE_HOST_CANDIDATE_RE.source); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // CIM instance methods must use Invoke-CimMethod (direct .GetOwner() calls fail). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const psCommand = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$ErrorActionPreference='SilentlyContinue'", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$me=[System.Security.Principal.WindowsIdentity]::GetCurrent().Name", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -346,7 +399,7 @@ export function listWindowsSnapshots(): ProcessSnapshot[] { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "}", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ].join("\n"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Top-level exec failure propagates (see listDarwinSnapshots note). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const output = execFileSync("powershell.exe", [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const output = execFileSync(resolveTrustedWindowsPowerShellExe(), [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "-NoProfile", "-NoLogo", "-NonInteractive", "-WindowStyle", "Hidden", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "-Command", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| psCommand, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -456,8 +509,24 @@ function readDarwinProcStartMs(pid: number): number | null { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Win32_Process.CreationDate → epoch ms, or null (Windows). */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function readWindowsProcStartMs(pid: number): number | null { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const wmic = resolveWmicExe(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!wmic) return readWindowsProcStartMsViaPowerShell(pid); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const out = execFileSync("powershell.exe", [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const out = execFileSync( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wmic, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ["process", "where", `ProcessId=${pid}`, "get", "CreationDate", "/format:list"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: 5_000, windowsHide: true }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const match = /^CreationDate=(.*)$/m.exec(out.replace(/\r/g, "")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return parseWmicCreationDate(match?.[1]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function readWindowsProcStartMsViaPowerShell(pid: number): number | null { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const out = execFileSync(resolveTrustedWindowsPowerShellExe(), [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "-NoProfile", "-NoLogo", "-NonInteractive", "-WindowStyle", "Hidden", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "-Command", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `(Get-CimInstance Win32_Process -Filter "ProcessId=${pid}").CreationDate.ToUniversalTime().ToString("o")`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -503,30 +572,32 @@ export function readProcessStartMsBatch( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const parsed = Date.parse(match[2]!.trim()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Number.isSafeInteger(pid) && Number.isFinite(parsed)) byPid.set(pid, parsed); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pid of pids) out.set(pid, byPid.get(pid) ?? null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pid of pids) if (!out.has(pid)) out.set(pid, null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return out; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pid of pids) out.set(pid, null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return out; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (platform === "win32") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const wmic = resolveWmicExe(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!wmic) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pid of pids) out.set(pid, null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return out; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const filter = pids.map(pid => `ProcessId=${pid}`).join(" OR "); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stdout = execFileSync("powershell.exe", [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "-NoProfile", "-NoLogo", "-NonInteractive", "-WindowStyle", "Hidden", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "-Command", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Get-CimInstance Win32_Process -Filter "${filter}" | ForEach-Object { "$($_.ProcessId)\t$($_.CreationDate.ToUniversalTime().ToString("o"))" }`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: 5_000, windowsHide: true }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const byPid = new Map<number, number>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const line of stdout.split(/\r?\n/)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const tab = line.indexOf("\t"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (tab <= 0) continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const pid = Number(line.slice(0, tab)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const parsed = Date.parse(line.slice(tab + 1).trim()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Number.isSafeInteger(pid) && Number.isFinite(parsed)) byPid.set(pid, parsed); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const filter = pids.map(pid => `ProcessId=${pid}`).join(" or "); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stdout = execFileSync( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wmic, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ["process", "where", filter, "get", "ProcessId,CreationDate", "/format:list"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: 5_000, windowsHide: true }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const record of parseWmicListRecords(stdout)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (record.creationDate !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out.set(record.processId, parseWmicCreationDate(record.creationDate)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pid of pids) out.set(pid, byPid.get(pid) ?? null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pid of pids) if (!out.has(pid)) out.set(pid, null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
582
to
+600
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win Chunk the WMIC batch filter and reject unusable PIDs before building the WQL. Two concrete failure modes exist in this branch:
Chunk the query and filter the PIDs first. The single-PID path at Lines 511-525 has the same lack of validation, but it fails in isolation there. 🛡️ Proposed chunking and validation try {
- const filter = pids.map(pid => `ProcessId=${pid}`).join(" or ");
- const stdout = execFileSync(
- wmic,
- ["process", "where", filter, "get", "ProcessId,CreationDate", "/format:list"],
- { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: 5_000, windowsHide: true },
- );
- for (const record of parseWmicListRecords(stdout)) {
- if (record.creationDate !== undefined) {
- out.set(record.processId, parseWmicCreationDate(record.creationDate));
- }
- }
+ const usable = pids.filter(pid => Number.isSafeInteger(pid) && pid > 1);
+ const WMIC_BATCH_SIZE = 200;
+ for (let i = 0; i < usable.length; i += WMIC_BATCH_SIZE) {
+ const chunk = usable.slice(i, i + WMIC_BATCH_SIZE);
+ const filter = chunk.map(pid => `ProcessId=${pid}`).join(" or ");
+ const stdout = execFileSync(
+ wmic,
+ ["process", "where", filter, "get", "ProcessId,CreationDate", "/format:list"],
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: 5_000, windowsHide: true },
+ );
+ for (const record of parseWmicListRecords(stdout)) {
+ if (record.creationDate !== undefined) {
+ out.set(record.processId, parseWmicCreationDate(record.creationDate));
+ }
+ }
+ }
for (const pid of pids) if (!out.has(pid)) out.set(pid, null);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return out; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pid of pids) out.set(pid, null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,10 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { execFile } from "node:child_process"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { basename } from "node:path"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { resolveTrustedWindowsPowerShellExe } from "../lib/windows-elevation"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resolveTrustedWindowsPowerShellExe, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resolveTrustedWindowsWmicExe, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from "../lib/windows-elevation"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { parseWmicListRecords } from "../lib/windows-wmic"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const PROCESS_LIST_MAX_BUFFER = 16 * 1024 * 1024; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const DIRECT_CODEX_BASENAMES = new Set(["codex", "codex.exe"]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -13,6 +17,9 @@ const CODEX_ENTRYPOINT_BASENAMES = new Set([ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "codex.ts", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const WINDOWS_CODEX_NAME_RE = /^(?:codex|codex\.exe)$/i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const WINDOWS_CODEX_CMDLINE_RE = /(?:^|[\\/"\s])codex(?:\.exe|\.cmd)?(?:["\s]|$)/i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface NativeProcessExecOptions { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| encoding: "utf8"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timeout: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -57,12 +64,67 @@ export const executeNativeProcess: NativeProcessExecutor = (file, args, options) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function windowsProcessCount(run: NativeProcessExecutor): Promise<number> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Count Codex processes on Windows. WMIC is preferred when present (faster | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * cold start, no .NET runtime); the hidden PowerShell CIM query is the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * fallback for hosts without WMIC (a deprecated optional component on modern | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Windows 11 images). Both paths run hidden (windowsHide) so a console-less | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * proxy never presents a child console window. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function windowsProcessCount(run: NativeProcessExecutor, selfPid: number): Promise<number> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const wmic = resolveTrustedWindowsWmicExe(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return wmic | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? windowsProcessCountViaWmic(run, wmic, selfPid) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : windowsProcessCountViaPowerShell(run, selfPid); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function windowsProcessCountViaWmic( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: NativeProcessExecutor, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wmic: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selfPid: number, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<number> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const output = await run(wmic, [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "process", "where", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "(Name like 'codex%' or CommandLine like '%codex%')", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "get", "ProcessId,Name,CommandLine", "/format:list", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| encoding: "utf8", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timeout: 12_000, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maxBuffer: PROCESS_LIST_MAX_BUFFER, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| windowsHide: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shell: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| killSignal: "SIGKILL", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const records = parseWmicListRecords(output); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // A valid enumeration always includes at least our own process (the proxy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // command line contains "opencodex"), so an empty result is a failure. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (records.length === 0) throw new Error("invalid process list"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let count = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const record of records) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (record.processId === selfPid) continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const nameMatch = record.name !== undefined && WINDOWS_CODEX_NAME_RE.test(record.name); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const commandLineMatch = record.commandLine !== undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| && WINDOWS_CODEX_CMDLINE_RE.test(record.commandLine); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (nameMatch || commandLineMatch) count += 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return count; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+98
to
+110
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Exclude the WMIC helper process explicitly rather than relying on quote characters. The WMIC child's own
🛡️ Proposed explicit exclusion for (const record of records) {
if (record.processId === selfPid) continue;
+ // WMIC's own CommandLine embeds the WQL "codex" literals, so skip it.
+ if (record.commandLine?.toLowerCase().includes(wmic.toLowerCase())) continue;
const nameMatch = record.name !== undefined && WINDOWS_CODEX_NAME_RE.test(record.name);📝 Committable suggestion
Suggested change
🧰 Tools🪛 ast-grep (0.45.0)[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec. (detect-child-process-typescript) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function windowsProcessCountViaPowerShell( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: NativeProcessExecutor, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selfPid: number, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<number> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const powershell = resolveTrustedWindowsPowerShellExe(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The script text itself contains "codex", so the PowerShell host process | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // matches the candidate filter and must be excluded ($self). The probing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // proxy (opencodex in its command line) is excluded by pid. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const selfFilter = Number.isSafeInteger(selfPid) && selfPid > 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? ` $_.ProcessId -ne ${selfPid} -and` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const script = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$ErrorActionPreference='Stop';", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$self=$PID;", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$items=Get-CimInstance Win32_Process | Where-Object { $_.ProcessId -ne $self -and ($_.Name -match '^(?i:codex)(?:\\.exe)?$' -or $_.CommandLine -match '(?i)(?:^|[\\\\/\"\\s])codex(?:\\.exe|\\.cmd)?(?:[\"\\s]|$)') };", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `$items=Get-CimInstance Win32_Process | Where-Object { $_.ProcessId -ne $self -and${selfFilter} ($_.Name -match '^(?i:codex)(?:\\.exe)?$' -or $_.CommandLine -match '(?i)(?:^|[\\\\/\"\\s])codex(?:\\.exe|\\.cmd)?(?:[\"\\s]|$)') };`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@($items).Count", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ].join(" "); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const output = (await run(powershell, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", script], { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -112,7 +174,7 @@ export async function probeNativeCodexProcesses({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: NativeCodexProcessProbeOptions = {}): Promise<NativeCodexProcessProbe> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const count = await (platform === "win32" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? windowsProcessCount(run) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? windowsProcessCount(run, pid) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : unixProcessCount(run, pid)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return count > 0 ? { status: "busy", count } : { status: "clear", count: 0 }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Fall back to PowerShell when the WMIC start-time query fails, not only when WMIC is absent.
Line 513 routes to
readWindowsProcStartMsViaPowerShellonly whenresolveWmicExe()returnsnull. If WMIC exists but the call fails (timeout on a contended host, WMI repository error,/format:listreturning noCreationDateline), thecatchat Line 522 returnsnulland the working PowerShell path is never tried. The caller then treats the process start time as unknown, which weakens the PID-reuse guard thatreadProcessStartMsexists to support.Reuse the fallback for both conditions.
🛡️ Proposed fallback on failure
📝 Committable suggestion
🧰 Tools
🪛 OpenGrep (1.26.0)
[ERROR] 520-520: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
🤖 Prompt for AI Agents