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
JavaScript
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);
}