Skip to content

Commit b15d475

Browse files
qozleclaude
andauthored
fix: allow # in branch names for PR checkout and base restore (#1167)
`validateBranchName` used a strict whitelist that excluded `#`, causing the action to fail on PRs from branches like `put-back-arm64-#2` with "Invalid branch name" — even though the branch already exists in git and `#` is permitted by git-check-ref-format. The validation was designed to prevent command injection. However, every git call in the action uses `execFileSync`, which bypasses the shell entirely and passes arguments directly to the kernel's execve. There is no shell to interpret `#` as a metacharacter, so the strict whitelist was over-blocking valid names with no security benefit. Add `#` to the whitelist pattern, and update the JSDoc and error message to reflect the allowed character set. Fixes #1137. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d5db820 commit b15d475

File tree

2 files changed

+13
-4
lines changed

2 files changed

+13
-4
lines changed

src/github/operations/branch.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function extractFirstLabel(githubData: FetchDataResult): string | undefined {
2828
*
2929
* Valid branch names:
3030
* - Start with alphanumeric character (not dash, to prevent option injection)
31-
* - Contain only alphanumeric, forward slash, hyphen, underscore, or period
31+
* - Contain only alphanumeric, forward slash, hyphen, underscore, period, or hash (#)
3232
* - Do not start or end with a period
3333
* - Do not end with a slash
3434
* - Do not contain '..' (path traversal)
@@ -58,12 +58,14 @@ export function validateBranchName(branchName: string): void {
5858
);
5959
}
6060

61-
// Strict whitelist pattern: alphanumeric start, then alphanumeric/slash/hyphen/underscore/period
62-
const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9/_.-]*$/;
61+
// Strict whitelist pattern: alphanumeric start, then alphanumeric/slash/hyphen/underscore/period/hash.
62+
// # 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/_.#-]*$/;
6365

6466
if (!validPattern.test(branchName)) {
6567
throw new Error(
66-
`Invalid branch name: "${branchName}". Branch names must start with an alphanumeric character and contain only alphanumeric characters, forward slashes, hyphens, underscores, or periods.`,
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 (#).`,
6769
);
6870
}
6971

test/validate-branch-name.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ describe("validateBranchName", () => {
3636
expect(() => validateBranchName("refs/heads/main")).not.toThrow();
3737
expect(() => validateBranchName("bugfix/JIRA-1234")).not.toThrow();
3838
});
39+
40+
it("should accept branch names containing # (git-valid, common in issue-linked branches)", () => {
41+
// Reported in #1137: branches like "put-back-arm64-#2" were rejected
42+
expect(() => validateBranchName("put-back-arm64-#2")).not.toThrow();
43+
expect(() => validateBranchName("feature/#123-description")).not.toThrow();
44+
expect(() => validateBranchName("fix/issue-#42")).not.toThrow();
45+
});
3946
});
4047

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

0 commit comments

Comments
 (0)