Skip to content

Commit 6ee201f

Browse files
awakiaclaude
andauthored
fix: allow + in branch names (generated by Claude Code EnterWorktree) (#1248)
Claude Code's EnterWorktree tool converts "/" to "+" when generating branch names from worktree names (e.g. EnterWorktree("feat/foo") creates branch "worktree-feat+foo"). The strict whitelist in validateBranchName rejected these names, causing claude-code-action to fail on any PR opened from an EnterWorktree-generated branch. Since all git calls use execFileSync (not shell interpolation), "+" carries no command injection risk — the same rationale used for allowing "#". Git itself permits "+" in branch names per git-check-ref-format. Fixes: #1244 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b4d6741 commit 6ee201f

2 files changed

Lines changed: 16 additions & 4 deletions

File tree

src/github/operations/branch.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,16 @@ export function validateBranchName(branchName: string): void {
5858
);
5959
}
6060

61-
// Strict whitelist pattern: alphanumeric start, then alphanumeric/slash/hyphen/underscore/period/hash.
61+
// Strict whitelist pattern: alphanumeric start, then alphanumeric/slash/hyphen/underscore/period/hash/plus.
6262
// # is valid per git-check-ref-format and commonly used in branch names like "fix/#123-description".
63-
// All git calls use execFileSync (not shell interpolation), so # carries no injection risk.
64-
const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9/_.#-]*$/;
63+
// + is valid per git-check-ref-format and generated by Claude Code's EnterWorktree tool when
64+
// converting worktree names containing "/" (e.g. "feat/foo" becomes "worktree-feat+foo").
65+
// All git calls use execFileSync (not shell interpolation), so neither # nor + carries injection risk.
66+
const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9/_.#+-]*$/;
6567

6668
if (!validPattern.test(branchName)) {
6769
throw new Error(
68-
`Invalid branch name: "${branchName}". Branch names must start with an alphanumeric character and contain only alphanumeric characters, forward slashes, hyphens, underscores, periods, or hashes (#).`,
70+
`Invalid branch name: "${branchName}". Branch names must start with an alphanumeric character and contain only alphanumeric characters, forward slashes, hyphens, underscores, periods, hashes (#), or plus signs (+).`,
6971
);
7072
}
7173

test/validate-branch-name.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ describe("validateBranchName", () => {
4545
).not.toThrow();
4646
expect(() => validateBranchName("fix/issue-#42")).not.toThrow();
4747
});
48+
49+
it("should accept branch names containing + (generated by Claude Code EnterWorktree)", () => {
50+
// EnterWorktree converts "/" in worktree names to "+" when generating branch names.
51+
// e.g. EnterWorktree("feat/skill-consolidation") → branch "worktree-feat+skill-consolidation"
52+
expect(() =>
53+
validateBranchName("worktree-feat+skill-consolidation"),
54+
).not.toThrow();
55+
expect(() => validateBranchName("fix+issue-123")).not.toThrow();
56+
expect(() => validateBranchName("feature+new-thing")).not.toThrow();
57+
});
4858
});
4959

5060
describe("command injection attempts", () => {

0 commit comments

Comments
 (0)