Skip to main content
Glama
exec.ts2.89 kB
/** * Safe command execution wrapper with security validation */ import { spawn } from 'child_process'; import { validateCommand } from '../security/commandValidator.js'; import { validateExecutionContext } from '../security/executionContextValidator.js'; import { DEFAULTS } from '../constants.js'; import type { ExecOptions, ExecResult } from '../types.js'; /** * Safely executes a command with validation and resource limits */ export async function safeExec( command: string, args: string[], options: ExecOptions = {} ): Promise<ExecResult> { const validation = validateCommand(command, args); if (!validation.isValid) { throw new Error(`Command validation failed: ${validation.error}`); } const contextValidation = validateExecutionContext(options.cwd); if (!contextValidation.isValid) { throw new Error( `Execution context validation failed: ${contextValidation.error}` ); } const timeout = options.timeout || DEFAULTS.COMMAND_TIMEOUT; const maxOutputSize = options.maxOutputSize || DEFAULTS.MAX_OUTPUT_SIZE; return new Promise((resolve, reject) => { const cleanup = () => {}; const child = spawn(command, args, { cwd: options.cwd, env: { ...process.env, ...options.env }, timeout, }); let stdout = ''; let stderr = ''; let killed = false; child.stdout.on('data', (data) => { stdout += data.toString(); if (stdout.length > maxOutputSize) { killed = true; child.kill(); cleanup(); reject( new Error(`Output size limit exceeded (${maxOutputSize} bytes)`) ); } }); child.stderr.on('data', (data) => { stderr += data.toString(); if (stderr.length > maxOutputSize) { killed = true; child.kill(); cleanup(); reject( new Error(`Error output size limit exceeded (${maxOutputSize} bytes)`) ); } }); child.on('error', (error) => { if (!killed) { cleanup(); reject(error); } }); child.on('close', (code) => { if (!killed) { cleanup(); resolve({ code, stdout, stderr, success: code === 0, }); } }); setTimeout(() => { if (child.exitCode === null) { killed = true; child.kill(); cleanup(); reject(new Error(`Command timeout after ${timeout}ms`)); } }, timeout); }); } /** * Executes a command and returns only stdout or throws on error */ export async function execSimple( command: string, args: string[], options: ExecOptions = {} ): Promise<string> { const result = await safeExec(command, args, options); if (!result.success) { throw new Error( `Command failed with code ${result.code}: ${result.stderr}` ); } return result.stdout; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bgauryy/local-explorer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server