From 2b923cf5bd8cbde76eeef1b21354c399aa7f99b7 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 27 Aug 2026 19:52:37 +0200 Subject: [PATCH] Pin the theme name check to C, and read a colon before any slash as scp-style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bracket range is collated, not ASCII, so `[a-z]` admits `é` under en_US.UTF-8 and refuses it under C: the same theme URL installed on one desktop and was refused on the next, and the manual's stated set was only true in the C locale. Pinning the comparison makes the written set the shipped one everywhere. git reads a URL as scp-style when a colon appears before any slash, so the path after it need not contain one. Requiring a slash left the prefix on `git@host:omarchy-blue-theme.git` and derived the name `git@host:omarchy-blue`, which the allowlist then refuses -- a repo that clones fine could no longer be installed at all. Co-Authored-By: Codex XHigh --- bin/omarchy-theme-install | 11 ++++++-- test/shell.d/theme-install-guards-test.sh | 34 +++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/bin/omarchy-theme-install b/bin/omarchy-theme-install index 6b442678..b324fe55 100755 --- a/bin/omarchy-theme-install +++ b/bin/omarchy-theme-install @@ -23,9 +23,12 @@ omarchy-git-url-check "$REPO_URL" || exit 1 THEMES_DIR="$HOME/.config/omarchy/themes" -# Strip user@host: prefix from scp-style SSH URLs so basename sees just the path +# Strip user@host: prefix from scp-style SSH URLs so basename sees just the path. +# git reads a URL as scp-style when a colon appears before any slash, so the path +# after it need not hold one: `git@host:omarchy-blue-theme.git` is a repo in that +# user's home, and leaving its prefix on names the theme after the whole URL. REPO_PATH="$REPO_URL" -[[ $REPO_PATH != *"://"* && $REPO_PATH == *:*/* ]] && REPO_PATH="${REPO_PATH#*:}" +[[ $REPO_PATH != *"://"* && $REPO_PATH == *:* && ${REPO_PATH%%:*} != */* ]] && REPO_PATH="${REPO_PATH#*:}" THEME_NAME=$(basename -- "$REPO_PATH" .git | sed -E 's/^omarchy-//; s/-theme$//' | tr '[:upper:]' '[:lower:]') THEME_PATH="$THEMES_DIR/$THEME_NAME" @@ -37,7 +40,9 @@ THEME_PATH="$THEMES_DIR/$THEME_NAME" # ~/.config/omarchy with it, and one called `a';'id` would carry its own # command into that picker. The leading character is kept out of `.` and `-`, # which also covers `host:-s/foo.git` leaving basename with `.git`. -if [[ ! $THEME_NAME =~ ^[a-z0-9_][a-z0-9._+-]*$ ]]; then +# A bracket range follows the locale's collation, not ASCII: `[a-z]` takes in +# `é` under en_US.UTF-8. Pin the locale so the set is the one written here. +if ! (LC_ALL=C; [[ $THEME_NAME =~ ^[a-z0-9_][a-z0-9._+-]*$ ]]); then echo "Error: '$REPO_URL' does not give a usable theme name." exit 1 fi diff --git a/test/shell.d/theme-install-guards-test.sh b/test/shell.d/theme-install-guards-test.sh index 2b29bba8..6c6044d0 100755 --- a/test/shell.d/theme-install-guards-test.sh +++ b/test/shell.d/theme-install-guards-test.sh @@ -135,6 +135,40 @@ grep -Fq "/themes/_private" "$git_calls" || pass "a plus and a leading underscore are still usable theme names" +# git reads a colon before any slash as the scp-style separator, so the path +# after it does not have to hold one. Without that reading, the whole URL becomes +# the theme name and the allowlist above refuses a repo that clones fine. +install_theme "git@example.com:omarchy-blue-theme.git" || + fail "omarchy-theme-install accepts a home-relative scp-style URL" +grep -Fq "/themes/blue" "$git_calls" || + fail "omarchy-theme-install names the theme after the repo, not the whole URL" "$(cat "$git_calls")" + +# A colon that is part of a local path, not an scp separator, keeps its prefix. +install_theme "/srv/git:mirrors/omarchy-blue-theme.git" || + fail "omarchy-theme-install accepts a local path holding a colon" +grep -Fq "/themes/blue" "$git_calls" || + fail "omarchy-theme-install reads a colon after a slash as part of the path" "$(cat "$git_calls")" + +pass "an scp-style URL with no slash after the colon still names the theme" + +# The allowlist is a bracket range, and a range follows the locale's collation +# rather than ASCII: under en_US.UTF-8 an unpinned `[a-z]` takes in `é`, so the +# same URL would install on one desktop and be refused on the next. +if locale -a 2>/dev/null | grep -qix 'en_US.utf-\?8'; then + for locale_name in C en_US.UTF-8; do + if LC_ALL=$locale_name install_theme "https://github.com/example/omarchy-café-theme.git"; then + fail "omarchy-theme-install refuses a non-ASCII theme name under LC_ALL=$locale_name" "$(cat "$git_calls")" + fi + + [[ ! -s $git_calls ]] || + fail "omarchy-theme-install refuses a non-ASCII name before running git" "$(cat "$git_calls")" + done + + pass "the accepted set does not move with the desktop's locale" +else + pass "no en_US.UTF-8 locale; skipping the locale-pinning check" +fi + # basename reads a leading dash as an option once the scp-style prefix is gone. install_theme "host:-s/foo.git" || fail "omarchy-theme-install accepts a normal scp-style URL" grep -Fq -- "-- host:-s/foo.git" "$git_calls" || fail "omarchy-theme-install passes the URL after --" "$(cat "$git_calls")"