Skip to content

Commit bae5e3b

Browse files
committed
fix: harden fish gtrconfig trust helpers
1 parent 73a5368 commit bae5e3b

2 files changed

Lines changed: 105 additions & 4 deletions

File tree

lib/commands/init.sh

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,15 @@ end
182182
183183
function __FUNC___hooks_current_content_hash
184184
set -l _gtr_config_file "$argv[1]"
185-
set -l _gtr_hook_defs (git config -f "$_gtr_config_file" --get-regexp '^hooks\.|^defaults\.editor$|^defaults\.ai$' 2>/dev/null)
186-
test $status -eq 0; or return 1
187-
printf '%s\n' "$_gtr_hook_defs" | shasum -a 256 | cut -d' ' -f1
185+
set -l _gtr_hook_defs (git config -f "$_gtr_config_file" --get-regexp '^hooks\.|^defaults\.editor$|^defaults\.ai$' 2>/dev/null | shasum -a 256 | cut -d' ' -f1)
186+
test $pipestatus[1] -eq 0; or return 1
187+
test -n "$_gtr_hook_defs"; or return 1
188+
printf '%s\n' "$_gtr_hook_defs"
188189
end
189190
190191
function __FUNC___hooks_repo_root
191192
set -l _gtr_config_file "$argv[1]"
192-
cd (dirname "$_gtr_config_file") 2>/dev/null; and pwd -P
193+
command sh -c 'cd "$1" 2>/dev/null && pwd -P' sh (dirname "$_gtr_config_file")
193194
end
194195
195196
function __FUNC___hooks_canonical_config_path

tests/init.bats

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,71 @@ printf '\n'
110110
SCRIPT
111111
}
112112

113+
run_generated_fish_gtrconfig_post_cd_hooks() {
114+
local trust_state="$1"
115+
local root repo wt xdg init_file
116+
117+
root=$(mktemp -d)
118+
repo="$root/repo"
119+
wt="$root/wt"
120+
xdg="$root/xdg"
121+
init_file="$root/gtr.fish"
122+
123+
git init --quiet "$repo"
124+
git -C "$repo" config user.name "Test User"
125+
git -C "$repo" config user.email "test@example.com"
126+
git -C "$repo" commit --allow-empty -m "init" --quiet
127+
git -C "$repo" worktree add --quiet "$wt" -b feature
128+
129+
cat > "$repo/.gtrconfig" <<'CFG'
130+
[hooks]
131+
postCd = pwd > "$WORKTREE_PATH/hook-pwd"
132+
postCd = echo second >> "$WORKTREE_PATH/hook-order"
133+
[defaults]
134+
ai = codex
135+
CFG
136+
137+
cmd_init fish > "$init_file"
138+
139+
if [ "$trust_state" = "trusted" ]; then
140+
(
141+
export XDG_CONFIG_HOME="$xdg"
142+
# shellcheck disable=SC1091
143+
. "$PROJECT_ROOT/lib/hooks.sh"
144+
_hooks_mark_trusted "$repo/.gtrconfig"
145+
)
146+
fi
147+
148+
XDG_CONFIG_HOME="$xdg" fish -c '
149+
source "$argv[1]"
150+
set -l wt "$argv[2]"
151+
set -l root "$argv[3]"
152+
153+
cd /
154+
gtr_run_post_cd_hooks "$wt" > "$root/stdout" 2> "$root/stderr"
155+
set -l rc $status
156+
157+
printf "RC=%s\n" "$rc"
158+
printf "PWD=%s\n" "$PWD"
159+
printf "WT=%s\n" "$wt"
160+
if test -f "$wt/hook-pwd"
161+
printf "HOOK_PWD=%s\n" (cat "$wt/hook-pwd")
162+
else
163+
printf "HOOK_PWD=<missing>\n"
164+
end
165+
if test -f "$wt/hook-order"
166+
printf "HOOK_ORDER=%s\n" (paste -sd, "$wt/hook-order")
167+
else
168+
printf "HOOK_ORDER=<missing>\n"
169+
end
170+
printf "STDERR=%s\n" (cat "$root/stderr")
171+
' -- "$init_file" "$wt" "$root"
172+
local rc=$?
173+
174+
rm -rf "$root"
175+
return "$rc"
176+
}
177+
113178
require_runtime_shell() {
114179
local shell_name="$1"
115180

@@ -320,6 +385,41 @@ require_runtime_shell() {
320385
[ "$output" = "/tmp/repo" ]
321386
}
322387

388+
@test "fish generated postCd skips untrusted gtrconfig hooks without changing cwd" {
389+
require_runtime_shell fish
390+
391+
run run_generated_fish_gtrconfig_post_cd_hooks untrusted
392+
393+
[ "$status" -eq 0 ]
394+
[[ "$output" == *"RC=0"* ]]
395+
[[ "$output" == *"HOOK_PWD=<missing>"* ]]
396+
[[ "$output" == *"HOOK_ORDER=<missing>"* ]]
397+
[[ "$output" == *"STDERR=gtr: Untrusted .gtrconfig hooks skipped"* ]]
398+
399+
local pwd_line wt_line
400+
pwd_line=$(printf '%s\n' "$output" | sed -n 's/^PWD=//p')
401+
wt_line=$(printf '%s\n' "$output" | sed -n 's/^WT=//p')
402+
[ "$pwd_line" = "$wt_line" ]
403+
}
404+
405+
@test "fish generated postCd trusts multi-entry gtrconfig hooks without changing cwd" {
406+
require_runtime_shell fish
407+
408+
run run_generated_fish_gtrconfig_post_cd_hooks trusted
409+
410+
[ "$status" -eq 0 ]
411+
[[ "$output" == *"RC=0"* ]]
412+
[[ "$output" == *"HOOK_ORDER=second"* ]]
413+
[[ "$output" == *"STDERR="* ]]
414+
415+
local pwd_line wt_line hook_pwd_line
416+
pwd_line=$(printf '%s\n' "$output" | sed -n 's/^PWD=//p')
417+
wt_line=$(printf '%s\n' "$output" | sed -n 's/^WT=//p')
418+
hook_pwd_line=$(printf '%s\n' "$output" | sed -n 's/^HOOK_PWD=//p')
419+
[ "$pwd_line" = "$wt_line" ]
420+
[ "$hook_pwd_line" = "$wt_line" ]
421+
}
422+
323423
# ── new --cd wrapper support ────────────────────────────────────────────────
324424

325425
@test "bash output intercepts new --cd and strips flag before delegating" {

0 commit comments

Comments
 (0)