diff --git a/scripts/smart-install.js b/scripts/smart-install.js index 77cfee11..5f24987d 100644 --- a/scripts/smart-install.js +++ b/scripts/smart-install.js @@ -12,7 +12,7 @@ */ import { existsSync, readFileSync, writeFileSync } from 'fs'; -import { execSync } from 'child_process'; +import { execSync, spawnSync } from 'child_process'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; @@ -270,13 +270,15 @@ async function main() { const pm2Command = existsSync(localPm2Cmd) ? localPm2Cmd : 'pm2'; const ecosystemPath = join(PLUGIN_ROOT, 'ecosystem.config.cjs'); - // shell: true required for Windows to handle quoted paths correctly - execSync(`"${pm2Command}" start "${ecosystemPath}"`, { + // Using spawnSync with array args to avoid command injection risks + const result = spawnSync(pm2Command, ['start', ecosystemPath], { cwd: PLUGIN_ROOT, stdio: 'pipe', - encoding: 'utf-8', - shell: true + encoding: 'utf-8' }); + if (result.status !== 0) { + throw new Error(result.stderr || 'PM2 start failed'); + } log('✅ Worker service started', colors.green); } catch (error) { diff --git a/src/shared/worker-utils.ts b/src/shared/worker-utils.ts index 7b8d0e49..ed12e68f 100644 --- a/src/shared/worker-utils.ts +++ b/src/shared/worker-utils.ts @@ -1,7 +1,7 @@ import path from "path"; import { homedir } from "os"; import { existsSync, readFileSync } from "fs"; -import { execSync } from "child_process"; +import { spawnSync } from "child_process"; import { getPackageRoot } from "./paths.js"; // Named constants for health checks @@ -63,13 +63,15 @@ async function startWorker(): Promise { // Start using PM2 with the ecosystem config // CRITICAL: Must set cwd to pluginRoot so PM2 starts from marketplace directory - // shell: true required for Windows to handle quoted paths correctly - execSync(`"${pm2Command}" start "${ecosystemPath}"`, { + // Using spawnSync with array args to avoid command injection risks + const result = spawnSync(pm2Command, ['start', ecosystemPath], { cwd: pluginRoot, stdio: 'pipe', - encoding: 'utf-8', - shell: true + encoding: 'utf-8' }); + if (result.status !== 0) { + throw new Error(result.stderr || 'PM2 start failed'); + } // Wait for worker to become healthy for (let i = 0; i < WORKER_STARTUP_RETRIES; i++) {