fix(server): accept Git-valid worktree branch names (#3591)
Branch-off creation reused the filesystem slug validator even when callers supplied a separate branch name and worktree slug. Validate branch refs with Git at the worktree boundary so exact valid refs are preserved while path slugs remain restricted.
This commit is contained in:
@@ -42,7 +42,6 @@ import { spawnProcess } from "./spawn.js";
|
||||
import { resolvePaseoHome } from "../server/paseo-home.js";
|
||||
import { createExternalProcessEnv } from "../server/paseo-env.js";
|
||||
import { parseGitRevParsePath, resolveGitRevParsePath } from "./git-rev-parse-path.js";
|
||||
import { validateBranchSlug } from "@getpaseo/protocol/branch-slug";
|
||||
import { expandTilde, getRealpathAwareRelativePath, isPathInsideRoot } from "./path.js";
|
||||
import { terminateWithTreeKill } from "./tree-kill.js";
|
||||
|
||||
@@ -1310,7 +1309,7 @@ async function resolveWorktreeSourcePlan({
|
||||
switch (source.kind) {
|
||||
case "branch-off": {
|
||||
const branchName = source.branchName;
|
||||
validateWorktreeBranchName(branchName);
|
||||
await validateGitBranchName(cwd, branchName);
|
||||
const normalizedBaseBranch = normalizeRequiredBaseBranch(source.baseBranch);
|
||||
const resolvedBaseBranch = await resolveBaseBranchForWorktree(cwd, source.baseBranch);
|
||||
const branchExists = await localBranchExists(cwd, branchName);
|
||||
@@ -1330,7 +1329,7 @@ async function resolveWorktreeSourcePlan({
|
||||
};
|
||||
}
|
||||
case "checkout-branch": {
|
||||
await validateExistingWorktreeBranchName(cwd, source.branchName);
|
||||
await validateGitBranchName(cwd, source.branchName);
|
||||
if (!(await localBranchExists(cwd, source.branchName))) {
|
||||
try {
|
||||
await runGitCommand(["fetch", "origin", `${source.branchName}:${source.branchName}`], {
|
||||
@@ -1367,7 +1366,7 @@ async function resolveWorktreeSourcePlan({
|
||||
case "checkout-change-request":
|
||||
case "checkout-github-pr": {
|
||||
const localBranchCandidate = source.localBranchName ?? source.headRef;
|
||||
await validateExistingWorktreeBranchName(cwd, localBranchCandidate);
|
||||
await validateGitBranchName(cwd, localBranchCandidate);
|
||||
const localBranchName = await resolveUniqueLocalBranchName(cwd, localBranchCandidate);
|
||||
const normalizedBaseRefName = normalizeRequiredBaseBranch(source.baseRefName);
|
||||
const changeRequestNumber =
|
||||
@@ -1589,14 +1588,7 @@ async function configureWorktreeTrackingRemote(options: {
|
||||
);
|
||||
}
|
||||
|
||||
function validateWorktreeBranchName(branchName: string): void {
|
||||
const validation = validateBranchSlug(branchName);
|
||||
if (!validation.valid) {
|
||||
throw new Error(`Invalid branch name: ${validation.error}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function validateExistingWorktreeBranchName(cwd: string, branchName: string): Promise<void> {
|
||||
async function validateGitBranchName(cwd: string, branchName: string): Promise<void> {
|
||||
const result = await runGitCommand(["check-ref-format", "--branch", branchName], {
|
||||
cwd,
|
||||
timeout: 30_000,
|
||||
|
||||
Reference in New Issue
Block a user