Repository navigation
Commit cdfb428
committed
fix(index): let git check the repository before running a commit hook
`run_commit_hook` finds a hook in `.git/hooks` or `core.hooksPath`, read
through GitPython's own config parser, and executes it directly. No git
command runs before that, so git's check that the repository is safe to
use (the ownership and `safe.directory` check added for CVE-2022-24765)
has not happened when code from the repository is executed.
`IndexFile.commit` runs the `pre-commit` and `commit-msg` hooks before
it calls git at all. In a repository owned by another user, where
`git commit` stops with "detected dubious ownership" without running any
hook, `repo.index.commit()` ran the repository's `pre-commit` hook and
only then failed in `git hash-object`. That is the situation git's check
exists for: a `.git` directory planted by another user in a shared or
parent directory (`Repo(path, search_parent_directories=True)` finds it
the same way git would).
Before executing a hook that exists, `run_commit_hook` now runs
`git rev-parse --git-dir` in the repository, so git applies its own
policy, including `safe.directory` and the exemptions git makes. When
git refuses, the `GitCommandError` it raises is the one the commit
already ended with, only now before the hook runs. When git accepts the
repository, hooks run as before, and nothing changes when there is no
hook. Asking git, rather than reimplementing the ownership rules, keeps
the result identical to `git commit` for every git version, including
versions older than 2.35.2 that make no check.
Adds `test_pre_commit_hook_not_run_in_repository_git_refuses` to
`test/test_index.py`, which uses git's `GIT_TEST_ASSUME_DIFFERENT_OWNER`
to simulate another owner; it fails before this change and passes
after. `test_run_commit_hook` and
`test_run_commit_hook_outside_worktree_on_windows` mock `Git.execute`
(the latter because it fakes the Windows `PATH`), so they now allow this
one call while still rejecting any git command during hook lookup.
`ruff check`, `ruff format --check` and `mypy` pass. In a full clone
prepared with `init-tests-after-clone.sh`, the pytest suite passes
except `test_diff_with_staged_file`, `test_index_mutation`,
`test_blame_content_with_carriage_returns`, `test_empty_repo`,
`test_rebasing` and the two `test_actor_get_uid_laziness_*` tests,
which fail the same way without this change on this machine.1 parent ccc4811 commit cdfb428
2 files changed
Lines changed: 31 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
185 | 185 | | |
186 | 186 | | |
187 | 187 | | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
188 | 192 | | |
189 | 193 | | |
190 | 194 | | |
191 | 195 | | |
192 | 196 | | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
193 | 202 | | |
194 | 203 | | |
195 | 204 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
189 | 189 | | |
190 | 190 | | |
191 | 191 | | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
192 | 198 | | |
193 | 199 | | |
194 | 200 | | |
| |||
1496 | 1502 | | |
1497 | 1503 | | |
1498 | 1504 | | |
1499 | | - | |
| 1505 | + | |
1500 | 1506 | | |
1501 | 1507 | | |
1502 | 1508 | | |
| |||
1533 | 1539 | | |
1534 | 1540 | | |
1535 | 1541 | | |
1536 | | - | |
| 1542 | + | |
1537 | 1543 | | |
1538 | 1544 | | |
1539 | 1545 | | |
| |||
1707 | 1713 | | |
1708 | 1714 | | |
1709 | 1715 | | |
| 1716 | + | |
| 1717 | + | |
| 1718 | + | |
| 1719 | + | |
| 1720 | + | |
| 1721 | + | |
| 1722 | + | |
| 1723 | + | |
| 1724 | + | |
| 1725 | + | |
| 1726 | + | |
| 1727 | + | |
| 1728 | + | |
| 1729 | + | |
1710 | 1730 | | |
1711 | 1731 | | |
1712 | 1732 | | |
| |||
0 commit comments