Skip to content

Commit 57eb199

Browse files
committed
fix: trust-gate gtrconfig tool defaults
1 parent 5bd5d38 commit 57eb199

15 files changed

Lines changed: 209 additions & 59 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- `git gtr trust` now covers `.gtrconfig` `defaults.editor` and `defaults.ai` entries as executable commands, preventing shared config from selecting editor or AI commands until reviewed.
12+
913
## [2.7.0] - 2026-04-27
1014

1115
### Added

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -345,13 +345,13 @@ git gtr clean --merged --force --yes # Force-clean and auto-confirm
345345

346346
### `git gtr trust`
347347

348-
Review and approve hook commands defined in the repository's `.gtrconfig` file. Hooks from `.gtrconfig` are **not executed** until explicitly trusted — this prevents malicious contributors from injecting arbitrary shell commands via shared config files.
348+
Review and approve executable commands defined in the repository's `.gtrconfig` file. Hooks and editor/AI defaults from `.gtrconfig` are **not used** until explicitly trusted — this prevents malicious contributors from injecting arbitrary shell commands via shared config files.
349349

350350
```bash
351-
git gtr trust # Review and approve .gtrconfig hooks
351+
git gtr trust # Review and approve .gtrconfig commands
352352
```
353353

354-
Trust is stored per repository path plus hook definitions and must be re-approved if hooks change. Hooks from your local git config (`.git/config`, `~/.gitconfig`) are always trusted.
354+
Trust is stored per repository path plus executable command definitions and must be re-approved if hooks or editor/AI defaults change. Hooks and defaults from your local git config (`.git/config`, `~/.gitconfig`) are always trusted.
355355

356356
### Other Commands
357357

@@ -412,14 +412,14 @@ git gtr config set gtr.ui.color never
412412
remote = upstream
413413
```
414414

415-
**Hook trust:** Hooks defined in `.gtrconfig` require explicit approval before they execute. Run `git gtr trust` after cloning a repository or when `.gtrconfig` hooks change. This protects against malicious hook injection in shared repositories.
415+
**Command trust:** Hooks and editor/AI defaults defined in `.gtrconfig` require explicit approval before they execute or select tools. Run `git gtr trust` after cloning a repository or when `.gtrconfig` command entries change. This protects against malicious command injection in shared repositories.
416416

417417
**Adapter safety:** Generic `gtr.editor.default` and `gtr.ai.default` values must resolve to safe PATH commands. Filesystem paths such as `./tool` and shell wrapper forms such as `sh -c ...` are rejected. Override-backed adapters like `claude`, `cursor`, and `nano` may include additional flags, for example `claude --continue` or `nano -w`.
418418

419419
**Configuration precedence** (highest to lowest):
420420

421421
1. `git config --local` (`.git/config`) - personal overrides
422-
2. `.gtrconfig` (repo root) - team defaults (hooks require `git gtr trust`)
422+
2. `.gtrconfig` (repo root) - team defaults (hooks and editor/AI defaults require `git gtr trust`)
423423
3. `git config --global` (`~/.gitconfig`) - user defaults
424424

425425
> For complete configuration reference including all settings, hooks, file copying patterns, and environment variables, see [docs/configuration.md](docs/configuration.md)

completions/_git-gtr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ _git-gtr() {
4545
'config:Manage configuration'
4646
'completion:Generate shell completions'
4747
'init:Generate shell integration for cd support'
48-
'trust:Trust .gtrconfig hooks'
48+
'trust:Trust .gtrconfig commands'
4949
'version:Show version'
5050
'help:Show help'
5151
)

completions/git-gtr.fish

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ complete -f -c git -n '__fish_git_gtr_using_command completion' -a 'bash zsh fis
5454
complete -f -c git -n '__fish_git_gtr_needs_command' -a init -d 'Generate shell integration for cd support'
5555
complete -f -c git -n '__fish_git_gtr_using_command init' -a 'bash zsh fish' -d 'Shell type'
5656
complete -c git -n '__fish_git_gtr_using_command init' -l as -d 'Custom function name' -r
57-
complete -f -c git -n '__fish_git_gtr_needs_command' -a trust -d 'Trust .gtrconfig hooks'
57+
complete -f -c git -n '__fish_git_gtr_needs_command' -a trust -d 'Trust .gtrconfig commands'
5858
complete -f -c git -n '__fish_git_gtr_needs_command' -a version -d 'Show version'
5959
complete -f -c git -n '__fish_git_gtr_needs_command' -a help -d 'Show help'
6060

docs/configuration.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ Create a `.gtrconfig` file in your repository root to share configuration across
6868
> [!TIP]
6969
> See `templates/.gtrconfig.example` for a complete example with all available settings.
7070

71+
> [!IMPORTANT]
72+
> Hooks and editor/AI defaults from `.gtrconfig` are executable command entries. They are ignored until you review them with `git gtr trust`; changing those entries requires re-approval.
73+
7174
---
7275

7376
## Worktree Settings

lib/commands/help.sh

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -415,23 +415,24 @@ EOF
415415

416416
_help_trust() {
417417
cat <<'EOF'
418-
git gtr trust - Trust .gtrconfig hooks
418+
git gtr trust - Trust .gtrconfig commands
419419
420420
Usage: git gtr trust
421421
422-
Reviews and approves hook commands defined in the repository's .gtrconfig
423-
file. Hooks from .gtrconfig are not executed until explicitly trusted.
422+
Reviews and approves executable commands defined in the repository's
423+
.gtrconfig file. Hooks and editor/AI defaults from .gtrconfig are not
424+
used until explicitly trusted.
424425
425426
This prevents malicious contributors from injecting arbitrary shell
426427
commands via shared .gtrconfig files. Trust is stored per repository
427-
path plus hook definitions in ~/.config/gtr/trusted/ and must be
428-
re-approved if hooks change.
428+
path plus executable command definitions in ~/.config/gtr/trusted/ and
429+
must be re-approved if those commands change.
429430
430-
Hooks from your local git config (.git/config, ~/.gitconfig) are always
431-
trusted since you control those files directly.
431+
Hooks and defaults from your local git config (.git/config, ~/.gitconfig)
432+
are always trusted since you control those files directly.
432433
433434
Examples:
434-
git gtr trust # Review and approve hooks
435+
git gtr trust # Review and approve commands
435436
EOF
436437
}
437438

@@ -609,9 +610,9 @@ SETUP & MAINTENANCE:
609610
--force, -f: force removal even if worktree has uncommitted changes or untracked files
610611
611612
trust
612-
Review and approve .gtrconfig hook commands
613-
Hooks from .gtrconfig are not executed until trusted
614-
Trust is re-required when hook content changes
613+
Review and approve .gtrconfig executable commands
614+
Hooks and editor/AI defaults from .gtrconfig are not used until trusted
615+
Trust is re-required when executable command entries change
615616
616617
completion <shell>
617618
Generate shell completions (bash, zsh, fish)

lib/commands/init.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ __FUNC___hooks_current_content_hash() {
113113
__SHELL_PRELUDE__
114114
local _gtr_config_file="$1"
115115
local _gtr_hook_defs
116-
_gtr_hook_defs="$(git config -f "$_gtr_config_file" --get-regexp '^hooks\.' 2>/dev/null)" || return 1
116+
_gtr_hook_defs="$(git config -f "$_gtr_config_file" --get-regexp '^hooks\.|^defaults\.editor$|^defaults\.ai$' 2>/dev/null)" || return 1
117117
printf '%s\n' "$_gtr_hook_defs" | shasum -a 256 | cut -d' ' -f1
118118
}
119119
@@ -182,7 +182,7 @@ 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\.' 2>/dev/null)
185+
set -l _gtr_hook_defs (git config -f "$_gtr_config_file" --get-regexp '^hooks\.|^defaults\.editor$|^defaults\.ai$' 2>/dev/null)
186186
test $status -eq 0; or return 1
187187
printf '%s\n' "$_gtr_hook_defs" | shasum -a 256 | cut -d' ' -f1
188188
end
@@ -783,7 +783,7 @@ complete -f -c __FUNC__ -n '___FUNC___needs_subcommand' -a adapter -d 'List avai
783783
complete -f -c __FUNC__ -n '___FUNC___needs_subcommand' -a config -d 'Manage configuration'
784784
complete -f -c __FUNC__ -n '___FUNC___needs_subcommand' -a completion -d 'Generate shell completions'
785785
complete -f -c __FUNC__ -n '___FUNC___needs_subcommand' -a init -d 'Generate shell integration'
786-
complete -f -c __FUNC__ -n '___FUNC___needs_subcommand' -a trust -d 'Trust .gtrconfig hooks'
786+
complete -f -c __FUNC__ -n '___FUNC___needs_subcommand' -a trust -d 'Trust .gtrconfig commands'
787787
complete -f -c __FUNC__ -n '___FUNC___needs_subcommand' -a version -d 'Show version'
788788
complete -f -c __FUNC__ -n '___FUNC___needs_subcommand' -a help -d 'Show help'
789789

lib/commands/trust.sh

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env bash
2-
# Trust management for .gtrconfig hooks
2+
# Trust management for executable .gtrconfig commands
33

44
cmd_trust() {
55
local config_file
@@ -10,18 +10,18 @@ cmd_trust() {
1010
return 0
1111
fi
1212

13-
# Show all hook entries from .gtrconfig
13+
# Show all trusted command entries from .gtrconfig
1414
local hook_content
15-
hook_content=$(git config -f "$config_file" --get-regexp '^hooks\.' 2>/dev/null) || true
15+
hook_content=$(_hooks_read_definitions "$config_file") || true
1616

1717
if [ -z "$hook_content" ]; then
18-
log_info "No hooks defined in $config_file"
18+
log_info "No hooks or executable defaults defined in $config_file"
1919
return 0
2020
fi
2121

2222
if _hooks_are_trusted "$config_file"; then
23-
log_info "Hooks in $config_file are already trusted"
24-
log_info "Current hooks:"
23+
log_info "Executable commands in $config_file are already trusted"
24+
log_info "Current trusted commands:"
2525
printf '%s\n' "$hook_content" >&2
2626
return 0
2727
fi
@@ -32,26 +32,26 @@ cmd_trust() {
3232
return 1
3333
}
3434

35-
log_warn "The following hooks are defined in $config_file:"
35+
log_warn "The following executable commands are defined in $config_file:"
3636
echo "" >&2
3737
printf '%s\n' "$hook_content" >&2
3838
echo "" >&2
3939
log_warn "These commands will execute on your machine during gtr operations."
4040

41-
if prompt_yes_no "Trust these hooks?"; then
41+
if prompt_yes_no "Trust these commands?"; then
4242
if _hooks_write_trust_marker "$trust_path" "$config_file"; then
4343
local current_trust_path
4444
current_trust_path=$(_hooks_current_trust_path "$config_file") || true
4545
if [ -n "$current_trust_path" ] && [ "$current_trust_path" != "$trust_path" ]; then
46-
log_warn "Hooks changed during review; current hooks remain untrusted"
46+
log_warn "Executable commands changed during review; current commands remain untrusted"
4747
return 1
4848
fi
49-
log_info "Hooks marked as trusted"
49+
log_info "Executable commands marked as trusted"
5050
else
51-
log_error "Failed to mark hooks as trusted"
51+
log_error "Failed to mark executable commands as trusted"
5252
return 1
5353
fi
5454
else
55-
log_info "Hooks remain untrusted and will not execute"
55+
log_info "Executable commands remain untrusted and will not run from .gtrconfig"
5656
fi
5757
}

lib/config.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,3 +431,54 @@ cfg_default() {
431431
# 5. Use fallback if still empty
432432
printf "%s" "${value:-$fallback}"
433433
}
434+
435+
# Get a default config value while trust-gating the .gtrconfig source.
436+
# Usage: cfg_default_trusted_file key env_name fallback_value file_key
437+
# Precedence: local config > trusted .gtrconfig > global/system config > env var > fallback
438+
cfg_default_trusted_file() {
439+
local key="$1"
440+
local env_name="$2"
441+
local fallback="$3"
442+
local file_key="${4:-}"
443+
local value file_value config_file
444+
445+
# Auto-map file_key if not provided and key is a gtr.* key
446+
if [ -z "$file_key" ] && [[ "$key" == gtr.* ]]; then
447+
file_key=$(cfg_map_to_file_key "$key")
448+
fi
449+
450+
# 1. Try local git config first (highest priority)
451+
value=$(git config --local --get "$key" 2>/dev/null || true)
452+
453+
# 2. Try .gtrconfig file only if its trusted command definitions are approved
454+
if [ -z "$value" ] && [ -n "$file_key" ]; then
455+
config_file=$(_gtrconfig_path)
456+
if [ -n "$config_file" ] && [ -f "$config_file" ]; then
457+
file_value=$(git config -f "$config_file" --get "$file_key" 2>/dev/null || true)
458+
if [ -n "$file_value" ]; then
459+
if _hooks_are_trusted "$config_file"; then
460+
value="$file_value"
461+
else
462+
log_warn "Untrusted .gtrconfig $file_key skipped — run: git gtr trust"
463+
fi
464+
fi
465+
fi
466+
fi
467+
468+
# 3. Try global/system git config
469+
if [ -z "$value" ]; then
470+
value=$(git config --global --get "$key" 2>/dev/null || true)
471+
fi
472+
473+
if [ -z "$value" ]; then
474+
value=$(git config --system --get "$key" 2>/dev/null || true)
475+
fi
476+
477+
# 4. Fall back to environment variable
478+
if [ -z "$value" ] && [ -n "$env_name" ]; then
479+
value=$(printenv "$env_name" 2>/dev/null) || true
480+
fi
481+
482+
# 5. Use fallback if still empty
483+
printf "%s" "${value:-$fallback}"
484+
}

lib/hooks.sh

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,37 @@
22
# Hook execution system
33

44
# ── Hook trust model ────────────────────────────────────────────────────
5-
# Hooks from .gtrconfig files (committed to repositories) require explicit
6-
# user approval before execution. This prevents malicious contributors from
7-
# injecting arbitrary commands via shared config files.
5+
# Hooks and executable defaults from .gtrconfig files (committed to
6+
# repositories) require explicit user approval before use. This prevents
7+
# malicious contributors from injecting arbitrary commands via shared config
8+
# files.
89
#
910
# Trust state is stored in ~/.config/gtr/trusted/<key>
10-
# where <key> is a SHA-256 of the canonical repo root plus the hook content hash.
11-
# Trust is scoped to repo identity + hook definitions, not repo snapshot state.
11+
# where <key> is a SHA-256 of the canonical repo root plus trusted content hash.
12+
# Trust is scoped to repo identity + trusted .gtrconfig definitions, not repo
13+
# snapshot state.
1214

1315
_GTR_TRUST_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/gtr/trusted"
1416

15-
# Read all hook definitions from a .gtrconfig file.
17+
# Read all trusted command definitions from a .gtrconfig file.
1618
# Usage: _hooks_read_definitions <config_file>
1719
_hooks_read_definitions() {
1820
local config_file="$1"
1921
local hook_content
20-
hook_content=$(git config -f "$config_file" --get-regexp '^hooks\.' 2>/dev/null) || true
22+
hook_content=$(git config -f "$config_file" --get-regexp '^hooks\.|^defaults\.editor$|^defaults\.ai$' 2>/dev/null) || true
2123
[ -n "$hook_content" ] || return 1
2224
printf '%s\n' "$hook_content"
2325
}
2426

25-
# Compute a content hash for hook definitions.
27+
# Compute a content hash for trusted command definitions.
2628
# Usage: _hooks_content_hash <hook_content>
2729
_hooks_content_hash() {
2830
local hook_content="$1"
2931
[ -n "$hook_content" ] || return 1
3032
printf '%s\n' "$hook_content" | shasum -a 256 | cut -d' ' -f1
3133
}
3234

33-
# Compute a content hash of all current hook entries in a .gtrconfig file.
35+
# Compute a content hash of all current trusted command entries in a .gtrconfig file.
3436
# Usage: _hooks_current_content_hash <config_file>
3537
_hooks_current_content_hash() {
3638
local config_file="$1"
@@ -63,7 +65,7 @@ _hooks_canonical_config_path() {
6365
printf '%s/%s\n' "$repo_root" "$(basename "$config_file")"
6466
}
6567

66-
# Compute the repo-scoped trust key for reviewed hook content
68+
# Compute the repo-scoped trust key for reviewed trusted command content
6769
# Usage: _hooks_reviewed_trust_key <config_file> <hook_content>
6870
_hooks_reviewed_trust_key() {
6971
local config_file="$1"
@@ -74,7 +76,7 @@ _hooks_reviewed_trust_key() {
7476
printf '%s\n%s\n' "$repo_root" "$hash" | shasum -a 256 | cut -d' ' -f1
7577
}
7678

77-
# Compute the repo-scoped trust key for the current hook content
79+
# Compute the repo-scoped trust key for the current trusted command content
7880
# Usage: _hooks_current_trust_key <config_file>
7981
_hooks_current_trust_key() {
8082
local config_file="$1"
@@ -88,7 +90,7 @@ _hooks_trust_key() {
8890
_hooks_current_trust_key "$1"
8991
}
9092

91-
# Resolve the trust marker path for reviewed hook content
93+
# Resolve the trust marker path for reviewed trusted command content
9294
# Usage: _hooks_reviewed_trust_path <config_file> <hook_content>
9395
_hooks_reviewed_trust_path() {
9496
local config_file="$1"
@@ -129,9 +131,9 @@ _hooks_marker_matches_config() {
129131
[ "$marker_content" = "$canonical_config_file" ]
130132
}
131133

132-
# Check if .gtrconfig hooks are trusted for the current repository
134+
# Check if .gtrconfig command definitions are trusted for the current repository
133135
# Usage: _hooks_are_trusted <config_file>
134-
# Returns: 0 if trusted (or no hooks), 1 if untrusted
136+
# Returns: 0 if trusted (or no trusted command definitions), 1 if untrusted
135137
_hooks_are_trusted() {
136138
local config_file="$1"
137139
[ ! -f "$config_file" ] && return 0
@@ -142,7 +144,7 @@ _hooks_are_trusted() {
142144
_hooks_marker_matches_config "$trust_path" "$config_file"
143145
}
144146

145-
# Write a trust marker that matches the reviewed hooks
147+
# Write a trust marker that matches the reviewed command definitions
146148
# Usage: _hooks_write_trust_marker <trust_path> [config_file]
147149
_hooks_write_trust_marker() {
148150
local trust_path="$1"
@@ -165,7 +167,7 @@ _hooks_write_trust_marker() {
165167
fi
166168
}
167169

168-
# Mark .gtrconfig hooks as trusted
170+
# Mark .gtrconfig command definitions as trusted
169171
# Usage: _hooks_mark_trusted <config_file>
170172
_hooks_mark_trusted() {
171173
local config_file="$1"

0 commit comments

Comments
 (0)