From 30471bf35a7fb28e24d960045e7ecd7cda132f1f Mon Sep 17 00:00:00 2001 From: Basti <233381911+bastidotnet@users.noreply.github.com> Date: Tue, 25 Aug 2026 08:29:48 +0200 Subject: [PATCH] Guard plugin-add against git transport-helper URLs (match theme-install) (#8067) * Guard plugin-add against git transport-helper URLs omarchy-plugin-add cloned a user-supplied git URL without the transport-helper guard that omarchy-theme-install already applies (added in #7884, which did not touch plugin-add). Port that guard (reject ext::/fd:: and leading-dash forms, keep https/ssh/scp-style incl. IPv6) and add a regression test. Stock systems are unaffected (git default protocol.ext.allow=never); this removes the silent dependency on that default and aligns the two install paths. * Test the plugin-add guard's leading-dash arm via the gum input path The prior leading-dash cases only exercised the argv option parser, not the guard (removing the guard's -* arm left them green). Drive a dash value through the interactive gum prompt under a pty so the post-input guard is actually covered; skip cleanly where util-linux script is unavailable. --- bin/omarchy-plugin-add | 9 +++ test/shell.d/plugin-add-test.sh | 105 ++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/bin/omarchy-plugin-add b/bin/omarchy-plugin-add index f0bdfca5..9fa0e6c0 100755 --- a/bin/omarchy-plugin-add +++ b/bin/omarchy-plugin-add @@ -93,6 +93,15 @@ if [[ -z $url ]]; then [[ -n $url ]] || fail "a git URL is required" fi +# git reads a leading dash as an option, and `::
` as a remote +# helper to run at clone time. Reject both so an untrusted URL cannot smuggle a +# transport helper that executes before the plugin is validated or enabled. An +# scp-style IPv6 host such as git@[2001:db8::1]:org/repo.git carries `::` too and +# must still clone. +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 (( ! ASSUME_YES )); then cat >&2 <::…`) and option-shaped URLs +# before `git clone` runs, matching omarchy-theme-install. A git stub records +# whether clone was reached, so the guard is exercised with no network: reaching +# the stub proves a URL passed the guard; not reaching it proves the guard +# rejected the URL first. + +guard_stubs="$TMPDIR/guard-stubs" +mkdir -p "$guard_stubs" +cat >"$guard_stubs/omarchy-shell" <<'STUB' +#!/bin/bash +exit 0 +STUB +chmod +x "$guard_stubs/omarchy-shell" + +clone_marker="$TMPDIR/git-clone-reached" +cat >"$guard_stubs/git" <"$guard_stubs/gum" <<'STUB' +#!/bin/bash +if [[ $1 == "input" ]]; then + printf '%s\n' "$GUM_INPUT_VALUE" +fi +STUB +chmod +x "$guard_stubs/gum" + +add_url() { + HOME="$test_home" OMARCHY_PATH="$ROOT" PATH="$guard_stubs:$ROOT/bin:$PATH" \ + omarchy-plugin-add "$1" --yes 2>&1 +} + +# Transport helpers reach the guard, are named as such, and never reach clone. +for bad in "ext::sh -c touch /tmp/omarchy-guard-test" "fd::17"; do + rm -f "$clone_marker" + output=$(add_url "$bad") && + fail "plugin add rejects a transport-helper URL: $bad" "$output" + grep -qF "names a git option or transport helper" <<<"$output" || + fail "plugin add names the transport-helper rejection: $bad" "$output" + [[ ! -e $clone_marker ]] || + fail "plugin add reached git clone for a transport-helper URL: $bad" +done +pass "plugin add rejects transport-helper URLs before cloning" + +# Option-shaped URLs on argv are refused before clone — by the option parser +# (`-*` falls to "unknown add option"), not the guard. The guard's own +# leading-dash arm is only reachable through the interactive gum prompt and is +# exercised separately below. +for bad in "-oProxyCommand=x" "--upload-pack=x"; do + rm -f "$clone_marker" + output=$(add_url "$bad") && + fail "plugin add rejects an option-shaped URL: $bad" "$output" + [[ ! -e $clone_marker ]] || + fail "plugin add reached git clone for an option-shaped URL: $bad" +done +pass "plugin add rejects option-shaped URLs before cloning" + +# The guard's leading-dash arm is only reachable through `gum input`: argv +# dashes die in the option parser first. interactive() requires a TTY on stdin +# and stdout, so run this one case on a pty via util-linux `script -qec` (the +# suite's existing pty idiom); gum itself is stubbed, so no rendering happens. +# Probe script's util-linux syntax first and skip cleanly where it is missing. +if script -qec true /dev/null >/dev/null 2>&1; then + rm -f "$clone_marker" + status=0 + raw=$(GUM_INPUT_VALUE="-oProxyCommand=x" HOME="$test_home" OMARCHY_PATH="$ROOT" \ + PATH="$guard_stubs:$ROOT/bin:$PATH" \ + script -qec "omarchy-plugin-add --yes" /dev/null) || status=$? + output=$(tr -d '\r' <<<"$raw") + (( status != 0 )) || + fail "plugin add rejects an option-shaped URL from the gum prompt" "$output" + grep -qF "names a git option or transport helper" <<<"$output" || + fail "plugin add names the guard rejection for the gum-prompt URL" "$output" + [[ ! -e $clone_marker ]] || + fail "plugin add reached git clone for an option-shaped gum-prompt URL" + pass "plugin add guard rejects an option-shaped URL from the interactive prompt" +else + pass "script -qec unavailable; skipping the interactive gum-prompt guard case" +fi + +# Legitimate URL forms pass the guard and reach git clone (stubbed, no network). +for good in \ + "https://github.com/acme/omarchy-weather.git" \ + "git@github.com:acme/repo.git" \ + "ssh://git@github.com/acme/repo.git" \ + "git@[2001:db8::1]:org/repo.git"; do + rm -f "$clone_marker" + output=$(add_url "$good") || true + ! grep -qF "names a git option or transport helper" <<<"$output" || + fail "plugin add wrongly rejected a legitimate URL: $good" "$output" + [[ -e $clone_marker ]] || + fail "plugin add did not reach git clone for a legitimate URL: $good" "$output" +done +pass "plugin add lets legitimate git URLs reach git clone"