From 3db53af02f765ec264717a942628d440e808cb95 Mon Sep 17 00:00:00 2001 From: yakanechi <138551445+yakanechi@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:51:08 +0900 Subject: [PATCH 1/6] add --- index.js | 28 ++++++++++++++++++---------- test/index.test.js | 37 ++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/index.js b/index.js index 8a8c723..859ddec 100644 --- a/index.js +++ b/index.js @@ -63,16 +63,25 @@ const ENTERPRISE_USER = 'EnterpriseUserAccount'; const allowedChars = [ '0-9', // ASCII digits 'A-Za-z', // ASCII alphabets - '\\p{Script=Hiragana}', // Hiragana - '\\p{Script=Katakana}', // Katakana - '\\p{Script=Han}', // CJK Han (Kanji) - '\\p{Script=Hangul}', // Hangul - '._/@\\-+', // ASCII symbols (Common filename-safe symbols allowed by Git) - '\\u3005' // Ideographic iteration mark: 々 + '\\p{Script_Extensions=Hiragana}', // Hiragana + '\\p{Script_Extensions=Katakana}', // Katakana + '\\p{Script_Extensions=Han}', // CJK Han (Kanji) + '\\p{Script_Extensions=Hangul}', // Hangul + '\\p{Script_Extensions=Greek}', // Greek (e.g. α β γ) + ',._/#%@\\-+=()', // ASCII symbols (Common filename-safe symbols allowed by Git) + '\\u3005', // Ideographic iteration mark: 々 + '\\u3010', // Full-width opening black lenticular bracket: 【 + '\\u3011', // Full-width closing black lenticular bracket: 】 + '\\uff1a', // Full-width colon: : + '\\uff08', // Full-width opening parenthesis: ( + '\\uff09', // Full-width closing parenthesis: ) + '\\u200b', // Full-width space + '\\uff10-\\uff19', // Full-width digits: 0-9 + '\\uff21-\\uff3a', // Full-width uppercase letters: A-Z + '\\uff41-\\uff5a' // Full-width lowercase letters: a-z ]; const BRANCH_NAME_ALLOWED_CHAR_RE = new RegExp(`^[${allowedChars.join('')}]+$`, 'u'); -const BRANCH_NAME_DANGEROUS_CHAR_RE = /['"`;!#$&<>|]/u; -const BRANCH_NAME_FORBIDDEN_SEQUENCE_RE = /(\/\/|(^|\/)\.|\/$|\.\.|@\{|\.lock$|\.$)/; +const BRANCH_NAME_DANGEROUS_CHAR_RE = /['"`;!$&<>|]/u; /** * Trim shell command indents @@ -153,8 +162,7 @@ function isSafeBranchName(name) { return ( BRANCH_NAME_ALLOWED_CHAR_RE.test(name) && !hasControlCharacters(name) && - !BRANCH_NAME_DANGEROUS_CHAR_RE.test(name) && - !BRANCH_NAME_FORBIDDEN_SEQUENCE_RE.test(name) + !BRANCH_NAME_DANGEROUS_CHAR_RE.test(name) ); } diff --git a/test/index.test.js b/test/index.test.js index ca42e6a..6b8b867 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -277,23 +277,21 @@ describe('index', function () { { category: 'ASCII digits', value: 'feature/20260615' }, { category: 'ASCII uppercase', value: 'feature/RELEASE' }, { category: 'ASCII lowercase', value: 'feature/release' }, - { category: 'hiragana', value: 'feature/ひらがなゔ' }, - { category: 'katakana', value: 'feature/カタカナヴ' }, - { category: 'cjk', value: 'feature/漢字東京' }, - { category: 'hangul', value: 'feature/한글테스트' } + { category: 'hiragana', value: 'feature/ひらがなゔー' }, + { category: 'katakana', value: 'feature/カタカナヴー' }, + { category: 'cjk', value: 'feature/漢字東京々' }, + { category: 'hangul', value: 'feature/한글테스트' }, + { category: 'greek', value: 'feature/alpha-β' }, + { category: 'fullwidth digits', value: 'feature/987' }, + { category: 'fullwidth letters', value: 'feature/Mm' } ]; const rejectedBranchCategorySamples = [ { category: 'ASCII symbols', value: 'feature/a+b.c=d,e@_](-)%' }, { category: 'extended latin', value: 'feature/Angstrom-Ångström-Đ' }, - { category: 'greek', value: 'feature/alpha-β' }, { category: 'control-special', value: 'feature/zero\u200bwidth※↑→−' }, { category: 'circled numbers', value: 'feature/④⑥⑧' }, - { category: 'jp punctuation', value: 'feature/、。々' }, - { category: 'jp brackets', value: 'feature/「名」【称】' }, { category: 'variation selector', value: 'feature/テスト\ufe0f' }, - { category: 'fullwidth symbols', value: 'feature/&():>_' }, - { category: 'fullwidth digits', value: 'feature/987' }, - { category: 'fullwidth letters', value: 'feature/Mm' } + { category: 'fullwidth symbols', value: 'feature/&>_' } ]; beforeEach(() => { @@ -325,7 +323,7 @@ describe('index', function () { ); }); - [`'`, '"', '`', ';', '!', '#', '&', '$', '<', '>', '|'].forEach(char => { + [`'`, '"', '`', ';', '!', '&', '$', '<', '>', '|'].forEach(char => { it(`rejects branch names containing shell metacharacter: ${char}`, () => { config.branch = `branch${char}name`; @@ -339,17 +337,14 @@ describe('index', function () { }); }); - ['branch..name', 'branch@{name', 'branch/.name', 'branch/', '.branch', 'branch.lock'].forEach(branchName => { - it(`rejects branch names with forbidden git ref sequence: ${branchName}`, () => { + ['branch..name', 'branch/.name', 'branch/', '.branch', 'branch.lock'].forEach(branchName => { + it(`accepts branch names without shell metacharacters: ${branchName}`, () => { config.branch = branchName; - return scm.getCheckoutCommand(config).then( - () => assert.fail('expected getCheckoutCommand to reject'), - err => { - assert.match(err.message, /Invalid branch name/); - assert.equal(err.statusCode, 400); - } - ); + return scm.getCheckoutCommand(config).then(command => { + assert.isString(command.command); + assert.isAbove(command.command.length, 0); + }); }); }); @@ -468,7 +463,7 @@ describe('index', function () { ); }); - [`'`, '"', '`', ';', '!', '#', '&', '$', '<', '>', '|'].forEach(char => { + [`'`, '"', '`', ';', '!', '&', '$', '<', '>', '|'].forEach(char => { it(`rejects PR branch names containing shell metacharacter: ${char}`, () => { config.prRef = 'pull/3/merge'; config.prBranchName = `branch${char}name`; From 24ca11c0d05aa1e70ce97c579a5bf7aca4f881a4 Mon Sep 17 00:00:00 2001 From: yakanechi <138551445+yakanechi@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:59:25 +0900 Subject: [PATCH 2/6] fix test --- test/index.test.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/index.test.js b/test/index.test.js index 6b8b867..d7bc51d 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -337,17 +337,6 @@ describe('index', function () { }); }); - ['branch..name', 'branch/.name', 'branch/', '.branch', 'branch.lock'].forEach(branchName => { - it(`accepts branch names without shell metacharacters: ${branchName}`, () => { - config.branch = branchName; - - return scm.getCheckoutCommand(config).then(command => { - assert.isString(command.command); - assert.isAbove(command.command.length, 0); - }); - }); - }); - it('accepts branch names with conservatively-safe special characters', () => { config.branch = 'feature/some_module.v1+rc1-final@host'; From 6a9ea1f7fe1a3cf991b31d35e1d4be294ce4b754 Mon Sep 17 00:00:00 2001 From: yakanechi <138551445+yakanechi@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:03:47 +0900 Subject: [PATCH 3/6] fix test --- test/index.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/index.test.js b/test/index.test.js index d7bc51d..4e91e55 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -282,8 +282,10 @@ describe('index', function () { { category: 'cjk', value: 'feature/漢字東京々' }, { category: 'hangul', value: 'feature/한글테스트' }, { category: 'greek', value: 'feature/alpha-β' }, + { category: 'fullwidth symbols', value: 'feature/():' }, { category: 'fullwidth digits', value: 'feature/987' }, - { category: 'fullwidth letters', value: 'feature/Mm' } + { category: 'fullwidth letters', value: 'feature/Mm' }, + { category: 'jp brackets', value: 'feature/「名」【称】' } ]; const rejectedBranchCategorySamples = [ { category: 'ASCII symbols', value: 'feature/a+b.c=d,e@_](-)%' }, @@ -291,7 +293,7 @@ describe('index', function () { { category: 'control-special', value: 'feature/zero\u200bwidth※↑→−' }, { category: 'circled numbers', value: 'feature/④⑥⑧' }, { category: 'variation selector', value: 'feature/テスト\ufe0f' }, - { category: 'fullwidth symbols', value: 'feature/&>_' } + { category: 'fullwidth symbols', value: 'feature/#&>_' } ]; beforeEach(() => { From 29c226144cddc817dde5950684d46ed681bd48ab Mon Sep 17 00:00:00 2001 From: yakanechi <138551445+yakanechi@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:04:57 +0900 Subject: [PATCH 4/6] fix test --- test/index.test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/index.test.js b/test/index.test.js index 4e91e55..28157e3 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -279,13 +279,14 @@ describe('index', function () { { category: 'ASCII lowercase', value: 'feature/release' }, { category: 'hiragana', value: 'feature/ひらがなゔー' }, { category: 'katakana', value: 'feature/カタカナヴー' }, - { category: 'cjk', value: 'feature/漢字東京々' }, + { category: 'cjk', value: 'feature/漢字東京' }, { category: 'hangul', value: 'feature/한글테스트' }, { category: 'greek', value: 'feature/alpha-β' }, + { category: 'jp punctuation', value: 'feature/、。々' }, + { category: 'jp brackets', value: 'feature/「名」【称】' } { category: 'fullwidth symbols', value: 'feature/():' }, { category: 'fullwidth digits', value: 'feature/987' }, { category: 'fullwidth letters', value: 'feature/Mm' }, - { category: 'jp brackets', value: 'feature/「名」【称】' } ]; const rejectedBranchCategorySamples = [ { category: 'ASCII symbols', value: 'feature/a+b.c=d,e@_](-)%' }, From b1f0e19c4b0a1a840daee98dc1737ed3e06a598d Mon Sep 17 00:00:00 2001 From: yakanechi <138551445+yakanechi@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:13:30 +0900 Subject: [PATCH 5/6] fix lint --- test/index.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/index.test.js b/test/index.test.js index 28157e3..96e8aa0 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -283,10 +283,10 @@ describe('index', function () { { category: 'hangul', value: 'feature/한글테스트' }, { category: 'greek', value: 'feature/alpha-β' }, { category: 'jp punctuation', value: 'feature/、。々' }, - { category: 'jp brackets', value: 'feature/「名」【称】' } + { category: 'jp brackets', value: 'feature/「名」【称】' }, { category: 'fullwidth symbols', value: 'feature/():' }, { category: 'fullwidth digits', value: 'feature/987' }, - { category: 'fullwidth letters', value: 'feature/Mm' }, + { category: 'fullwidth letters', value: 'feature/Mm' } ]; const rejectedBranchCategorySamples = [ { category: 'ASCII symbols', value: 'feature/a+b.c=d,e@_](-)%' }, From 4ad0e66b5df198b46132197eb9f53d61a2f8054b Mon Sep 17 00:00:00 2001 From: yakanechi <138551445+yakanechi@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:24:09 +0900 Subject: [PATCH 6/6] fix space --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 859ddec..7611ab6 100644 --- a/index.js +++ b/index.js @@ -75,7 +75,7 @@ const allowedChars = [ '\\uff1a', // Full-width colon: : '\\uff08', // Full-width opening parenthesis: ( '\\uff09', // Full-width closing parenthesis: ) - '\\u200b', // Full-width space + '\\u3000', // Full-width space '\\uff10-\\uff19', // Full-width digits: 0-9 '\\uff21-\\uff3a', // Full-width uppercase letters: A-Z '\\uff41-\\uff5a' // Full-width lowercase letters: a-z