PRININIT / src /utils.ts
Rachit-Tw's picture
Upload 50 files
7d9309d verified
Raw
History Blame Contribute Delete
1.8 kB
import {execSync, ExecSyncOptions, spawnSync} from 'child_process'
import {als} from './context'
/**
* Executes a shell command using the current context's working directory.
* Thread-safe for Probot.
* @deprecated Use prixSpawn for new code to avoid RCE risks
*/
export const prixExec = (
command: string,
options: ExecSyncOptions = {}
): string => {
const context = als.getStore()
const cwd = options.cwd || context?.workingDir || process.cwd()
const result = execSync(command, {
...options,
cwd,
encoding: 'utf8'
})
return result ? result.toString() : ''
}
/**
* SAFER: Executes a command using spawn with argument array.
* Prevents shell injection by not using shell string interpolation.
* Thread-safe for Probot.
*/
export const prixSpawn = (
cmd: string,
args: string[] = [],
options: {cwd?: string; env?: NodeJS.ProcessEnv} = {}
): {stdout: string; stderr: string; status: number | null} => {
const context = als.getStore()
const cwd = options.cwd || context?.workingDir || process.cwd()
const result = spawnSync(cmd, args, {
cwd,
env: {...process.env, ...options.env},
encoding: 'utf8',
maxBuffer: 10 * 1024 * 1024 // 10MB buffer
})
return {
stdout: result.stdout || '',
stderr: result.stderr || '',
status: result.status
}
}
export const sleep = (ms: number): Promise<void> => {
return new Promise(resolve => setTimeout(resolve, ms))
}
/**
* Safely quotes a string for use in a shell command.
*/
export const quote = (s: string): string => {
if (process.platform === 'win32') {
// Windows PowerShell/CMD quoting
return `"${s.replace(/"/g, '""')}"`
}
// POSIX shell quoting
return `'${s.replace(/'/g, "'\\''")}'`
}