diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bbe4be..25f79c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html): --- +## [1.0.2] — 2026-06-23 +### Fixed +- `_wrktr_sanitize_branch_name`: Fixed branch naming bug. Previously was adding an arbitrary `%` to the end of the branch and riectory name + + ## [1.0.1] — 2026-06-05 ### Fixed diff --git a/tests/wrktr.bats b/tests/wrktr.bats index b0855a6..f063ef7 100644 --- a/tests/wrktr.bats +++ b/tests/wrktr.bats @@ -66,6 +66,21 @@ teardown() { [ "$result" = "main" ] } +@test "_wrktr_sanitize_branch_name: plain name with dash is unchanged" { + result="$(_wrktr_sanitize_branch_name "fix-crash-100")" + [ "$result" = "fix-crash-100" ] +} + +@test "_wrktr_sanitize_branch_name: plain name with underscore is unchanged" { + result="$(_wrktr_sanitize_branch_name "fix_crash_100")" + [ "$result" = "fix_crash_100" ] +} + +@test "_wrktr_sanitize_branch_name: plain name with dot is unchanged" { + result="$(_wrktr_sanitize_branch_name "release.2026")" + [ "$result" = "release.2026" ] +} + @test "_wrktr_sanitize_branch_name: single slash encoded as %2F" { result="$(_wrktr_sanitize_branch_name "feature/login")" [ "$result" = "feature%2Flogin" ] @@ -76,16 +91,76 @@ teardown() { [ "$result" = "a%2Fb%2Fc" ] } -@test "_wrktr_sanitize_branch_name: percent encoded before slash to avoid double-encoding" { - result="$(_wrktr_sanitize_branch_name "fix/crash-100%")" - [ "$result" = "fix%2Fcrash-100%25" ] -} - -@test "_wrktr_sanitize_branch_name: existing percent-sign is escaped first" { +@test "_wrktr_sanitize_branch_name: existing percent-sign is escaped before slash encoding" { result="$(_wrktr_sanitize_branch_name "already%2Fencoded")" [ "$result" = "already%252Fencoded" ] } +@test "_wrktr_sanitize_branch_name: internal percent-sign is escaped" { + result="$(_wrktr_sanitize_branch_name "fix/100%repro")" + [ "$result" = "fix%2F100%25repro" ] +} + +@test "_wrktr_sanitize_branch_name: trailing percent is rejected" { + run _wrktr_sanitize_branch_name "fix/crash-100%" + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + +@test "_wrktr_sanitize_branch_name: trailing dash is rejected" { + run _wrktr_sanitize_branch_name "fix/crash-100-" + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + +@test "_wrktr_sanitize_branch_name: trailing underscore is rejected" { + run _wrktr_sanitize_branch_name "fix/crash-100_" + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + +@test "_wrktr_sanitize_branch_name: trailing dot is rejected by git" { + run _wrktr_sanitize_branch_name "fix/crash-100." + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + +@test "_wrktr_sanitize_branch_name: space is rejected" { + run _wrktr_sanitize_branch_name "feature/bad name" + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + +@test "_wrktr_sanitize_branch_name: exclamation mark is rejected" { + run _wrktr_sanitize_branch_name "feature/bad!" + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + +@test "_wrktr_sanitize_branch_name: at sign is rejected by git" { + run _wrktr_sanitize_branch_name "@" + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + +@test "_wrktr_sanitize_branch_name: double dot is rejected by git" { + run _wrktr_sanitize_branch_name "feature/foo..bar" + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + +@test "_wrktr_sanitize_branch_name: lock suffix is rejected by git" { + run _wrktr_sanitize_branch_name "feature/foo.lock" + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + +@test "_wrktr_sanitize_branch_name: empty branch is rejected" { + run _wrktr_sanitize_branch_name "" + [ "$status" -eq 1 ] + [ "$output" = "" ] +} + # =========================================================================== # _wrktr_assert_subpath # =========================================================================== diff --git a/worktree-functions.sh b/worktree-functions.sh index af58108..3f99e34 100644 --- a/worktree-functions.sh +++ b/worktree-functions.sh @@ -917,8 +917,26 @@ function wrktr_git() { # ----------------------------------------------------------------------------- function _wrktr_sanitize_branch_name() { local branch="$1" + + if ! git check-ref-format --branch "$branch" >/dev/null 2>&1; then + return 1 + fi + + # Require the original branch name to end in a letter or number. + # This prevents trailing %, -, _, ., etc. from becoming acceptable after encoding. + if [[ ! "$branch" =~ [A-Za-z0-9]$ ]]; then + return 1 + fi + branch="${branch//%/%25}" - echo "${branch//\//%2F}" + branch="${branch//\//%2F}" + + # Allow only safe output characters and known encodings. + if [[ ! "$branch" =~ ^([A-Za-z0-9._-]|%2F|%25)+$ ]]; then + return 1 + fi + + printf '%s\n' "$branch" } # -----------------------------------------------------------------------------