* Share the git URL check between theme-install and plugin-add Both commands clone a URL a stranger can choose, and each carried its own copy of the rule that refuses a git option or a `<helper>::<address>` transport helper before cloning. Two copies of a security check drift: the second one arrived four months after the first, and only because someone went looking for it. The rule now lives in omarchy-git-url-check and the callers ask it. Its absence refuses the URL rather than waving it through, since the callers read a non-zero status as a refusal and a missing command exits 127. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Codex XHigh <noreply@openai.com> * Refuse a git URL naming a transport Omarchy does not clone from `<helper>::<address>` is only one of the two ways a URL reaches a remote helper. git also resolves git-remote-<scheme> for `<scheme>://<address>` whenever the scheme is not one it connects itself, so `ext::sh -c id` and `ext://sh -c id` arrive at the same helper while only the first was refused. That shape cannot be refused outright, because it is also how every legitimate URL arrives, so the scheme is checked against the transports git still connects itself. `git+ssh` and `ssh+git` are on that list: they are spelled like a helper and read as plain ssh, and leaving them off would refuse a URL that clones today. `ext` and `fd` are off it deliberately -- git ships a helper for each, and `ext` runs whatever command the URL carries. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Codex XHigh <noreply@openai.com> --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Codex XHigh <noreply@openai.com>
129 lines
4.7 KiB
Bash
Executable File
129 lines
4.7 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
# omarchy-theme-install feeds a pasted URL to git and a name derived from it to
|
|
# rm, and omarchy-theme-remove feeds its argument to rm. Both are exercised here
|
|
# with git and the themes directory stubbed, so a guard that stopped working
|
|
# shows up as a clone or a removal that should never have been reached.
|
|
|
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
|
|
|
test_tmp=$(mktemp -d)
|
|
trap 'rm -rf "$test_tmp"' EXIT
|
|
|
|
mock_bin="$test_tmp/bin"
|
|
mkdir -p "$mock_bin"
|
|
|
|
cat >"$mock_bin/git" <<'SH'
|
|
#!/bin/bash
|
|
printf '%s\n' "$*" >>"$OMARCHY_TEST_GIT_CALLS"
|
|
[[ $1 == "clone" ]] && mkdir -p "${*: -1}"
|
|
exit 0
|
|
SH
|
|
|
|
cat >"$mock_bin/gum" <<'SH'
|
|
#!/bin/bash
|
|
exit 1
|
|
SH
|
|
|
|
for command in omarchy-theme-set omarchy-notification-send omarchy-menu-select; do
|
|
printf '#!/bin/bash\nprintf "%%s\\n" "$*" >>"$OMARCHY_TEST_THEME_CALLS"\nexit 0\n' >"$mock_bin/$command"
|
|
done
|
|
|
|
chmod +x "$mock_bin"/*
|
|
|
|
git_calls="$test_tmp/git-calls"
|
|
theme_calls="$test_tmp/theme-calls"
|
|
|
|
install_theme() {
|
|
: >"$git_calls"
|
|
: >"$theme_calls"
|
|
|
|
HOME="$test_tmp/home" PATH="${2-$mock_bin:$ROOT/bin:$PATH}" \
|
|
OMARCHY_TEST_GIT_CALLS="$git_calls" OMARCHY_TEST_THEME_CALLS="$theme_calls" \
|
|
bash "$ROOT/bin/omarchy-theme-install" "$1" >"$test_tmp/out" 2>&1 || return $?
|
|
}
|
|
|
|
mkdir -p "$test_tmp/home/.config/omarchy/themes"
|
|
|
|
# A URL git would read as an option or as a remote helper to run.
|
|
for url in "-x" "--upload-pack=touch /tmp/pwned" "ext::sh -c id" "fd::0,1"; do
|
|
if install_theme "$url"; then
|
|
fail "omarchy-theme-install refuses the URL '$url'"
|
|
fi
|
|
|
|
[[ ! -s $git_calls ]] || fail "omarchy-theme-install refuses '$url' before running git" "$(cat "$git_calls")"
|
|
done
|
|
|
|
pass "a URL that names a git option or a transport helper never reaches git"
|
|
|
|
# git resolves git-remote-<scheme> for any scheme it does not implement itself,
|
|
# so the `://` spelling of a helper has to be refused as well as the `::` one.
|
|
for url in "ext://sh -c id" "fd://17" "gcrypt://example.com/x"; do
|
|
if install_theme "$url"; then
|
|
fail "omarchy-theme-install refuses the URL '$url'"
|
|
fi
|
|
|
|
[[ ! -s $git_calls ]] || fail "omarchy-theme-install refuses '$url' before running git" "$(cat "$git_calls")"
|
|
done
|
|
|
|
pass "a URL naming a transport git does not implement never reaches git"
|
|
|
|
# The checker is a separate command, so its absence has to refuse the URL rather
|
|
# than wave it through to git.
|
|
if install_theme "https://github.com/example/omarchy-cool-theme.git" "$mock_bin:$PATH"; then
|
|
fail "omarchy-theme-install refuses a URL it cannot check"
|
|
fi
|
|
|
|
[[ ! -s $git_calls ]] ||
|
|
fail "omarchy-theme-install refuses an unchecked URL before running git" "$(cat "$git_calls")"
|
|
|
|
pass "a missing url checker refuses the URL instead of cloning it"
|
|
|
|
# A URL whose derived name would escape the themes directory.
|
|
for url in "https://example.com/..git" "https://example.com/.git"; do
|
|
if install_theme "$url"; then
|
|
fail "omarchy-theme-install refuses the derived name from '$url'"
|
|
fi
|
|
|
|
[[ ! -s $git_calls ]] || fail "omarchy-theme-install refuses '$url' before running git" "$(cat "$git_calls")"
|
|
done
|
|
|
|
pass "a URL whose name would climb out of the themes directory never reaches git"
|
|
|
|
# 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")"
|
|
grep -Fq "/themes/foo" "$git_calls" || fail "omarchy-theme-install derives 'foo', not '.git'" "$(cat "$git_calls")"
|
|
|
|
pass "a dash inside the path does not become a basename option"
|
|
|
|
# And the ordinary case still works.
|
|
install_theme "https://github.com/example/omarchy-cool-theme.git" || fail "omarchy-theme-install clones a normal URL"
|
|
grep -Fq "/themes/cool" "$git_calls" || fail "omarchy-theme-install derives the theme name" "$(cat "$git_calls")"
|
|
grep -Fxq "cool" "$theme_calls" || fail "omarchy-theme-install applies the theme it installed" "$(cat "$theme_calls")"
|
|
|
|
pass "an ordinary theme URL still clones and applies"
|
|
|
|
# omarchy-theme-remove joins its argument into the path it deletes.
|
|
remove_theme() {
|
|
: >"$theme_calls"
|
|
|
|
HOME="$test_tmp/home" PATH="$mock_bin:$PATH" OMARCHY_TEST_THEME_CALLS="$theme_calls" \
|
|
bash "$ROOT/bin/omarchy-theme-remove" "$1" >"$test_tmp/out" 2>&1 || return $?
|
|
}
|
|
|
|
canary="$test_tmp/home/.config/omarchy/canary"
|
|
printf 'still here\n' >"$canary"
|
|
|
|
for name in ".." "." "../../evil" ".git"; do
|
|
if remove_theme "$name"; then
|
|
fail "omarchy-theme-remove refuses the theme name '$name'"
|
|
fi
|
|
|
|
[[ -f $canary ]] || fail "omarchy-theme-remove refuses '$name' before removing anything"
|
|
done
|
|
|
|
pass "a theme name cannot climb out of the themes directory on the way to rm"
|