feat(delete): enhance branch deletion handling and validation

- Introduced a flag to track if a branch was successfully deleted, improving response clarity.
- Updated the response structure to include the new branchDeleted flag.
- Enhanced projectPath validation in init-script to ensure it is a non-empty string before processing.
This commit is contained in:
Shirone
2026-01-12 19:09:25 +01:00
parent cebf57ffd3
commit f50520c93f
3 changed files with 23 additions and 5 deletions

View File

@@ -57,6 +57,7 @@ export function createDeleteHandler() {
}
// Optionally delete the branch
let branchDeleted = false;
if (deleteBranch && branchName && branchName !== 'main' && branchName !== 'master') {
// Validate branch name to prevent command injection
if (!isValidBranchName(branchName)) {
@@ -64,8 +65,10 @@ export function createDeleteHandler() {
} else {
try {
await execGitCommand(['branch', '-D', branchName], projectPath);
branchDeleted = true;
} catch {
// Branch deletion failed, not critical
logger.warn(`Failed to delete branch: ${branchName}`);
}
}
}
@@ -74,7 +77,8 @@ export function createDeleteHandler() {
success: true,
deleted: {
worktreePath,
branch: deleteBranch ? branchName : null,
branch: branchDeleted ? branchName : null,
branchDeleted,
},
});
} catch (error) {

View File

@@ -36,9 +36,10 @@ function getInitScriptPath(projectPath: string): string {
export function createGetInitScriptHandler() {
return async (req: Request, res: Response): Promise<void> => {
try {
const projectPath = req.query.projectPath as string;
const rawProjectPath = req.query.projectPath;
if (!projectPath) {
// Validate projectPath is a non-empty string (not an array or undefined)
if (!rawProjectPath || typeof rawProjectPath !== 'string') {
res.status(400).json({
success: false,
error: 'projectPath query parameter is required',
@@ -46,6 +47,15 @@ export function createGetInitScriptHandler() {
return;
}
const projectPath = rawProjectPath.trim();
if (!projectPath) {
res.status(400).json({
success: false,
error: 'projectPath cannot be empty',
});
return;
}
const scriptPath = getInitScriptPath(projectPath);
try {

View File

@@ -63,7 +63,7 @@ interface BacklogPlanDialogProps {
setPendingPlanResult: (result: BacklogPlanResult | null) => void;
isGeneratingPlan: boolean;
setIsGeneratingPlan: (generating: boolean) => void;
// Branch to use for created features (defaults to main if not provided)
// Branch to use for created features (defaults to 'main' when applying)
currentBranch?: string;
}
@@ -170,7 +170,11 @@ export function BacklogPlanDialog({
}) || [],
};
const result = await api.backlogPlan.apply(projectPath, filteredPlanResult, currentBranch);
const result = await api.backlogPlan.apply(
projectPath,
filteredPlanResult,
currentBranch ?? 'main'
);
if (result.success) {
toast.success(`Applied ${result.appliedChanges?.length || 0} changes`);
setPendingPlanResult(null);