From 65556904d98e52278b4588b209030f8fe23c8e2e Mon Sep 17 00:00:00 2001 From: Maxwell Calkin Date: Sun, 8 Mar 2026 14:11:22 -0400 Subject: [PATCH] fix: allow '#' in branch names for Azure DevOps integration The branch name validation regex rejected the '#' character, which is commonly used in Azure DevOps branch naming conventions (e.g., "feature/AB#1992-sentry-enhancements"). The '#' character is valid in git branch names and poses no command injection risk. Updated the whitelist pattern to include '#' and added corresponding test cases. Fixes #1024 Co-Authored-By: Claude Opus 4.6 --- src/github/operations/branch.ts | 10 +++++----- test/validate-branch-name.test.ts | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/github/operations/branch.ts b/src/github/operations/branch.ts index 86197da96..65dee4307 100644 --- a/src/github/operations/branch.ts +++ b/src/github/operations/branch.ts @@ -28,14 +28,14 @@ function extractFirstLabel(githubData: FetchDataResult): string | undefined { * * Valid branch names: * - Start with alphanumeric character (not dash, to prevent option injection) - * - Contain only alphanumeric, forward slash, hyphen, underscore, or period + * - Contain only alphanumeric, forward slash, hyphen, underscore, hash, or period * - Do not start or end with a period * - Do not end with a slash * - Do not contain '..' (path traversal) * - Do not contain '//' (consecutive slashes) * - Do not end with '.lock' * - Do not contain '@{' - * - Do not contain control characters or special git characters (~^:?*[\]) + * - Do not contain control characters or special git characters (~^:?*[\\]) */ export function validateBranchName(branchName: string): void { // Check for empty or whitespace-only names @@ -58,12 +58,12 @@ export function validateBranchName(branchName: string): void { ); } - // Strict whitelist pattern: alphanumeric start, then alphanumeric/slash/hyphen/underscore/period - const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9/_.-]*$/; + // Strict whitelist pattern: alphanumeric start, then alphanumeric/slash/hyphen/underscore/hash/period + const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9/_#.-]*$/; if (!validPattern.test(branchName)) { throw new Error( - `Invalid branch name: "${branchName}". Branch names must start with an alphanumeric character and contain only alphanumeric characters, forward slashes, hyphens, underscores, or periods.`, + `Invalid branch name: "${branchName}". Branch names must start with an alphanumeric character and contain only alphanumeric characters, forward slashes, hyphens, underscores, hashes, or periods.`, ); } diff --git a/test/validate-branch-name.test.ts b/test/validate-branch-name.test.ts index 539932dd0..28bc6e0c6 100644 --- a/test/validate-branch-name.test.ts +++ b/test/validate-branch-name.test.ts @@ -29,6 +29,14 @@ describe("validateBranchName", () => { expect(() => validateBranchName("release.1.2.3")).not.toThrow(); }); + it("should accept names with hash characters (Azure DevOps work items)", () => { + expect(() => + validateBranchName("feature/AB#1992-sentry-enhancements"), + ).not.toThrow(); + expect(() => validateBranchName("fix/PROJ#123-bug")).not.toThrow(); + expect(() => validateBranchName("user/task#42")).not.toThrow(); + }); + it("should accept typical branch name formats", () => { expect(() => validateBranchName("claude/issue-123-20250101-1234"),