UNPKG

vibe-coder-mcp

Version:

Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.

103 lines (102 loc) 4.65 kB
import path from 'path'; import logger from '../../logger.js'; export function normalizePath(inputPath, baseDirectory) { if (!inputPath) { throw new Error('Path cannot be empty or undefined'); } const normalizedPath = path.normalize(inputPath); if (normalizedPath.includes('temp/') && path.isAbsolute(normalizedPath)) { logger.debug(`Using test path as-is: ${normalizedPath}`); return normalizedPath; } const resolveBase = baseDirectory || process.cwd(); return path.isAbsolute(normalizedPath) ? normalizedPath : path.resolve(resolveBase, normalizedPath); } export function isPathWithin(childPath, parentPath) { const normalizedChild = normalizePath(childPath); const normalizedParent = normalizePath(parentPath); if (normalizedChild === normalizedParent) { return true; } const parentWithSep = normalizedParent.endsWith(path.sep) ? normalizedParent : normalizedParent + path.sep; return normalizedChild.startsWith(parentWithSep); } export function validatePathSecurity(inputPath, allowedDirectory) { try { if (!allowedDirectory || typeof allowedDirectory !== 'string' || allowedDirectory.trim() === '') { return { isValid: false, error: 'Security boundary violation: allowedDirectory must be explicitly provided by centralized configuration' }; } const normalizedPath = normalizePath(inputPath, allowedDirectory); const normalizedAllowedDir = normalizePath(allowedDirectory); if (!isPathWithin(normalizedPath, normalizedAllowedDir)) { return { isValid: false, error: `Access denied: Path '${inputPath}' is outside of the allowed directory '${allowedDirectory}'`, }; } return { isValid: true, normalizedPath, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { isValid: false, error: `Path validation error: ${errorMessage}`, }; } } export function createSecurePath(inputPath, allowedDirectory) { if (!inputPath || typeof inputPath !== 'string') { throw new Error('createSecurePath: inputPath must be a non-empty string'); } if (!allowedDirectory || typeof allowedDirectory !== 'string' || allowedDirectory.trim() === '') { logger.error({ inputPath, allowedDirectory, function: 'createSecurePath' }, 'Security boundary violation: allowedDirectory must be explicitly provided by centralized configuration'); throw new Error('Security boundary violation: allowedDirectory must be explicitly provided by centralized configuration. ' + 'Services must use centralized config-loader.ts to provide security boundaries.'); } const validationResult = validatePathSecurity(inputPath, allowedDirectory); if (!validationResult.isValid) { logger.error({ inputPath, allowedDirectory, error: validationResult.error }, 'Security violation: Attempted to access path outside allowed directory'); throw new Error(validationResult.error); } return validationResult.normalizedPath; } export function resolveSecurePath(relativePath, allowedDirectory) { if (!relativePath) { throw new Error('Path cannot be empty or undefined'); } if (!allowedDirectory || typeof allowedDirectory !== 'string' || allowedDirectory.trim() === '') { throw new Error('Security boundary violation: allowedDirectory must be explicitly provided by centralized configuration. ' + 'Services must use centralized config-loader.ts to provide security boundaries.'); } if (path.isAbsolute(relativePath)) { return createSecurePath(relativePath, allowedDirectory); } const resolvedPath = path.resolve(allowedDirectory, relativePath); return createSecurePath(resolvedPath, allowedDirectory); } export function getRelativePath(absolutePath, allowedDirectory) { if (!allowedDirectory || typeof allowedDirectory !== 'string' || allowedDirectory.trim() === '') { throw new Error('Security boundary violation: allowedDirectory must be explicitly provided by centralized configuration. ' + 'Services must use centralized config-loader.ts to provide security boundaries.'); } const securePath = createSecurePath(absolutePath, allowedDirectory); return path.relative(allowedDirectory, securePath); }