Skip to content

Commit 864d660

Browse files
Secure shared .gtrconfig commands behind trust (#163)
* Address thresher.sh findings, introduce trust flow for injectable code, remove path traversal vuln, harden workflows for supplychain attacks * Updated items based on CONTRIBUTING.md * fix: address PR 162 regressions * fix: harden adapter and trust handling * fix: harden adapter execution and trust markers * fix: allow override adapters without PATH lookup * fix: avoid trust marker temp leaks * refactor: clean adapter parsing and init trust helpers * Address CodeRabbit review: relax argv validation and fail closed hook trust * fix: trust-gate gtrconfig tool defaults * fix: correct fish gtrconfig path regex * fix: harden fish gtrconfig trust helpers --------- Co-authored-by: shadowcodex <1348053+shadowcodex@users.noreply.github.com>
1 parent acb53b9 commit 864d660

31 files changed

Lines changed: 1491 additions & 69 deletions

.github/workflows/homebrew.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ on:
44
release:
55
types: [published]
66

7+
permissions: read-all
8+
79
jobs:
810
homebrew:
911
name: Bump Homebrew formula
1012
runs-on: ubuntu-latest
1113
if: ${{ !github.event.release.prerelease }}
1214
steps:
13-
- uses: mislav/bump-homebrew-formula-action@v3
15+
- uses: mislav/bump-homebrew-formula-action@56a283fa15557e9abaa4bdb63b8212abc68e655c # v3
1416
with:
1517
formula-name: git-gtr
1618
formula-path: Formula/git-gtr.rb

.github/workflows/lint.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ on:
66
pull_request:
77
branches: [main]
88

9+
permissions: read-all
10+
911
jobs:
1012
shellcheck:
1113
name: ShellCheck
1214
runs-on: ubuntu-latest
1315
steps:
14-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
1517

1618
- name: Install ShellCheck
1719
run: sudo apt-get update && sudo apt-get install -y shellcheck
@@ -24,7 +26,7 @@ jobs:
2426
name: Completions
2527
runs-on: ubuntu-latest
2628
steps:
27-
- uses: actions/checkout@v4
29+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2830

2931
- name: Verify completion files are up to date
3032
run: ./scripts/generate-completions.sh --check
@@ -33,7 +35,7 @@ jobs:
3335
name: Tests
3436
runs-on: ubuntu-latest
3537
steps:
36-
- uses: actions/checkout@v4
38+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
3739

3840
- name: Install BATS
3941
run: sudo apt-get update && sudo apt-get install -y bats

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: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,16 @@ git gtr clean --merged --force --yes # Force-clean and auto-confirm
343343

344344
**Note:** The `--merged` mode auto-detects your hosting provider (GitHub or GitLab) from the `origin` remote URL and requires the corresponding CLI tool (`gh` or `glab`) to be installed and authenticated. For self-hosted instances, set the provider explicitly: `git gtr config set gtr.provider gitlab`.
345345

346+
### `git gtr trust`
347+
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.
349+
350+
```bash
351+
git gtr trust # Review and approve .gtrconfig commands
352+
```
353+
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.
355+
346356
### Other Commands
347357

348358
- `git gtr doctor` - Health check (verify git, editors, AI tools)
@@ -362,6 +372,14 @@ git gtr config set gtr.editor.default cursor
362372
# Set your AI tool (aider, auggie, claude, codex, continue, copilot, cursor, gemini, opencode)
363373
git gtr config set gtr.ai.default claude
364374

375+
# Override-backed adapters may include flags
376+
git gtr config set gtr.editor.default "nano -w"
377+
git gtr config set gtr.ai.default "claude --continue"
378+
379+
# Generic fallbacks may use other safe PATH commands
380+
git gtr config set gtr.editor.default "code --wait"
381+
git gtr config set gtr.ai.default "bunx @github/copilot@latest"
382+
365383
# Copy env files to new worktrees
366384
git gtr config add gtr.copy.include "**/.env.example"
367385

@@ -394,10 +412,14 @@ git gtr config set gtr.ui.color never
394412
remote = upstream
395413
```
396414

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.
416+
417+
**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`.
418+
397419
**Configuration precedence** (highest to lowest):
398420

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

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

adapters/ai/claude.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ ai_can_start() {
4242
ai_start() {
4343
local path="$1"
4444
shift
45+
local configured_args=("${GTR_AI_CMD_ARGS[@]}")
4546

4647
local claude_cmd
4748
claude_cmd="$(find_claude_executable)"
@@ -57,5 +58,5 @@ ai_start() {
5758
return 1
5859
fi
5960

60-
(cd "$path" && "$claude_cmd" "$@")
61+
(cd "$path" && "$claude_cmd" "${configured_args[@]}" "$@")
6162
}

adapters/ai/cursor.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ai_can_start() {
1111
ai_start() {
1212
local path="$1"
1313
shift
14+
local configured_args=("${GTR_AI_CMD_ARGS[@]}")
1415

1516
if ! ai_can_start; then
1617
log_error "Cursor not found. Install from https://cursor.com"
@@ -25,9 +26,9 @@ ai_start() {
2526

2627
# Try cursor-agent first, then fallback to cursor CLI commands
2728
if command -v cursor-agent >/dev/null 2>&1; then
28-
(cd "$path" && cursor-agent "$@")
29+
(cd "$path" && cursor-agent "${configured_args[@]}" "$@")
2930
elif command -v cursor >/dev/null 2>&1; then
3031
# Try various Cursor CLI patterns (implementation varies by version)
31-
(cd "$path" && cursor cli "$@") 2>/dev/null || (cd "$path" && cursor "$@")
32+
(cd "$path" && cursor cli "${configured_args[@]}" "$@") 2>/dev/null || (cd "$path" && cursor "${configured_args[@]}" "$@")
3233
fi
3334
}

adapters/editor/nano.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,18 @@ editor_can_open() {
1010
# Usage: editor_open path
1111
editor_open() {
1212
local path="$1"
13+
local configured_args=("${GTR_EDITOR_CMD_ARGS[@]}")
1314

1415
if ! editor_can_open; then
1516
log_error "Nano not found. Usually pre-installed on Unix systems."
1617
return 1
1718
fi
1819

20+
if [ "${#configured_args[@]}" -gt 0 ]; then
21+
(cd "$path" && nano "${configured_args[@]}")
22+
return $?
23+
fi
24+
1925
# Open nano in the directory (just cd there, nano doesn't open directories)
2026
log_info "Opening shell in $path (nano doesn't support directory mode)"
2127
(cd "$path" && exec "$SHELL")

bin/git-gtr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ main() {
100100
init)
101101
cmd_init "$@"
102102
;;
103+
trust)
104+
cmd_trust "$@"
105+
;;
103106
version|--version|-v)
104107
echo "git gtr version $GTR_VERSION"
105108
;;

completions/_git-gtr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +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 commands'
4849
'version:Show version'
4950
'help:Show help'
5051
)

completions/git-gtr.fish

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +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 commands'
5758
complete -f -c git -n '__fish_git_gtr_needs_command' -a version -d 'Show version'
5859
complete -f -c git -n '__fish_git_gtr_needs_command' -a help -d 'Show help'
5960

0 commit comments

Comments
 (0)