mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
fix: improve Cursor CLI implementation with type safety and security fixes
- Add getCliPath() public method to CursorProvider to avoid private field access - Add path validation to cursor-config routes to prevent traversal attacks - Add supportsVision field to CursorModelConfig (all false - CLI limitation) - Consolidate duplicate types in providers/types.ts (re-export from @automaker/types) - Add MCP servers warning log instead of error (not yet supported by Cursor CLI) - Fix debug log type safety (replace 'as any' with proper type narrowing) - Update docs to remove non-existent tier field, add supportsVision field - Remove outdated TODO comment in sdk-options.ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import path from 'path';
|
||||
import { CursorConfigManager } from '../../../providers/cursor-config-manager.js';
|
||||
import {
|
||||
CURSOR_MODEL_MAP,
|
||||
@@ -37,6 +38,27 @@ import {
|
||||
} from '../../../services/cursor-config-service.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
/**
|
||||
* Validate that a project path is safe (no path traversal)
|
||||
* @throws Error if path contains traversal sequences
|
||||
*/
|
||||
function validateProjectPath(projectPath: string): void {
|
||||
// Resolve to absolute path and check for traversal
|
||||
const resolved = path.resolve(projectPath);
|
||||
const normalized = path.normalize(projectPath);
|
||||
|
||||
// Check for obvious traversal attempts
|
||||
if (normalized.includes('..') || projectPath.includes('..')) {
|
||||
throw new Error('Invalid project path: path traversal not allowed');
|
||||
}
|
||||
|
||||
// Ensure the resolved path doesn't escape intended boundaries
|
||||
// by checking if it starts with the normalized path components
|
||||
if (!resolved.startsWith(path.resolve(normalized))) {
|
||||
throw new Error('Invalid project path: path traversal detected');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates handler for GET /api/setup/cursor-config
|
||||
* Returns current Cursor configuration and available models
|
||||
@@ -54,6 +76,9 @@ export function createGetCursorConfigHandler() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate path to prevent traversal attacks
|
||||
validateProjectPath(projectPath);
|
||||
|
||||
const configManager = new CursorConfigManager(projectPath);
|
||||
|
||||
res.json({
|
||||
@@ -88,6 +113,9 @@ export function createSetCursorDefaultModelHandler() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate path to prevent traversal attacks
|
||||
validateProjectPath(projectPath);
|
||||
|
||||
if (!model || !(model in CURSOR_MODEL_MAP)) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
@@ -127,6 +155,9 @@ export function createSetCursorModelsHandler() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate path to prevent traversal attacks
|
||||
validateProjectPath(projectPath);
|
||||
|
||||
if (!Array.isArray(models)) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
@@ -173,6 +204,11 @@ export function createGetCursorPermissionsHandler() {
|
||||
try {
|
||||
const projectPath = req.query.projectPath as string | undefined;
|
||||
|
||||
// Validate path if provided
|
||||
if (projectPath) {
|
||||
validateProjectPath(projectPath);
|
||||
}
|
||||
|
||||
// Get global config
|
||||
const globalConfig = await readGlobalConfig();
|
||||
|
||||
@@ -238,6 +274,8 @@ export function createApplyPermissionProfileHandler() {
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Validate path to prevent traversal attacks
|
||||
validateProjectPath(projectPath);
|
||||
await applyProfileToProject(projectPath, profileId);
|
||||
} else {
|
||||
await applyProfileGlobally(profileId);
|
||||
@@ -279,6 +317,9 @@ export function createSetCustomPermissionsHandler() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate path to prevent traversal attacks
|
||||
validateProjectPath(projectPath);
|
||||
|
||||
if (!permissions || !Array.isArray(permissions.allow) || !Array.isArray(permissions.deny)) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
@@ -324,6 +365,9 @@ export function createDeleteProjectPermissionsHandler() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate path to prevent traversal attacks
|
||||
validateProjectPath(projectPath);
|
||||
|
||||
await deleteProjectConfig(projectPath);
|
||||
|
||||
res.json({
|
||||
|
||||
@@ -24,10 +24,8 @@ export function createCursorStatusHandler() {
|
||||
provider.checkAuth(),
|
||||
]);
|
||||
|
||||
// Get CLI path from provider (using type assertion since cliPath is private)
|
||||
const cliPath = installed
|
||||
? (provider as unknown as { cliPath: string | null }).cliPath
|
||||
: null;
|
||||
// Get CLI path from provider using public accessor
|
||||
const cliPath = installed ? provider.getCliPath() : null;
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
|
||||
Reference in New Issue
Block a user