Files
omarchycn/bin/omarchy-git-url-check
T
68ab12f77d Share the git URL check, and refuse the transports Omarchy does not clone from (#8174)
* 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>
2026-08-25 09:10:20 +02:00

51 lines
1.7 KiB
Bash
Executable File

#!/bin/bash
# omarchy:summary=Check that a git URL names a repository, not a transport helper
# omarchy:args=<git-url>
# omarchy:hidden=true
set -euo pipefail
# git picks a remote helper -- an executable it runs at clone time -- out of a URL
# in exactly two shapes, and no others: `<helper>::<address>`, and
# `<scheme>://<address>` for any scheme git does not handle itself. A single
# colon is always scp-style ssh, and a bare path is always a path; neither can
# reach a helper. So constraining those two shapes covers the whole surface.
#
# The `::` shape is refused outright, because no helper reachable that way is one
# a theme or plugin URL has business naming, and `ext::` runs a shell command.
# The `://` shape cannot be refused the same way, since it is also how every
# legitimate URL arrives -- so it is allowlisted instead. The list is the
# transports git still connects itself, `git+ssh` and `ssh+git` included: those
# two are spelled like a helper but are read as plain ssh. `ext` and `fd` are
# left out deliberately -- git ships a helper for each, and `ext` runs whatever
# command the URL carries.
TRANSPORTS=(ssh git git+ssh ssh+git http https ftp ftps file)
fail() {
echo "omarchy-git-url-check: $*" >&2
exit 1
}
url="${1-}"
if [[ -z $url ]]; then
fail "a git URL is required"
fi
if [[ $url == -* || $url =~ ^[A-Za-z0-9][A-Za-z0-9+.-]*:: ]]; then
fail "'$url' names a git option or transport helper, not a repository."
fi
if [[ $url =~ ^([A-Za-z0-9][A-Za-z0-9+.-]*):// ]]; then
scheme="${BASH_REMATCH[1]}"
for transport in "${TRANSPORTS[@]}"; do
if [[ $scheme == "$transport" ]]; then
exit 0
fi
done
fail "'$url' names the '$scheme' transport, which Omarchy does not clone from."
fi